先来说说策略模式的定义:定义了算法族,分别封装起来让他们可以相互替换,此模式让算法的变化独立于使用算法的客户。
没用设计模式之前的例子 :
所有的鸭子类都是继承 Duck 类,所有鸭子的行为都是又超类 Duck 实现,因为每种鸭子的样子是不用的,所以在超类 Duck 里面定义了一个抽象的 display(); 每个子类鸭子去实现自己的外观。
但是由于需求变化, 现在要在鸭子的行为里面加入飞行的行为,直接在超类 Duck 里加入了一个 fly() 行为,然而出现了严重的后果,在鸭子子类的鸭子也出现了飞行的行为,然而橡皮鸭子是不会飞行的,这是严重不允许的。
这时可能会想到,在橡皮鸭里把 fly(); 方法给覆盖掉,然后什么也不做,但是以后可能还会有诱饵鸭,既不会飞也不会叫,只能继续覆盖,显然这不是一个好主意。
接着尝试使用接口
然而这样做就会增加许多重复的代码,也不是一个好的注意。
由此可见,继承并不能很好的解决问题,因为鸭子的行为在子类里不断的改变,并且让所有的子类都又这些行为时不恰当的,使用 Flyable 和 Quackable接口一开始还不错,解决了问题,只有会飞的鸭子才去继承 Flyable 接口,但是 JAVA 接口不具有实现代码 ,所以继承接口无法达到代码的复用,这代表着无论何时你需要修改某个行为的时候,你必须向下追踪并在每一个实现此行为的类中去修改(比如某些鸭子的飞行行为发生了改变,用翅膀飞变成了用火箭筒飞,哈哈举个例子而已,或者飞行速度发生了变化,你就需要在某个鸭子子类中去单独的修改,一个还好说,多了就很蛋疼了,也有可能发生新的错误,这是就需要使用设计模式了,因为鸭子的行为时变化的,所以我们可以把着部分单独的抽出来,之后在给每个鸭子单独的组合上这些行为,这样当行为改变的时候我们就可以改动很小的地方来完成某些需求)
这里引出一个设计原则 : 找出应用中可能需要变化之处,把他们独立起来,不要和那些不需要变化的代码混在一起。
换句话说,如果每次需求一来,都会使某方面的代码发生变化,就可以确定这部分代码需要抽出来,和那些稳定的代码做区分。总体来说就是,把会变化的部分抽取并封装起来,以便以后可以轻易的修改或扩充此部分,而不影响其他不需要变化的部分。
这里所提到的变化的部分是指 fly() 和 quack() 行为,现在,为了分开变化的部分和不变的部分,我们准备建立两组类(远离 Duck 类),一个是 fly 相关的,一个是 quack 相关的,每一组类将实现各自的动作,比如 有一个类是 “呱呱叫 ” 一个是 “吱吱叫”
上面提到了一点就是组合,我们想要能够制定某个行为道子类鸭子的实例,比如,我们要产生一个新的绿头鸭实例,并制定特定类型的飞行行为给他,那这样就可以设计为让鸭子的行为可以动态的改变,也就是说我们应该在子类鸭子类中包含设定行为的方法,这样就可以在“运行”的时候“动态的设定”绿头鸭的行为。
这里又可以引出一个设计原则 : 针对接口编程,而不是针对实现编程。
我们利用每个接口来代表每个行为,比方说,定义两个接口 FlyBehavior 和 QuackBehavior ,而每个行为类去实现其中一个对应的接口。所以这次鸭子类不会去实现飞行和叫的接口,而是又我们新定义的类(“呱呱叫 ”)去实现 FlyBehavior 和 QuackBehavior ,这就称为行为类,由行为类而不是鸭子类去实现行为类接口。
这种做法异于以往,以前的做法是,行为来自 Duck 超类的具体实现,或者是实现某个接口由子类自行实现,这两种做法都是依赖于实现,没办法更改行为(除非写更多的代码)
在新的设计中,鸭子的子类将使用接口( FlyBehavior 和 QuackBehavior )所表示的行为(也就是借助行为类实现行为接口),所以实际的实现不会被绑死在鸭子的子类中。(也就是,特定的具体行为,编写在了实现FlyBehavior 和 QuackBehavior的行为类中)
说了这么多,开始上代码
首先建立两个接口 FlyBehavior 和 QuackBehavior
public interface FlyBehaviorInter { void fly(); }
public interface QuackBehaviorInter { void quack(); }
然后在新建一些行为类,这里我建了两个飞行行为和两个叫的行为
飞行 行为类
public class FlyWithWings implements FlyBehaviorInter{ @Override public void fly() { System.out.println("用翅膀飞"); } }
public class FlyNoWay implements FlyBehaviorInter{ @Override public void fly() { System.out.println("不会飞"); } }
叫 行为类
public class QuackForGuaGua implements QuackBehaviorInter{ @Override public void quack() { System.out.println("呱呱叫"); } }
public class QuackForZhiZhi implements QuackBehaviorInter{ @Override public void quack() { System.out.println("吱吱叫"); } }
然后是 超类 Duck
public abstract class Duck { /**声明行为类型为接口类型 由子类去定义具体的引用*/ protected FlyBehaviorInter flyBehaviorInter; protected QuackBehaviorInter quackBehaviorInter; /**抽象的外观方法*/ abstract void dishPlay(); /** 执行鸭子的行为 具体实现被分离又单独的行为类去实现*/ protected void performFly(){ flyBehaviorInter.fly(); } protected void performQuack(){ quackBehaviorInter.quack(); } /** 动态改变鸭子的行为 */ public void setFlyBehaviorInter(FlyBehaviorInter flyBehaviorInter) { this.flyBehaviorInter = flyBehaviorInter; } public void setQuackBehaviorInter(QuackBehaviorInter quackBehaviorInter) { this.quackBehaviorInter = quackBehaviorInter; } }
接着写两个 鸭子类 进行测试
public class GreenHeadDuck extends Duck{ public GreenHeadDuck(){ flyBehaviorInter = new FlyWithWings(); quackBehaviorInter = new QuackForGuaGua(); } @Override void dishPlay() { System.out.println("我是绿头鸭"); } }
public class RubberDuck extends Duck{ public RubberDuck(){ flyBehaviorInter = new FlyNoWay(); quackBehaviorInter = new QuackForZhiZhi(); } @Override void dishPlay() { System.out.println("我是橡皮鸭"); } }
最后就是 main 函数了
public class Main { public static void main(String[] a){ GreenHeadDuck greenHeadDuck = new GreenHeadDuck(); greenHeadDuck.dishPlay(); greenHeadDuck.performFly(); greenHeadDuck.performQuack(); RubberDuck rubberDuck = new RubberDuck(); rubberDuck.dishPlay(); rubberDuck.performFly(); rubberDuck.performQuack(); } }
总共也就这么多了 大概整理了一下