#android #kotlin #enums
#Android #kotlin #перечисления
Вопрос:
Как я могу создать класс, который можно было бы более повторно использовать с классами enum, поскольку позже у меня может появиться еще несколько классов? Моя цель — сделать его более многоразовым, гибким и глобальным для другого использования.
enum class PaymentMethodType(val type: String) {
PAYPAL("Paypal"),
VISA("Visa"),
MASTERCARD("MasterCard"),
VISA_DEBIT("VISA Debit"),
LPQ_CREDIT("Lpq Credit");
companion object {
private val TAG: String = this::class.java.simpleName
fun fromString(name: String): PaymentMethodType? {
return getEnumFromString(PaymentMethodType::class.java, name)
}
private inline fun <reified T : Enum<T>> getEnumFromString(c: Class<T>?, string: String?): T? {
if (c != null amp;amp; string != null) {
try {
return enumValueOf<T>(
string.trim()
.toUpperCase(Locale.getDefault()).replace(" ", "_")
)
} catch (e: IllegalArgumentException) {
Log.e(TAG, e.message)
}
}
return null
}
}
}
Ответ №1:
Вы можете обобщить свою getEnumFromString
функцию, создав интерфейс и используя сопутствующий объект, реализующий его. Расширение в этом интерфейсе позволит вам вызывать функцию непосредственно в компаньоне вашего класса enum.
Это поможет:
interface EnumWithKey<T : Enum<T>, K> {
val T.key: K
}
/* The reified type parameter lets you call the function without explicitly
* passing the Class-object.
*/
inline fun <reified T : Enum<T>, K> EnumWithKey<T, K>.getByKey(key: K): T? {
return enumValues<T>().find { it.key == key }
}
Теперь вы можете создать свой PaymentMethodType
следующим образом:
enum class PaymentMethodType(val type: String) {
PAYPAL("Paypal"),
VISA("Visa"),
MASTERCARD("MasterCard"),
VISA_DEBIT("VISA Debit"),
LPQ_CREDIT("Lpq Credit");
companion object : EnumWithKey<PaymentMethodType, String> {
// Just define what the key is
override val PaymentMethodType.key
get() = type
}
}
И вуаля, теперь вы можете это сделать:
println(PaymentMethodType.getByKey("Paypal")) // Prints PAYPAL
EnumWithKey
Интерфейс теперь можно использовать повторно, просто имея сопутствующий объект enum, реализующий его.
Комментарии:
1. Ты легенда! Спасибо, сэр.
Ответ №2:
Ну? Как насчет этого кода?
enum class PaymentMethodType(val type: String) {
PAYPAL("Paypal"),
VISA("Visa"),
MASTERCARD("MasterCard"),
VISA_DEBIT("VISA Debit"),
LPQ_CREDIT("Lpq Credit");
companion object {
private val TAG: String = PaymentMethodType::class.simpleName
fun fromString(name: String?): PaymentMethodType? {
val maybeType = PaymentMethodType.values().firstOrNull { it.type == name }
if (maybeType == null) {
Log.e(TAG, "No corresponding PaymentMethodType for $name")
}
return maybeType
}
}
}
Просто упростил getEnumFromString
метод таким образом.
Более того, если вы хотите сделать свой PaymentMethod Type более «многоразовым, гибким и глобальным», добавьте в свой какой-нибудь абстрактный метод PaymentMethodType
или рассмотрите возможность использования в этом случае закрытого класса. Мы можем предположить, что многие способы оплаты требуют своих собственных протоколов, и для их реализации с помощью enum
требуется внешняя ветка when
or if-else
для этого. Например, код должен выглядеть следующим образом:
fun paymentProcessor(payment: PaymentMethodType): Boolean {
return when (payment) {
PAYPAL -> { processPaypalPayment() }
VISA -> { processVisaPayment() }
// ...
}
}
что неплохо, если только количество способов оплаты не ограничено, но не совсем желательно. Мы можем удалить это коварное ключевое слово if
or when
следующим образом (сохраняя enum class
подход):
enum class PaymentMethodType(val type: String) {
PAYPAL("Paypal") {
override fun processPayment(): Boolean {
TODO("Not implemented.")
}
},
VISA("Visa") {
override fun processPayment(): Boolean {
TODO("Not implemented.")
}
},
// ... more types ...
;
abstract fun processPayment(): Boolean
// ...
}
При любом подходе мы можем исключить when
ключевое слово в paymentProcessor
методе, который я продемонстрировал следующим образом:
fun paymentProcessor(payment: PaymentMethodType): Boolean {
return payment.processPayment()
}
Я не объясняю sealed class
подход, поскольку код не сильно отличается по сравнению с enum class
подходом в этом случае. Официальный документ может помочь.
Надеюсь, это поможет.
Ответ №3:
Получите все значения enum с помощью PaymentMethodType.values()
, затем используйте find()
, чтобы получить то, что вам нужно:
fun fromString(type: String): PaymentMethodType? = PaymentMethodType.values().find { it.type.toLowerCase() == type.toLowerCase() }