这个案例很好地解释了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