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

 

posted @ 2021-01-19 21:40  地中有山  阅读(168)  评论(0编辑  收藏  举报