在上一篇中咱们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern)。本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pattern)和模板模式(Template Pattern)。html
简介java
策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每个算法封装到具备共同接口的独立的类中,从而使得它们能够相互替换。策略模式使得算法能够在不影响到客户端的状况下发生变化。
其主要目的是经过定义类似的算法,替换if else 语句写法,而且能够随时相互替换。git
策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)。github
示例图以下:
算法
这里为了方便理解,咱们就拿刚学习Java的时候使用计算方法来讲吧。
在使用计算器进行计算的时候,会常常用到加减乘除方法。若是咱们想获得两个数字相加的和,咱们须要用到“+”符号,获得相减的差,须要用到“-”符号等等。虽然咱们能够经过字符串比较使用if/else写成通用方法,可是计算的符号每次增长,咱们就不得不加在原先的方法中进行增长相应的代码,若是后续计算方法增长、修改或删除,那么会使后续的维护变得困难。
可是在这些方法中,咱们发现其基本方法是固定的,这时咱们就能够经过策略模式来进行开发,能够有效避免经过if/else来进行判断,即便后续增长其余的计算规则也可灵活进行调整。设计模式
首先定义一个抽象策略角色,并拥有一个计算的方法。ide
interface CalculateStrategy { int doOperation(int num1, int num2); }
而后再定义加减乘除这些具体策略角色并实现方法。学习
那么代码以下:测试
class OperationAdd implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 + num2; } } class OperationSub implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 - num2; } } class OperationMul implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 * num2; } } class OperationDiv implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 / num2; } }
最后在定义一个环境角色,提供一个计算的接口供客户端使用。
代码以下:this
class CalculatorContext { private CalculateStrategy strategy; public CalculatorContext(CalculateStrategy strategy) { this.strategy = strategy; } public int executeStrategy(int num1, int num2) { return strategy.doOperation(num1, num2); } }
编写好以后,那么咱们来进行测试。
测试代码以下:
public static void main(String[] args) { int a=4,b=2; CalculatorContext context = new CalculatorContext(new OperationAdd()); System.out.println("a + b = "+context.executeStrategy(a, b)); CalculatorContext context2 = new CalculatorContext(new OperationSub()); System.out.println("a - b = "+context2.executeStrategy(a, b)); CalculatorContext context3 = new CalculatorContext(new OperationMul()); System.out.println("a * b = "+context3.executeStrategy(a, b)); CalculatorContext context4 = new CalculatorContext(new OperationDiv()); System.out.println("a / b = "+context4.executeStrategy(a, b)); }
输出结果:
a + b = 6 a - b = 2 a * b = 8 a / b = 2
策略模式优势:
扩展性好,能够在不修改对象结构的状况下,为新的算法进行添加新的类进行实现;
灵活性好,能够对算法进行自由切换;
策略模式缺点:
使用策略类变多,会增长系统的复杂度。;
客户端必须知道全部的策略类才能进行调用;
使用场景:
若是在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式能够动态地让一个对象在许多行为中选择一种行为;
一个系统须要动态地在几种算法中选择一种;
若是一个对象有不少的行为,若是不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现;
简介
模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类能够按须要重写方法实现,但调用将以抽象类中定义的方式进行。 这种类型的设计模式属于行为型模式。定义一个操做中的算法的骨架,而将一些步骤延迟到子类中。
模板模式,其主要的的思想就是作一个模板,提供给客户端进行调用。除去生活中咱们常常用到的简历模板、合同模板等等,Java中也有很经典的模板使用,那就是Servlet,HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法须要由HttpServlet的具体则由子类提供。
模板模式主要由抽象模板(Abstract Template)角色和具体模板(Concrete Template)角色组成。
抽象模板(Abstract Template): 定义了一个或多个抽象操做,以便让子类实现。这些抽象操做叫作基本操做,它们是一个顶级逻辑的组成步骤;定义并实现了一个模板方法。这个模板方法通常是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操做中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
具体模板(Concrete Template): 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤;每个抽象模板角色均可以有任意多个具体模板角色与之对应,而每个具体模板角色均可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不一样实现,从而使得顶级逻辑的实现各不相同。
示例图以下:
这里为了方便理解,咱们依旧使用一个简单的示例来加以说明。
咱们之前在玩魂斗罗、双截龙、热血物语、忍者神龟等等游戏的时候,都须要在小霸王游戏机上插卡,而后启动游戏才能玩,其中魂斗罗这种游戏,启动游戏以后就能够直接玩了,可是忍者神龟这种游戏则在启动游戏以后,须要选择其中一个角色才能开始玩。那么咱们能够根据这个场景写出一个通用的模板,主要包含启动游戏,玩游戏,结束游戏这几个必须实现的方法,选择人物这个方法改为可选。
那么这个抽象类的代码以下:
abstract class Game{ //启动游戏 protected abstract void runGame(); //选择人物 protected void choosePerson() {}; //开始玩游戏 protected abstract void startPlayGame(); //结束游戏 protected abstract void endPlayGame(); //模板方法 public final void play() { runGame(); choosePerson(); startPlayGame(); endPlayGame(); } }
定义好该抽象类以后,咱们再来定义具体模板实现类。这里定义两个游戏类,一个是魂斗罗,一个忍者神龟。
那么代码以下:
class ContraGame extends Game{ @Override protected void runGame() { System.out.println("启动魂斗罗II..."); } @Override protected void startPlayGame() { System.out.println("1P正在使用S弹打aircraft..."); } @Override protected void endPlayGame() { System.out.println("1P被流弹打死了,游戏结束!"); } } class TMNTGame extends Game{ @Override protected void runGame() { System.out.println("启动忍者神龟III..."); } @Override protected void choosePerson() { System.out.println("1P选择了Raph !"); } @Override protected void startPlayGame() { System.out.println("Raph正在使用绝技 “火箭头槌” "); } @Override protected void endPlayGame() { System.out.println("Raph 掉进井盖里死了,游戏结束了! "); } }
最后再来进行测试,测试代码以下:
public static void main(String[] args) { Game game = new ContraGame(); game.play(); System.out.println(); game = new TMNTGame(); game.play(); }
输出结果:
启动魂斗罗II... 1P正在使用S弹打aircraft... 1P被流弹打死了,游戏结束! 启动忍者神龟III... 1P选择了Raph ! Raph正在使用绝技 “火箭头槌” Raph 掉进井盖里死了,游戏结束了!
模板模式优势:
扩展性好,对不变的代码进行封装,对可变的进行扩展;
可维护性好,由于将公共代码进行了提取,使用的时候直接调用便可;
模板模式缺点:
由于每个不一样的实现都须要一个子类来实现,致使类的个数增长,会使系统变得复杂;
使用场景:
有多个子类共有逻辑相同的方法;
重要的、复杂的方法,能够考虑做为模板方法。
注意事项:
为防止恶意操做,通常模板方法都加上 final 关键词!
分享一首很是好听的轻音乐!
网易云网友评论:
简单,重复,毫无华丽旋律,也无厚重悲凉的伴奏。但心恰恰就被牢牢的抓住了。一种茫然却被迫紧凑的感受。一种不知何所处的心虚。what for?
java-study是本人在学习Java过程当中记录的一些代码,也包括以前博文中使用的代码。若是感受不错,但愿顺手给个start,固然若是有不足,也但愿提出。
github地址: https://github.com/xuwujing/java-study
原创不易,若是感受不错,但愿给个推荐!您的支持是我写做的最大动力! 版权声明: 做者:虚无境 博客园出处:http://www.cnblogs.com/xuwujing CSDN出处:http://blog.csdn.net/qazwsxpcm 我的博客出处:http://www.panchengming.com