设计模式-策略模式
1、定义
将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现并使他们可以互相替换,从而导致客户端程序独立于算法的改变
2、组合与策略模式
继承是重用代码的利器,但继承并不总是最好的方式,还有组合方式:在类中增加一个私有域引用另一个已有的类的实例,通过调用引用实例的方法从而获得新的功能,这种设计被称作组合(复合)
定义策略接口-FlyStragety
public interface FlyStragety { void performFly();//飞行能力 }
策略接口实现1-FlyNoWay
public class FlyNoWay implements FlyStragety { public void performFly() { System.out.println("我不会飞啊"); } }
策略接口实现2-FlyWithWin
public class FlyWithWin implements FlyStragety { public void performFly() { System.out.println("我会飞行"); } }
定义抽象类
public abstract class Duck { private FlyStragety flyStragety;//面向接口编程 public Duck(FlyStragety flyStragety) { this.flyStragety = flyStragety; } public void quack(){//鸣叫 System.out.println("嘎嘎嘎..."); } abstract void display();//外观 /** * 提供公有的方法,面向接口编程使用动态绑定特性执行具体实现 */ public void fly(){ flyStragety.performFly(); } }
定义Duck的子类1-RedDuck
public class RedDuck extends Duck { public RedDuck(FlyStragety flyStragety) { super(flyStragety); } @Override void display() { System.out.println("我是红脖子鸭子"); } }
定义Duck的子类2-RubberDuck
public class RubberDuck extends Duck { public RubberDuck(FlyStragety flyStragety) { super(flyStragety); } @Override void display() { System.out.println("全身发黄,嘴巴很红"); } }
说明:
- quack方法已在抽象的父类中实现,子类不会强制覆盖,不覆盖则直接使用父类的方法。
- display方法在抽象的父类中申明为抽象方法,子类必须覆盖。
- fly方法在抽象的父类中为公共方法,通过组合方式,采用面向接口编程,基于动态特性调用实现类的具体方法。
测试方法:
public class DuckTest { @Test public void testDuck(){ Duck duck=new RedDuck(new FlyWithWin()); // Duck duck=new RubberDuck(new FlyNoWay()); duck.display(); duck.quack(); duck.fly(); } }
3、策略模式的实现
从上述实例基本可以看出怎样使用策略模式:
- 通过分离变化得出策略接口:定义策略几口
- 提供策略接口的实现类:定义具体策略
- 在客户程序申明一个域为策略接口:组合+面向接口编程(Duck持有FlyStragety接口,而不是具体实现)
- 在客户程序中组装策略接口的实现类:注入实现类
4、策略模式的适用场景
- 许多相关的类仅仅是行为差异,可将差异分离出为策略接口,而相关的类作为策略算法
- 运行时选取不同的算法变体
- 通过条件语句在多个分支中选取一种行为
写在最后:
设计模式是一种经验总结、编程思想,拒绝代码的迷惑。
一种设计模式的代码变体可以有很多,但万变不离其宗。