依然是那句話,Kotlin 在狀態模式也沒有語法糖可以用
interface Level {
    fun status(member: Member): String
}
data class Member(
    var name: String,
    var money: BigDecimal,
    var level: Level
) {
    fun checkout(): String {
        val text = StringBuilder()
        text.append("結帳完成")
        text.append(" / ")
        text.append("會員名稱:")
        text.append(name)
        text.append(" / ")
        text.append("累計消費金額:")
        text.append(money.toPlainString())
        text.append(" / ")
        text.append("會員狀態:")
        text.append(level.status(this))
        return text.toString()
    }
    fun addMoney(money: BigDecimal) {
        this.money = this.money.add(money)
    }
}
class Copper : Level {
    override fun status(member: Member): String {
        val text = StringBuilder()
        if (member.money < BigDecimal.valueOf(500)) {
            text.append("消費五百以下,還是銅會員")
        } else {
            member.level = Silver()
            member.checkout()
            text.append("消費超過五百,成為銀會員")
        }
        return text.toString()
    }
}
class Silver : Level {
    override fun status(member: Member): String {
        val text = StringBuilder()
        if (member.money < BigDecimal.valueOf(1000)) {
            text.append("消費一千以下,還是銀會員")
        } else {
            member.level = Gold()
            member.checkout()
            text.append("消費超過一千,成為金會員")
        }
        return text.toString()
    }
}
class Gold : Level {
    override fun status(member: Member): String {
        val text = StringBuilder()
        text.append("升級到金會員,無法再升級")
        return text.toString()
    }
}
class KotlinTest {
    @Test
    fun show() {
        val text = StringBuilder()
        text.append("\n")
        val member = Member("Andy", BigDecimal.ZERO, Copper())
        text.append(member.checkout())
        member.addMoney(BigDecimal.valueOf(50))
        text.append("\n")
        text.append(member.checkout())
        member.addMoney(BigDecimal.valueOf(500))
        text.append("\n")
        text.append(member.checkout())
        member.addMoney(BigDecimal.valueOf(1100))
        text.append("\n")
        text.append(member.checkout())
        member.addMoney(BigDecimal.valueOf(2000))
        text.append("\n")
        text.append(member.checkout())
        assertEquals("測試", text.toString())
    }
}
結帳完成 / 會員名稱:Andy / 累計消費金額:0 / 會員狀態:消費五百以下,還是銅會員
結帳完成 / 會員名稱:Andy / 累計消費金額:50 / 會員狀態:消費五百以下,還是銅會員
結帳完成 / 會員名稱:Andy / 累計消費金額:550 / 會員狀態:消費超過五百,成為銀會員
結帳完成 / 會員名稱:Andy / 累計消費金額:1650 / 會員狀態:消費超過一千,成為金會員
結帳完成 / 會員名稱:Andy / 累計消費金額:3650 / 會員狀態:升級到金會員,無法再升級