策略模式就是定义了一系列的的算法,将它们都单独封装起来,让他们之间能够相互替换,可让算法的变化独立于使用算法的客户。
首先建立一个Dog父类,有run方法控制跑,jump方法控制跳,color方法控制颜色。算法
public class Dog { public void run(){ System.out.println("狗在跑"); } public void jump(){ System.out.println("狗在跳"); } public void color(){ } }
建立两个子类,分别是WhiteDog和BlackDog,都重写了父类的color方法,运行一下。编程
public class WhiteDog extends Dog { @Override public void color() { System.out.println("白颜色的狗"); } } public class BlackDog extends Dog { @Override public void color() { System.out.println("黑颜色的狗"); } } public class Test { public static void main(String[] args){ WhiteDog whiteDog = new WhiteDog(); whiteDog.run(); whiteDog.jump(); whiteDog.color(); BlackDog blackDog = new BlackDog(); blackDog.run(); blackDog.jump(); blackDog.color(); } }
结果:
狗在跑
狗在跳
白颜色的狗
狗在跑
狗在跳
黑颜色的狗设计模式
这个时候看上去好像很完美没有任何问题,可是有一天咱们又新建了一个公仔狗的对象Doll dog,这个时候咱们发现好像有点不对,公仔狗是不会跳也不会跑的。能够若是继承了Dog父类他就自带跑和跳的功能了,那就不对了。ide
public class DollDog extends Dog { @Override public void color() { System.out.println("五光十色"); } } DollDog dollDog = new DollDog(); dollDog.run(); dollDog.jump(); dollDog.color();
结果:
狗在跑
狗在跳
五光十色的玩具狗this
这个时候咱们灵机一动想到可让子类覆盖父类run方法和jump方法,让DollDog中的跑和跳功能失效,咱们再运行一下。设计
@Override public void run() { System.out.println("玩具狗不会跑"); } @Override public void jump() { System.out.println("玩具狗不会跳"); }
结果:
玩具狗不会跑
玩具狗不会跳
五光十色的玩具狗code
看起来是解决了问题,可是若是一天要增长100个各类各样的狗的话难道咱们要让100个新建的子类都重写父类的方法吗?这个时候父类里面还只有3个方法,若是是30个呢?若是咱们都靠子类重写的话那效率该多低呢?有没有别的方法来解决呢?答案是确定的。下面咱们就来介绍怎么用策略模式来解决这个问题。
首先咱们要知道设计模式中第一个原则,要把代码中常常须要修改的部分独立抽取出来,不要和其余代码混在一块儿,这样更便于咱们扩展要修改的部分 。目前来看最常变化的是run和jump方法。因此咱们能够将这两个方法抽取出来,这里就要说到设计模式中第二个原则,针对接口编程,而不是现实编程。好比run和jump有不一样的种类,咱们能够声明一个接口里面定义run和jump方法,而后建立许多类去实现,调用的时候动态选择类型。这种类被称为行为类。行为类中的代码能够进行复用,却不会有继承带来的那些麻烦。对象
定义方法的接口:继承
public interface RunBehavior { void run(); } public interface JumpBehavior { void jump(); }
实现方法的行为类:接口
public class RunNoWay implements RunBehavior { @Override public void run() { System.out.println("不会跑"); } } public class RunFast implements RunBehavior { @Override public void run() { System.out.println("很快的跑"); } } public class RunSlow implements RunBehavior { @Override public void run() { System.out.println("很慢的跑"); } } public class JumpNoWay implements JumpBehavior { @Override public void jump() { System.out.println("不会跳"); } } public class JumpFast implements JumpBehavior { @Override public void jump() { System.out.println("很快的跳"); } }
如今咱们将变化的部分抽取出来了,因此Dog父类就会把run和jump的操做委托给行为类处理,那么具体要怎么使用这些行为类?这里就须要在Dog父类中定义两个实例变量,声明类型为RunBehavior和JumpBehavior,因此在代码运行的时候会用多态的方式引用正确的类型。而后在父类中的run和jump方法中委托行为类去执行功能。
public class Dog { public RunBehavior runBehavior; public JumpBehavior jumpBehavior; public void run(){ runBehavior.run(); } public void jump(){ jumpBehavior.jump(); } public void color(){ } }
最后当咱们没出现一个新的类型的狗狗的时候,咱们为它建立一个新类而后继承Dog父类,而后咱们在子类的构造方法中获取父类中两个接口的引用,根据本身的须要经过多态指定不一样的行为类。
public class SuperDog extends Dog { public SuperDog(){ runBehavior = new RunFast(); jumpBehavior = new JumpFast(); } @Override public void color() { System.out.println("红蓝相间的超人狗"); } } Dog dog = new SuperDog(); dog.jump(); dog.run(); dog.color();
结果:
很快的跳
很快的跑
红蓝相间的超人狗
最后咱们还有一个小问题,每次指定选择类的时候都是在子类的构造方法中指定,可不能够动态的指定呢?固然能够,咱们只须要为声明的接口引用添加两个set方法。而后在外部调用便可。
public void setRunBehavior(RunBehavior runBehavior) { this.runBehavior = runBehavior; } public void setJumpBehavior(JumpBehavior jumpBehavior) { this.jumpBehavior = jumpBehavior; } Dog dog = new SuperDog(); dog.jump(); dog.run(); dog.color(); dog.setJumpBehavior(new JumpNoWay()); dog.setRunBehavior(new RunNoWay()); dog.jump(); dog.run(); dog.color();
结果:
很快的跳
很快的跑
红蓝相间的超人狗
不会跳
不会跑
红蓝相间的超人狗
总结:策略模式就是把全部的可变的行为都抽取出来放到接口中,而后定义不少的行为类去实现接口。在父类中声明了接口的引用利用多态去动态的选择本身须要的行为类,避免了之前由于单纯的继承形成的每次的新变更都须要写大量的重复代码,而如今只须要定义好行为类进行复用便可,不须要修改本来的代码。