• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

How to Enforce Required Parameters in Kotlin Sealed Interfaces?

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Introduction


In Kotlin, using sealed interfaces provides a structured way to represent restricted class hierarchies. However, ensuring that all implementations contain certain required elements can be tricky, especially when adhering to architectural constraints. This article explores a solution for enforcing required parameters in params maps across implementations of the AnalyticsCustomEvent interface.

Understanding the Current Implementation


In the provided Kotlin code, we have a sealed interface AnalyticsEvent that includes a nested interface AnalyticsCustomEvent. Each class that implements this interface can define the params map, which is crucial for passing data to an analytics service. Here’s a summary of the original code snippet:

sealed interface AnalyticsEvent : Event {
interface AnalyticsCustomEvent : AnalyticsEvent {
var eventName: String
val params: Map<String, Any>?
}
interface AnalyticsEComerceEvent : AnalyticsEvent {
var eCommerceEvent: Any
}
}


We also have a concrete implementation:

class AddAllProductsToCartClickedEventAnalyticsDelegate(
orderId: String,
productIds: List<String>,
) : AnalyticsEvent.AnalyticsCustomEvent {

override var eventName: String = "add_all_products"

override val params: Map<String, Any> = mapOf(
EventParamNames.PRODUCT_ID to orderId,
EventParamNames.PRODUCTS to productIds,
)
}


As you noted, copying and pasting required elements into the params map for every implementation is not an ideal solution. Let's explore a more maintainable approach.

Solution: Create a Utility Function


Instead of changing AnalyticsCustomEvent from an interface to a class, we can introduce a helper utility function or property that ensures required elements are included in the params map without repetition.

Step 1: Create a Base Implementation


We can define a base implementation class that holds the logic for the required elements while still allowing other implementations to remain as they are. Here’s how to do it:

abstract class BaseAnalyticsCustomEvent : AnalyticsEvent.AnalyticsCustomEvent {
protected abstract val additionalParams: Map<String, Any>

override val params: Map<String, Any> = buildParams()

private fun buildParams(): Map<String, Any> {
val baseParams = mutableMapOf<String, Any>()
baseParams[EventParamNames.REQUIRED_PARAM] = "YourRequiredValue"
baseParams.putAll(additionalParams)
return baseParams
}
}

Step 2: Implement Specific Events


Next, we make the previous event implementation extend from this base class instead of the interface. Each specific event will then provide its own additional parameters, inheriting the required parameter logic:

class AddAllProductsToCartClickedEventAnalyticsDelegate(
orderId: String,
productIds: List<String>,
) : BaseAnalyticsCustomEvent() {

override var eventName: String = "add_all_products"

override val additionalParams: Map<String, Any> = mapOf(
EventParamNames.PRODUCT_ID to orderId,
EventParamNames.PRODUCTS to productIds,
)
}

Step 3: Ensuring Required Elements Across the Implementation


Now, with this structure, every class that inherits from BaseAnalyticsCustomEvent will automatically have the REQUIRED_PARAM included in the params map, thus maintaining the required parameter across different implementations without duplicating code.

Advantages of This Approach

  1. Code Reusability: By defining common logic in a base class, we avoid duplication and adhere to the DRY (Don’t Repeat Yourself) principle.
  2. Easy Maintenance: If you need to change the requirement for the params map, you only need to update the base class.
  3. Flexibility: Each specific implementation can maintain its unique parameters while adhering to the common requirement.
Frequently Asked Questions

Can I use a sealed class instead?


Sealed classes can also work, but if you still need an interface for architectural reasons, the solution above fits well with sealed interfaces.

How do I ensure type safety for the params map?


Using sealed classes or interfaces can provide type safety through Kotlin's smart casting and compile-time checks, so when retrieving values from the map, ensure you use a corresponding type or checks for type safety.

Conclusion


Implementing required parameters in params for Kotlin sealed interfaces need not be cumbersome. By leveraging a base implementation that handles the common logic, we can ensure every AnalyticsCustomEvent implementation maintains consistency without redundancy. This solution not only simplifies the design but also enhances maintainability, aligning well with Kotlin's expressive capabilities.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу