Scala:抽象成员之汇率代码的整理
对Prgramming in Scala 2nd的第20章“汇率”的例子进行了整理,添加了部分注释。
只能说:抽象类型很好很强大!
/** * 通过抽象类型的延迟实现,达到一种安全的类型操作 */object TestCurrency extends Application{ //客户端代码入口 val ret1=Japan.Yen from US.Dollar * 100 val ret2=Europe.Euro from ret1 val ret3=US.Dollar from ret2 println(ret1) //12110 JPY println(ret2) //75.95 EUR println(ret3) //99.95 USD 转换之后基本等同于原来的100USD,毕竟转换关系并不精确 println(US.Dollar*100+ret3) //199.95 USD //println(US.Dollar+Europe.Euro) //good!!compile error: type mismatch; this is what we want println(US.Dollar*100) //100.00 USD println(Japan.Yen*100) //100 JPY}abstract class CurrencyZone{ type Currency <: AbstractCurrency //定义汇率类型上界 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 -(that:Currency):Currency=make(this.amount-that.amount) def *(x:Double):Currency=make((this.amount*x).toLong) def /(that:Double)=make((this.amount/that).toLong) def /(that:Currency)=this.amount.toDouble/that.amount //from:从other转到当前(调用方)汇率 def from(other:CurrencyZone#AbstractCurrency):Currency= //路径依赖类型:CurrencyZone#AbstractCurrency make(math.round( other.amount.toDouble*Converter.exchangeRate(other.designation)(this.designation))) //10^x ~= n , 返回x private def decimals(n:Long):Int= if(n==1) 0 else 1+decimals(n/10) //重写:formatted的作用是根据单位来决定小数点后的位数 override def toString=((amount.toDouble/CurrencyUnit.amount) formatted ("%."+ this.decimals(CurrencyUnit.amount)+"f")+" "+this.designation) }}object US extends CurrencyZone{ abstract class Dollar extends AbstractCurrency{ def designation="USD" //抽象的designation在此实现 } type Currency=Dollar //类型延迟实现,可避免不同币种的直接运算 def make(cent:Long)=new Dollar{ val amount=cent //抽象的amount在此实现 } val Cent=make(1) val Dollar=make(100) val CurrencyUnit=Dollar}object Europe extends CurrencyZone{ //同US单例 abstract class Euro extends AbstractCurrency{ def designation="EUR" } type Currency=Euro def make(cents:Long)=new Euro{ val amount=cents } val Cent=make(1) val Euro=make(100) val CurrencyUnit=Euro}object Japan extends CurrencyZone{ //同US单例 abstract class Yen extends AbstractCurrency{ def designation="JPY" } type Currency=Yen def make(yen:Long)=new Yen{val amount=yen} val Yen=make(1) //日圆的的最小单位,没有日分 val CurrencyUnit=Yen}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.623), "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 ) )}