Mark Buikema
08/20/2020, 10:08 AMsealed class PaymentMethod {
abstract val transactionCost: BigDecimal
data class PayPal(...) : PaymentMethod
data class CreditCard(...) : PaymentMethod
data class Cash(...) : PaymentMethod
companion object {
fun create(id: Long, transactionCost: BigDecimal) : PaymentMethod {
// TODO
}
}
}
Also I want to have a single source of truth for defining which ID belongs to which subclass (only define it once).
Would like to hear some tips on how to implement this. If you think there are better approaches (except for modifying API) than what I want, feel free to suggest.Jonathan Mew
08/20/2020, 10:39 AMenum class
to own the mapping, and if you need reverse lookup there are some tidy ideas here: https://stackoverflow.com/questions/37794850/effective-enums-in-kotlin-with-reverse-lookup
Might depend whether there are other fields on the different types of transactions to take care of.marstran
08/20/2020, 10:40 AMsealed class PaymentMethod(val id: Long) {
abstract val transactionCost: BigDecimal
private interface PaymentMethodCompanion {
val id: Long
fun create(transactionCost: BigDecimal): PaymentMethod
}
data class PayPal(override val transactionCost: BigDecimal) : PaymentMethod(id) {
companion object : PaymentMethodCompanion {
override val id: Long = 1
override fun create(transactionCost: BigDecimal) = PayPal(transactionCost)
}
}
data class CreditCard(override val transactionCost: BigDecimal) : PaymentMethod(id) {
companion object : PaymentMethodCompanion {
override val id: Long = 2
override fun create(transactionCost: BigDecimal) = CreditCard(transactionCost)
}
}
data class Cash(override val transactionCost: BigDecimal) : PaymentMethod(id) {
companion object : PaymentMethodCompanion {
override val id: Long = 3
override fun create(transactionCost: BigDecimal) = Cash(transactionCost)
}
}
companion object {
fun create(id: Long, transactionCost: BigDecimal): PaymentMethod {
return PaymentMethod::class.sealedSubclasses
.mapNotNull { it.companionObjectInstance as PaymentMethodCompanion? }
.find { it.id == id }
?.create(transactionCost)
?: throw NoSuchElementException("No payment method with id $id")
}
}
}
marstran
08/20/2020, 10:44 AMPaymentMethodType
as an enum besides the PaymentMethod
class. Something like this:
enum class PaymentMethodType(val id: Long) {
PayPal(1),
CreditCard(2),
Cash(3)
}
data class PaymentMethod(val type: PaymentMethodType, val transactionCost: BigDecimal) {
companion object {
fun create(id: Long, transactionCost: BigDecimal): PaymentMethod {
val type = PaymentMethodType.values().find { it.id == id }
?: throw NoSuchElementException("No payment method type with id $id")
return PaymentMethod(type, transactionCost)
}
}
}
Michael de Kaste
08/20/2020, 11:40 AMMichael de Kaste
08/20/2020, 12:04 PMsealed class PaymentMethod(val id: Long) {
abstract val transactionCost: BigDecimal
private interface PaymentMethodCompanion {
val id: Long
}
data class PayPal(override val transactionCost: BigDecimal) : PaymentMethod(id) {
companion object : PaymentMethodCompanion {
override val id: Long = 1
}
}
data class CreditCard(override val transactionCost: BigDecimal) : PaymentMethod(id) {
companion object : PaymentMethodCompanion {
override val id: Long = 2
}
}
data class Cash(override val transactionCost: BigDecimal) : PaymentMethod(id) {
companion object : PaymentMethodCompanion {
override val id: Long = 3
}
}
companion object {
fun create(id: Long, transactionCost: BigDecimal): PaymentMethod? {
return PaymentMethod::class.sealedSubclasses
.find { (it.companionObjectInstance as PaymentMethodCompanion).id == id }
?.primaryConstructor
?.call(transactionCost)
}
}
}
marstran
08/20/2020, 12:08 PMMichael de Kaste
08/20/2020, 12:09 PMMichael de Kaste
08/20/2020, 12:12 PMMark Buikema
08/21/2020, 10:05 AMcompanionObjectInstance