20-4 案例分析:货币(抽象类型的应用)
这个案例很好地解释了Scala中抽象类型的应用。我们的任务是设计一个Currency类。一个典型的Currency实例可以用来代表以美元、欧元、日元或其他货币表示的金额。它应该支持对货币金额的计算。例如,应该能将相同货币额度的两笔金额相加,或者可以用表示利率的因子对某笔货币金额做乘法。同时添加两个改良点,一、支持子单位;二、支持货币转换的功能。
①抽象类CurrencyZone
abstract class CurrencyZone {
//抽象类型
type Currency <: AbstractCurrency
//抽象值val
val CurrencyUnit: Currency
//抽象方法
def make(x: Long): Currency
abstract class AbstractCurrency{
val amount: Long
def designation: String
def +(that: Currency): Currency = make(this.amount + that.amount)
def *(x: Double): Currency = make((this.amount * x).toLong)
def -(that: Currency): Currency = make(this.amount - that.amount)
def /(that: Double) = make((this.amount / that).toLong)
def /(that: Currency) = this.amount.toDouble / that.amount
//将给定的源货币转换成当前的Currency对象
def from(other: CurrencyZone#AbstractCurrency): Currency = {
make(math.round(other.amount.toDouble * Converter.exchangeRate(other.designation)(this.designation)))
}
//入参n为1单位货币包含的amount,如1美元的amount为100,val Dollar = make(100)。
private def decimals(n: Long): Int = if (n == 1) 0 else 1 + decimals(n / 10)
//amount需除以1单位包含的amount显示
override def toString: String =
((amount.toDouble / CurrencyUnit.amount.toDouble) formatted("%." + decimals(CurrencyUnit.amount) + "f")
+ " " + designation)
}
}
②汇率转换对象
object Converter {
var exchangeRate = Map(
"USD" -> Map("USD" -> 1.0, "EUR" -> 0.7596, "JPY" -> 1.211, "CHF" -> 1.223),
"EUR" -> Map("USD" -> 1.316,"EUR" -> 1.0, "JPY" -> 1.594, "CHF" -> 1.632),
"JPY" -> Map("USD" -> 0.8257,"EUR" -> 0.6272, "JPY" -> 1.0, "CHF" -> 1.018),
"CHF" -> Map("USD" -> 0.8108,"EUR" -> 0.6160, "JPY" -> 0.982, "CHF" -> 1.0),
)
}
③美元对象
object US extends CurrencyZone {
abstract class Dollar extends AbstractCurrency{
override def designation: String = "USD"
}
override type Currency = Dollar
override def make(cents: Long): Dollar = new Dollar {
override val amount: Long = cents
}
val Cent = make(1)
val Dollar = make(100)
val CurrencyUnit = Dollar
}
④欧元对象
object Europe extends CurrencyZone {
abstract class Euro extends AbstractCurrency{
override def designation: String = "EUR"
}
override type Currency = Euro
override def make(cents: Long): Euro = new Euro {
override val amount: Long = cents
}
val Cent = make(1)
val Euro = make(100)
val CurrencyUnit = Euro
}
⑤日元对象
object Japan extends CurrencyZone{
abstract class Yen extends AbstractCurrency{
override def designation: String = "JPY"
}
override type Currency = Yen
override def make(yen: Long): Yen = new Yen {
override val amount: Long = yen
}
val Yen = make(1)
val CurrencyUnit = Yen
}
⑥测试类
object Test {
def main(args: Array[String]): Unit = {
val res1 = Japan.Yen from US.Dollar * 100
println(res1)
val res2 = Europe.Euro from res1
println(res2)
val res3 = US.Dollar from res2
println(res3)
val res4 = US.Dollar * 100 + res3
println(res4)
}
}
控制台输出
12110 JPY 75.95 EUR 99.95 USD 199.95 USD

浙公网安备 33010602011771号