Skip to content

Instantly share code, notes, and snippets.

@Pooh3Mobi
Last active September 5, 2018 15:25
Show Gist options
  • Save Pooh3Mobi/82ed07d882da0d0a5c211900b0112d6a to your computer and use it in GitHub Desktop.
Save Pooh3Mobi/82ed07d882da0d0a5c211900b0112d6a to your computer and use it in GitHub Desktop.
Study of Kotlin Domain Modeling : Functional And Reactive Domain Modeling - ADT and Smart Constructor -
@file:Suppress("DataClassPrivateConstructor")
// ADT and Smart Constructor
package com.example.algebra
import java.math.BigDecimal
import java.util.*
// domain modeling part
typealias Amount = BigDecimal
val today = Calendar.getInstance().time
data class Balance(val amount: Amount = BigDecimal.ZERO)
sealed class Account(
open val no: String,
open val name: String,
open val dataOfOpen: Date?,
open val dateOfClose: Date?,
open val balance: Balance
)
data class CheckingAccount private constructor(
override val no: String,
override val name: String,
override val dataOfOpen: Date?,
override val dateOfClose: Date?,
override val balance: Balance
) : Account(no, name, dataOfOpen, dateOfClose, balance) {
companion object {
fun checkingAccount(
no: String,
name: String,
openDate: Date?,
closeDate: Date?,
balance: Balance
): Try<Account> {
return closeDateCheck(openDate, closeDate).map { d ->
CheckingAccount(no, name, d.first, d.second, balance)
}
}
}
}
data class SavingAccount private constructor(
override val no: String,
override val name: String,
override val dataOfOpen: Date?,
override val dateOfClose: Date?,
override val balance: Balance
) : Account(no, name, dataOfOpen, dateOfClose, balance) {
companion object {
fun savingAccount(
no: String,
name: String,
rate: BigDecimal,
openDate: Date?,
closeDate: Date?,
balance: Balance
): Try<Account> {
return closeDateCheck(openDate, closeDate).map { d ->
if (rate <= BigDecimal.ZERO) {
throw Exception("Interest rate $rate must be > 0")
} else {
SavingAccount(no, name, d.first, d.second, balance)
}
}
}
}
}
private fun closeDateCheck(openDate: Date?, closeDate: Date?): Try<Pair<Date, Date?>> {
val od = openDate ?: today
return closeDate?.let { cd ->
if (cd before od) Failure<Pair<Date, Date?>>(Exception("Close date $cd cannot be earlier than open date $od"))
else Success(od to cd)
} ?: Success(od to closeDate)
}
// utilities part
infix fun Date.before(date: Date) = this.before(date)
sealed class Try<out T> {
fun <U> map(f: (T) -> U): Try<U> = when (this) {
is Success ->
try { Success(f(value)) }
catch (e: Exception) { Failure<U>(e) }
is Failure -> Failure(e)
}
}
data class Success<out T>(val value: T) : Try<T>()
data class Failure<out T>(val e: Throwable) : Try<T>()
@Pooh3Mobi
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment