Scala patterns (#4) - Strategy

策略模式是一种经典的设计模式,简而言之,就是做同一件事情,但在不同的场景中(或针对不同的对象)采用不同的算法。由于Scala简洁的语法和对高阶函数的支持,相比Java写出的代码会更加精简。

下面给出几个例子来感受一下Scala中策略模式的写法,首先是Scala in action书中的例子。

1
2
3
4
5
def calculatePrice(product: String, taxingStrategy: String => Double) = {
...
val tax = taxingStrategy(product)
...
}

这个例子简直是简单地过分,只需要传入一个函数(参数是String类型,返回值是Double类型),借由传入函数来决定具体的计算方法(策略)就可以了。由于这个例子过分简单,我们再来看一个更具体的例子(来自Memetic Musings Blog):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
trait TaxPayer
case class Employee(sal: Long) extends TaxPayer
case class NonProfitOrg(funds: BigInt) extends TaxPayer
//Consider a generic tax calculation function. (It can be in TaxPayer also).
def calculateTax[T <: TaxPayer](victim: T, taxingStrategy: (T => long)) = {
taxingStrategy(victim)
}
val employee = new Employee(1000)
//A strategy to calculate tax for employees
def empStrategy(e: Employee) = Math.ceil(e.sal * .3) toLong
calculateTax(employee, empStrategy)
val npo = new NonProfitOrg(100000000)
//The tax calculation strategy for npo is trivial, so we can inline it
calculateTax(nonProfit, ((t: TaxPayer) => 0)

这个例子更加Scala一些,其中用到了类型上限T <: TaxPayer,意思是T为TaxPayer类型及其子类型。其实仔细一看核心部分和第一个例子是一样的,只不过多用了一些对象的继承关系,使得Strategy的声明和实现更加明确化。

最后一个例子来自于之前提到过的Design Patterns in Scala,这篇博客的好处是能看到Java实现和Scala实现的比较:

Java实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface Strategy {
int compute(int a, int b);
}
public class Add implements Strategy {
public int compute(int a, int b) { return a + b; }
}
public class Multiply implements Strategy {
public int compute(int a, int b) { return a * b; }
}
public class Context {
private final Strategy strategy;
public Context(Strategy strategy) { this.strategy = strategy; }
public void use(int a, int b) { strategy.compute(a, b); }
}
new Context(new Multiply()).use(2, 3);

Scala实现

1
2
3
4
5
6
7
8
9
10
type Strategy = (Int, Int) => Int
class Context(computer: Strategy) {
def use(a: Int, b: Int) { computer(a, b) }
}
val add: Strategy = _ + _
val multiply: Strategy = _ * _
new Context(multiply).use(2, 3)

是不是觉得尝到一点儿函数式编程的甜头儿了呢?:)

参考资源