Scala中战略模式的更好替代方案?

Mat*_*ttK 12 design-patterns scala strategy-pattern

当我使用Java(或类似语言)编程时,我经常使用简单版本的策略模式,使用接口和实现类,在我的代码中提供特定概念的运行时可选实现.

作为一个非常人为的例子,我可能希望拥有一个可以在我的Java代码中产生噪音的Animal的一般概念,并希望能够在运行时选择动物的类型.所以我会沿着这些方向编写代码:

interface Animal {
    void makeNoise();
}

class Cat extends Animal {
    void makeNoise() { System.out.println("Meow"); }
}

class Dog extends Animal {
    void makeNoise() { System.out.println("Woof"); }
}

class AnimalContainer {
    Animal myAnimal;

    AnimalContainer(String whichOne) {
        if (whichOne.equals("Cat"))
            myAnimal = new Cat();
        else
            myAnimal = new Dog();
    }

    void doAnimalStuff() {
        ...
        // Time for the animal to make a noise
        myAnimal.makeNoise();
        ...
    }
Run Code Online (Sandbox Code Playgroud)

很简单.不过,最近,我一直在Scala开展一个项目,我想做同样的事情.使用特征这样做似乎很容易,例如:

trait Animal {
    def makeNoise:Unit
}

class Cat extends Animal {
    override def makeNoise:Unit = println("Meow")
}

class AnimalContainer {
    val myAnimal:Animal = new Cat
    ...
}
Run Code Online (Sandbox Code Playgroud)

然而,这看起来非常类似Java而且不是很实用 - 更不用说特征和接口并不是真的相同.所以我想知道在我的Scala代码中是否有更惯用的方法来实现策略模式 - 或类似的东西 - 以便我可以在运行时选择抽象概念的具体实现.或者使用特征是实现这一目标的最佳方法?

Von*_*onC 12

它可能就像" scala中的设计模式 "中的那个例子:

就像任何函数是第一类对象或闭包可用的语言一样,策略模式很明显.
例如.考虑'征税'的例子:

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)
Run Code Online (Sandbox Code Playgroud)

这样我就可以在运行时选择抽象概念的具体实现.

在这里,您使用上限,以便将子类中的T的特化限制为这些子类型TaxPayer.


Dan*_*ral 8

你可以对蛋糕图案做一个变化.

trait Animal {
    def makenoise: Unit
}

trait Cat extends Animal {
    override def makeNoise { println("Meow") }
}

trait Dog extends Animal {
    override def makeNoise { println("Woof") }
}

class AnimalContaineer {
    self: Animal =>

    def doAnimalStuff {
         // ...
         makeNoise
         // ...
     }
}

object StrategyExample extends Application {
    val ex1 = new AnimalContainer with Dog
    val ex2 = new AnimalContainer with Cat

    ex1.doAnimalStuff
    ex2.doAnimalStuff
}
Run Code Online (Sandbox Code Playgroud)

就策略模式而言,策略上的自我类型表明它必须与某种算法的特定实现混合在一起.