Last active
September 5, 2018 15:25
-
-
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 -
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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>() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Original https://github.com/debasishg/frdomain/blob/master/src/main/scala/frdomain/ch3/smartconstructor/Account.scala