策略模式
策略模式属于Java 23种设计模式中行为模式之一,那先看看什么是策略模式。
1、什么是策略模式
策略模式的定义:
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
其实我们在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等。或者比如网购,你可以选择工商银行、农业银行、建设银行等等,但是它们提供的算法都是一致的,就是帮你付款。
在软件开发中也会遇到相似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。(这个在下面案例中详讲)
图解:
2、策略模式的优缺点
优点:
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句
- 提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码
- 提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的
- 提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法把算法
- 的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离
缺点:
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类
- 策略模式造成很多的策略类,增加维护难度
3、策略模式的结构
1.抽象策略类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
2.具体策略类:实现了抽象策略定义的接口,提供具体的算法实现。
3.环境类:持有一个策略类的引用,最终给客户端调用。
结构图:
4、代码实现
现在有三只鸭子: 绿毛鸭、红毛鸭、小鸭子(小鸭子还不会飞)
现在定义一个鸭子的父类:里面有都会叫的方法,有显示外观的方法(因为每只都不一样,就需要子类重写)
还会飞行 (这里使用策略模式)
public abstract class duck { //鸭子都会叫: public void quack(){ System.out.println("嘎嘎嘎"); } //鸭子的外观,因为都不一样,所以由子类去实现 public abstract void display(); //以下使用策略模式: //在父类中持有该接口,并由该接口代替飞行行为(组合) private Flying flying; //提供set方法 public void setFlying(Flying flying) { this.flying = flying; } public void fly(){ flying.Fly(); } }
定义一个飞行接口:
/** * 策略接口:实现了鸭子的飞行行为 */ public interface Flying { void Fly(); }
我们知道策略模式就是把需要用的算法封装起来,就在另一个包内封装了会飞和不会飞的两个方法:
会飞(继承至上面的飞行接口,重写飞行方法):
public class FlyWithWin implements Flying { @Override public void Fly() { System.out.println("我会飞"); } }
不会飞:
public class FlyNoWay implements Flying { @Override public void Fly() { System.out.println("我不会飞行"); } }
注意: 上面这两个方法我是把他们单独封装起来,当做算法族,然后程序需要使用里面某个算法的时候,程序不会受算法改变的影响,因为这里面的算法最终效果是一致的
红毛鸭类:
/** * 红色鸭子 */ public class RedDuck extends duck{ public RedDuck(){ super(); //给鸭子注入飞行的能力,这里就是通过算法族里面的会飞的算法 super.setFlying(new FlyWithWin()); } @Override public void display() { System.out.println("我是红色的鸭子"); } }
绿毛鸭:
/** * * 绿色鸭子 */ public class GreenDuck extends duck{ public GreenDuck(){ super(); //给鸭子注入飞行的能力,这里也是通过算法族里面的会飞的算法 super.setFlying(new FlyWithWin()); } @Override public void display() { System.out.println("我是绿色的鸭子"); } }
小鸭子类(不会飞):
/** * 小鸭子,还不会飞 */ public class SamllDuck extends duck{ public SamllDuck(){ super(); //小鸭子不会飞,所以使用了算法族里面不会飞的算法 super.setFlying(new FlyNoWay()); } @Override public void display() { System.out.println("我还是小鸭子"); } //因为小鸭子和大鸭子的叫声不一样,所以重写叫声方法 public void quack(){ System.out.println("嘎~嘎~嘎"); } }
测试类:
public class Test { public static void main(String[] args) { System.out.println("***测试鸭子程序***"); duck d = null; //这下面是轮流运行!!!! d = new RedDuck(); //测试红色的鸭子 d = new GreenDuck(); //测试绿色的鸭子 d = new SamllDuck(); //测试小鸭子 d.display(); d.quack(); d.fly(); System.out.println("***测试完毕***"); } }
当使用红毛鸭为对象时:
***测试鸭子程序***
我是红色的鸭子
嘎嘎嘎
我会飞
***测试完毕***
当使用绿毛鸭为对象时:
***测试鸭子程序*** 我是绿色的鸭子 嘎嘎嘎 我会飞 ***测试完毕***
当使用小鸭子为对象时:
***测试鸭子程序***
我还是小鸭子
嘎~嘎~嘎
我不会飞行
***测试完毕***
5、策略模式的应用场景
1.一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中
2.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句
3.系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时
4.系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构
5.多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!