第一个程序
class Cafe{ def buyCoffee(cc:CreditCard) : Coffee = { val cup = new Coffee() cc.charge(cup.price) // 这段代码出现副作用: cup } }(1)函数只是为了返回一个Coffee对象,而在此过程中,却涉及到了CreditCard对象的更改。因此产生副作用,这个副作用使得代码难以测试,因为信用卡计费更改操作可能是一个webservice,而我们在测试中并不真的想联系信用卡公司 (2)因此,我们传递一个Payments对象给函数,使代码更加模块化
第2个程序class Cafe{ def buyCoffee(cc:CreditCard,p:Payments) : Coffee = { val cup = new Coffee() p.charge(cc,cup.price) // 这段代码出现副作用: cup } } (1)改进后的优点:虽然payments的实现可能还是需要调用远程webservice,但是测试代码时,可以使用mock创造一个不用远程调用的接口 (2)仍然存在的缺点:如果想买12杯咖啡,需要对函数循环12次,这样会进入12次计费计算过程,会导致效率急剧下降。;
函数式的代码写法 ``` class Cafe{ def buyCoffee(cc:CreditCard) : (Coffee,Charge) = { val cup = new Coffee() // p.charge(cc,cup.price) 删除这段 (cup,Charge(cc,cup.price)) } def buyCoffees(cc:CreditCard,n:Int):(List[Coffee],Charge) = { val purchases:List[(Coffee,Charge)] = List.fill(n)(buyCoffee(cc)) val (coffees,charges) = purchases.unzip(coffees,charges.reduce( (c1,c2)=>c1.add(c2) )) } }
case class Charge(cc:CreditCard,amount:Double){ def add(other:Charge):Charge = { // 累计计费,只能累计一个卡 if(cc==other.cc) Charge(cc,amount+other.amount) else throw new Exception("can't add different cards") } } ``` 【注】:函数式程序的标准写法:纯内核 + 很薄的外壳
非纯函数,往往会破坏引用透明,使同一个表达式产生的结果并不相同,使人费解 (eg:1+1表达式永远为2,这就是引用透明,但有些java函数,并不是引用透明的,例如stringbuilder的相关方法)
scala> val x = new StringBuilder("Hello") x: StringBuilder = Hello scala> val r1 = x.append(" world") r1: StringBuilder = Hello world scala> val r2 = x.append(" world") // r2和r1的表达式一样,但是得到的结果却不同 r2: StringBuilder = Hello world world转载于:https://www.cnblogs.com/moonlord/p/6273141.html