设计模式之策略模式
策略模式Strategy Pattern
定义:
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)
策略模式使用的是面向对象的继承和多态。策略模式有三个角色:
- Context封装角色
它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
public class Context{
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public void doAnyThing() {
strategy.doSomething();
}
}
- Strategy抽象策略角色
是策略、算法的封装抽象,通常为接口,定义了每个策略必须要具有的方法、属性。
public interface Strategy() {
public void doSomething();
}
- ConcreteStrategy 具体策略角色
实现中具体的操作。
public class ConcreteStrategy1 implements Strategy() {
public void dosomething() {
System.out.println("策略1的具体逻辑");
}
}
public class ConcreteStrategy2 implements Strategy() {
public void dosomething() {
System.out.println("策略2的具体逻辑");
}
}
Pros
- 算法可以自由切换
- 避免使用多重条件判断,减少大量嵌套if else。
- 扩展性比较好,新的策略只需要实现对应接口就OK了。
Cons
- 策略类会增加
- 所有的策略类都需要对外暴露,不符合迪米特法则。(即最少知道原则)。不过可以结合工厂方法、代理模式等去修正这个缺陷。
使用场景
- 多个类只有在算法或行为上稍有不同的场景。
- 算法需要自由切换的场景。
- 需要屏蔽算法规则的场景。
注意事项
如果系统中的一个策略家族的具体策略数量超过4个,则需要考虑使用混合模式,解决策略类膨胀和对外暴露的问题。
策略枚举
它是一个枚举。它是一个浓缩了的策略模式的枚举。
注意 策略枚举是一个非常优秀和方便的模式,但是它受枚举类型的限制,每个枚举项都是public、final、static的,扩展性受到了一定的约束,因此在系统开发中,策略枚举一般担当不经常发生变化的角色。
最佳实践
策略模式是一个非常简单的模式。它在项目中使用得非常多,但它单独使用的地方就比较少了,因为它有致命缺陷:所有的策略都需要暴露出去,这样才方便客户端决定使用哪一个策略。我们的策略模式只是实现了锦囊的管理,但是我们没有严格地定义“适当的场景”拆开“适当的锦囊”,在实际项目中,我们一般通过工厂方法模式来实现策略类的声明,读者可以参考混编模式。