小游戏网站模板长沙市有什么好玩的旅游景点

当前位置: 首页 > news >正文

小游戏网站模板,长沙市有什么好玩的旅游景点,cms系统模板,为什么做网站必须要用域名目录 一、模版方法模式

  1. 基本介绍

  2. 应用案例一#xff1a;豆浆制作问题 需求 代码实现 模板方法模式的钩子方法

  3. View的draw#xff08;Android#xff09; Android中View的draw方法就是使用了模板方法模式 模板方法模式在 Spring 框架应用的源码分析 知识小… 目录 一、模版方法模式

  4. 基本介绍

  5. 应用案例一豆浆制作问题 需求 代码实现 模板方法模式的钩子方法

  6. View的drawAndroid Android中View的draw方法就是使用了模板方法模式 模板方法模式在 Spring 框架应用的源码分析 知识小结 二、命令模式

  7. 基本介绍

  8. 应用案例一智能生活问题 需求 代码实现

  9. 常见应用 Thread Android 中的 Handler

  10. 知识小结 三、访问者模式

  11. 基本介绍

  12. 应用案例一歌手测评问题 需求 传统方式的问题分析 代码实现 双分派

  13. 知识小结 四、迭代器模式

  14. 基本介绍

  15. 应用案例一学校院系结构问题 需求

  16. 代码实现

  17. JDK源码ArrayList

  18. 知识小结 五、观察者模式

  19. 基本介绍

  20. 应用案例一天气预报问题 需求 传统方案 传统方式代码实现 传统方式问题分析 观测者模式实现

  21. JDK源码Observable

  22. 知识小结 六、中介者模式

  23. 基本介绍

  24. 应用案例一智能家庭管理问题 需求 传统方式解决 传统的方式的问题分析 代码实现

  25. 知识小结 七、备忘录模式

  26. 基本介绍

  27. 基本原理

  28. 代码实现

  29. 应用案例一游戏角色状态恢复问题 需求提出 代码实现

  30. 知识小结 八、解释器模式

  31. 基本介绍

  32. 基本原理

  33. 应用案例一四则运算问题 需求 传统方案解决四则运算问题分析 代码实现

  34. 知识小结 九、状态模式

  35. 基本介绍

  36. 基本原理

  37. 应用案例一APP 抽奖活动问题 需求提出 代码实现

  38. 源码剖析借贷平台
    需求提出 代码实现

  39. 知识小结 十、策略模式

  40. 基本介绍

  41. 应用案例一鸭子飞行 需求分析 代码实现

  42. 应用案例二旅游出行 简介 结构 三案例实现

  43. 应用案例三综合案例 简介 目前已实现的代码 代码改造工厂策略 举一反三

  44. JDK源码Arrays

  45. 知识小结 十一、职责链模式

  46. 基本介绍

  47. 应用案例一学校OA系统采购审批 需求分析 代码实现

  48. 应用案例二订单处理 基本介绍 基本结构 案例实现 优缺点 举一反三

  49. Andorid 应用

  50. 知识小结 一、模版方法模式

  51. 基本介绍 模板方法模式Template Method Pattern又叫模板模式(Template Pattern)在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现但调用将以抽象类中定义的方式进行。简单说模板方法模式定义一个操作中的算法的骨架而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构就可以重定义该算法的某些特定步骤这种类型的设计模式属于行为型模式。 对原理类图的说明-即(模板方法模式的角色及职责) AbstractClass 抽象类 类中实现了模板方法(template)定义了算法的骨架具体子类需要去实现 其它的抽象方法 operationr2,3,4ConcreteClass 实现抽象方法 operationr2,3,4, 以完成算法中特点子类的步骤

  52. 应用案例一豆浆制作问题 需求 编写制作豆浆的程序说明如下: 制作豆浆的流程 选材—添加配料—浸泡—放到豆浆机打碎通过添加不同的配料可以制作出不同口味的豆浆选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的请使用 模板方法模式完成 代码实现 应用实例要求 编写制作豆浆的程序说明如下: 制作豆浆的流程 选材—添加配料—浸泡—放到豆浆机打碎通过添加不同的配料可以制作出不同口味的豆浆 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的(红豆、花生豆浆。。。)思路分析和图解(类图) public abstract class SoyaMilk {//模板方法 makefinal void make(){select();addCondiments();soak();beat();}//选材void select(){System.out.println(第一步选择好的新鲜黄豆);}//添加不同配料子类具体实现abstract void addCondiments();//浸泡void soak(){System.out.println(第三步黄豆和配料开始浸泡需要3个小时);}//打豆浆void beat(){System.out.println(第四步黄豆和配料放到豆浆机去打碎);}} 红豆豆浆和花生豆浆某些具体细节不同 public class RedBeanSoyaMilk extends SoyaMilk {Overridevoid addCondiments() {System.out.println(第二步加入上等红豆);} }public class PeanutSoyaMilk extends SoyaMilk {Overridevoid addCondiments() {System.out.println(第二步加入上好的花生);} } 客户端调用 public class Client {public static void main(String[] args) {System.out.println(——–制作红豆豆浆——–);SoyaMilk soyaMilk new RedBeanSoyaMilk();soyaMilk.make();System.out.println(——–制作红豆豆浆——–);SoyaMilk peanutSoyaMilk new PeanutSoyaMilk();peanutSoyaMilk.make();} } 模板方法模式的钩子方法 在模板方法模式的父类中我们可以定义一个方法它默认不做任何事子类可以视情况要不要覆盖它该方法称为“钩子”。还是用上面做豆浆的例子来讲解比如我们还希望制作纯豆浆不添加任何的配料请使用钩子方法对前面的模板方法进行改造 改造抽象类 public abstract class SoyaMilk {//模板方法 makefinal void make(){select();if (customerWantCondiments()) {addCondiments();}soak();beat();}…//钩子方法决定是否需要添加配料boolean customerWantCondiments() {return true;} } 纯豆浆 public class PureSoyaMilk extends SoyaMilk {Overridevoid addCondiments() {}//重写钩子方法Overrideboolean customerWantCondiments() {return false;} } 客户端调用 main(…){System.out.println(——–制作纯豆浆——–);SoyaMilk pureSoyaMilk new PureSoyaMilk();pureSoyaMilk.make();//输出——–制作纯豆浆——–第一步选择好的新鲜黄豆第三步黄豆和配料开始浸泡需要3个小时第四步黄豆和配料放到豆浆机去打碎 }

  53. View的drawAndroid Android中View的draw方法就是使用了模板方法模式 public class View{//钩子方法空实现protected void onDraw(Canvas canvas) {}//钩子方法空实现protected void dispatchDraw(Canvas canvas) {}//绘制方法定义绘制流程public void draw(Canvas canvas) {//其他代码略/** 绘制流程如下** 1. 绘制view背景* 2. 如果有需要就保存图层* 3. 绘制view内容* 4. 绘制子View* 5. 如果有必要绘制渐变框和恢复图层* 6. 绘制装饰滑动条等*/if (!dirtyOpaque) {drawBackground(canvas);//步骤1. 绘制view背景}// 如果可能的话跳过第2步和第5步常见情况final int viewFlags mViewFlags;boolean horizontalEdges (viewFlags FADING_EDGE_HORIZONTAL) ! 0;boolean verticalEdges (viewFlags FADING_EDGE_VERTICAL) ! 0;if (!verticalEdges !horizontalEdges) {if (!dirtyOpaque) onDraw(canvas);//步骤3. 绘制view内容dispatchDraw(canvas);//步骤4. 绘制子View// 覆盖一部分内容绘制前景if (mOverlay ! null !mOverlay.isEmpty()) {mOverlay.getOverlayView().dispatchDraw(canvas);}onDrawForeground(canvas); //步骤6. 绘制装饰滑动条等return;} } 说明 View的draw()方法中定义了一整套的绘制流程这个流程是固定的所有的Android中的View都是按照这个流程来绘制的。其中drawBackground()这个方法在View类中是实现了具体过程的而onDraw()方法和dispatchDraw()方法在View中都是空实现即都是钩子方法。不同的子类通过重写这些空实现来实现自身不同的绘制效果。具体的View像TextView这些单一的View就会重写onDraw()方法由于TextView没有子View所以dispatchDraw()还是空实现而ViewGroup类含有子View需要遍历子View并绘制因此需要重写onDraw()和dispatchDraw()。所以我们自定义View时必须且只需重写onDraw自定义ViewGroup时则需要重写onDraw()和dispatchDraw()。 模板方法模式在 Spring 框架应用的源码分析 知识小结 基本思想是算法只存在于一个地方也就是在父类中容易修改。需要修改算法时只要修改父类的模板方法或者已经实现的某些步骤子类就会继承这些修改实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。既统一了算法也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变同时由子类提供部分步骤的实现。该模式的不足之处每一个不同的实现都需要一个子类实现导致类的个数增加使得系统更加庞大一般模板方法都加上 final 关键字 防止子类重写模板方法.模板方法模式使用场景当要完成在某个过程该过程要执行一系列步骤 这一系列的步骤基本相同但其个别步骤在实现时可能不同通常考虑用模板方法模式来处理 二、命令模式

  54. 基本介绍 命令模式Command Pattern在软件设计中我们经常需要向某些对象发送请求但是并不知道请求的接收者是谁也不知道被请求的操作是哪个 我们只需在程序运行时指定具体的请求接收者即可此时可以使用命令模式来进行设计命名模式使得请求发送者与请求接收者消除彼此之间的耦合让对象之间的调用关系更加灵活实现解耦。在命令模式中会将一个请求封装为一个对象以便使用不同参数来表示不同的请求(即命名)同时命令模式也支持可撤销的操作。通俗易懂的理解将军发布命令士兵去执行。其中有几个角色将军命令发布者、士兵命令的具体执行者、命令(连接将军和士兵)。 Invoker 是调用者将军Receiver 是被调用者士兵MyCommand 是命令实现了 Command 接口持有接收对象 对原理类图的说明-即(命名模式的角色及职责) Invoker 是调用者角色Command: 是命令角色需要执行的所有命令都在这里可以是接口或抽象类Receiver: 接收者角色知道如何实施和执行一个请求相关的操作ConcreteCommand: 将一个接受者对象与一个动作绑定调用接受者相应的操作实现 execute

  55. 应用案例一智能生活问题 需求 我们买了一套智能家电有照明灯、风扇、冰箱、洗衣机我们只要在手机上安装 app 就可以控制对这些家电工作。这些智能家电来自不同的厂家我们不想针对每一种家电都安装一个 App分别控制我们希望只要一个 app 就可以控制全部智能家电。要实现一个 app 控制所有智能家电的需要则每个智能家电厂家都要提供一个统一的接口给 app 调用这时 就可以考虑使用命令模式。命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来.在我们的例子中动作的请求者是手机 app动作的执行者是每个厂商的一个家电产品 代码实现 ICommand 抽象命令者Command角色 public interface ICommand {void execute();//执行void undo();//撤销 } 电灯开关命令ConcreteCommand public class LightOnCommand implements ICommand {LightReceiver receiver;public LightOnCommand(LightReceiver receiver) {this.receiver receiver;}Overridepublic void execute() {receiver.on();}Overridepublic void undo() {receiver.off();} } public class LightOffCommand implements ICommand {LightReceiver receiver;public LightOffCommand(LightReceiver receiver) {this.receiver receiver;}Overridepublic void execute() {receiver.off();}Overridepublic void undo() {receiver.on();} } public class NoCommand implements ICommand {Overridepublic void execute() {}Overridepublic void undo() {} } 电灯对象 接收者 Receiver角色 public class LightReceiver {public void on(){System.out.println(开灯请睁眼);}public void off(){System.out.println(关灯请闭眼);} } 遥控器调用者角色 Invoker角色 public class RemoteController {//开关按钮ICommand[] onCommands;ICommand[] offCommands;//撤销按钮ICommand undoCommand;public RemoteController() {onCommands new ICommand[5];offCommands new ICommand[5];for (int i 0; i 5; i) {onCommands[i] new NoCommand();offCommands[i] new NoCommand();}}// 给我们的按钮设置你需要的命令public void setCommand(int no, ICommand onCommand, ICommand offCommand) {onCommands[no] onCommand;offCommands[no] offCommand;}public void onButtonClicked(int no){onCommands[no].execute();undoCommand onCommands[no];}public void offButtonClicked(int no){offCommands[no].execute();undoCommand offCommands[no];}public void undoButtonClicked(){undoCommand.undo();}} 电视机对象

    编写第2种家电

    public class TVReceiver {public void on() {System.out.println( 电视机打开了.. );}public void off() {System.out.println( 电视机关闭了.. );} } 电视机开关命令 public class TVOffCommand implements Command {// 聚合TVReceiverTVReceiver tv;// 构造器public TVOffCommand(TVReceiver tv) {super();this.tv tv;}Overridepublic void execute() {// TODO Auto-generated method stub// 调用接收者的方法tv.off();}Overridepublic void undo() {// TODO Auto-generated method stub// 调用接收者的方法tv.on();} } public class TVOnCommand implements Command {// 聚合TVReceiverTVReceiver tv;// 构造器public TVOnCommand(TVReceiver tv) {super();this.tv tv;}Overridepublic void execute() {// TODO Auto-generated method stub// 调用接收者的方法tv.on();}Overridepublic void undo() {// TODO Auto-generated method stub// 调用接收者的方法tv.off();} } 客户端调用 public class Client {public static void main(String[] args) {//创建电灯的对象 接收者LightReceiver receiver new LightReceiver();//创建电灯的开关命令ICommand onCommand new LightOnCommand(receiver);ICommand offCommand new LightOffCommand(receiver);//创建遥控器RemoteController controller new RemoteController();//给遥控器设置相关命令controller.setCommand(0,onCommand,offCommand);System.out.println(—-按下开灯按钮—-);controller.onButtonClicked(0);System.out.println(—-按下关灯按钮—-);controller.offButtonClicked(0);System.out.println(—-按下撤销按钮—-);controller.undoButtonClicked();System.out.println(———-开始操作电视机———-);TVReceiver tvReceiver new TVReceiver();ICommand tvOnCommand new TVOnCommand(tvReceiver);ICommand tvOffCommand new TVOffCommand(tvReceiver);controller.setCommand(1,tvOnCommand,tvOffCommand);controller.onButtonClicked(1);controller.offButtonClicked(1);controller.undoButtonClicked();} }

  56. 常见应用 Thread 实际上Thread的使用就是一个简单的命令模式先看下Thread的使用 new Thread(new Runnable() {Overridepublic void run() {//doSomeThing}}).start(); Thread的start()方法即命令的调用者同时Thread的内部会调用Runnable的run()这里Thread又 充当了具体的命令角色最后的Runnable则是接受者了负责最后的功能处理。 Android 中的 Handler 另一个比较典型的常用到命令模式就是Handler了这里就不贴代码了简单分析下各个类的角 色 接收者Handler执行消息的处理操作。调用者Looper调用消息的的处理方法。命令角色Message消息类。

  57. 知识小结 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者调用者只要调用命令对象的execute()方法就可以让接收者工作而不必知道具体的接收者对象是谁、是如何实现的命令对象会负责让接收者执行请求的动作也就是说”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的命令对象起到了纽带桥梁的作用。容易设计一个命令队列。只要把命令对象放到列队就可以多线程的执行命令容易实现对请求的撤销和重做命令模式不足可能导致某些系统有过多的具体命令类增加了系统的复杂度这点在在使用的时候要注意空命令也是一种设计模式它为我们省去了判空的操作。在上面的实例中如果没有用空命令我们每按下一个按键都要判空这给我们编码带来一定的麻烦。命令模式经典的应用场景界面的一个按钮都是一条命令、模拟 CMDDOS 命令订单的撤销/恢复、触发- 反馈机制 三、访问者模式

  58. 基本介绍 访问者模式Visitor Pattern封装一些作用于某种数据结构的各元素的操作它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。主要将数据结构与数据操作分离解决数据结构和操作耦合性问题访问者模式的基本工作原理是在被访问的类里面加一个对外提供接待访问者的接口访问者模式主要应用场景是需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联)同时需要避免让这些操作污染这些对象的类可以选用访问者模式解决 对原理类图的说明-即(访问者模式的角色及职责) Visitor 是抽象访问者为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作ConcreteVisitor 是一个具体的访问值 实现每个有 Visitor 声明的操作是每个操作实现的部分.ObjectStructure 能枚举它的元素 可以提供一个高层的接口用来允许访问者访问元素Element 定义一个 accept 方法接收一个访问者对象ConcreteElement 为具体元素实现了 accept 方法

  59. 应用案例一歌手测评问题 需求 完成测评系统需求 将观众分为男人和女人对歌手进行测评当看完某个歌手表演后得到他们对该歌手不同的评价(评价 有不同的种类比如 成功、失败 等)传统方案 传统方式的问题分析 如果系统比较小还是 ok 的但是考虑系统增加越来越多新的功能时对代码改动较大违反了 ocp 原则 不利于维护扩展性不好比如 增加了 新的人员类型或者管理方法都不好做引出我们会使用新的设计模式 – 访问者模式 代码实现 将人分为男人和女人对歌手进行测评当看完某个歌手表演后得到他们对该歌手不同的评价(评价 有不同的种类比如 成功、失败 等)请使用访问者模式来说实现思路分析和图解(类图) ① 抽象访问者Visitor角色 public abstract class Action {//得到男性测评结果abstract void getManResult(Man man);//得到女性评测结果abstract void getWomanResult(Woman man); } ② 具体访问者 ConcreteVisitor角色 public class Success extends Action{Overridevoid getManResult(Man man) {System.out.println(man.getName(),这个男人给的评价是很成功);}Overridevoid getWomanResult(Woman woman) {System.out.println(woman.getName(),这个女人给的评价是很成功);} }public class Fail extends Action{Overridevoid getManResult(Man man) {System.out.println(man.getName(),这个男人给的评价是失败了);}Overridevoid getWomanResult(Woman woman) {System.out.println(woman.getName(),这个女人给的评价是失败了);} } ③ 抽象接收者(Element角色) public abstract class Person {//提供一个方法 让访问者可以访问public abstract void accept(Action action); } ④ 具体接收者 /*** 说明* 1. 这里使用到了双分派即首先在客户端程序中将具体的状态作为参数传递到Woman或者Man中第一次分派* 2. 然后Woman类调用了作为参数的具体方法中方法getWomanResult同时将自己this作为参数传入完成了第二次分派/ public class Woman extends Person {Overridepublic void accept(Action action) {action.getWomanResult(this);} }public class Man extends Person {Overridepublic void accept(Action action) {action.getManResult(this);} } ⑤ 数据结构 ObjectStructure 角色 /** description 数据结构管理很多人Man Woman*/ public class ObjectStructure {//维护了一个集合private ListPerson persons new LinkedList();//增加到listpublic void attach(Person person){persons.add(person);}//删除public void detach(Person person){persons.remove(person);}//显示测评结果public void display(Action action){for (Person p: persons) {p.accept(action);}} } ⑥ 客户端调用 public class Client {public static void main(String[] args) {//创建objectStructureObjectStructure objectStructure new ObjectStructure();objectStructure.attach(new Man(张三));objectStructure.attach(new Man(李四));objectStructure.attach(new Woman(王小花));//成功Action success new Success();objectStructure.display(success);//失败Action fail new Fail();objectStructure.display(fail);} } 输出 张三,这个男人给的评价是很成功 李四,这个男人给的评价是很成功 王小花,这个女人给的评价是很成功 张三,这个男人给的评价是失败了 李四,这个男人给的评价是失败了 王小花,这个女人给的评价是失败了 张三,这个男人给的评价是待定 李四,这个男人给的评价是待定 王小花,这个女人给的评价是待定 双分派 上面提到了双分派所谓双分派是指不管类怎么变化我们都能找到期望的方法运行。双分派意味着得到执行的操作取决于请求的种类和两个接收者的类型以上述实例为例假设我们要添加一个 Wait 的状态类考察 Man 类和 Woman 类的反应由于使用了双分派只需增加一个 Action 子类即可在客户端调用即可不需要改动任何其他类的代码 如 新增待定评价 public class Wait extends Action {Overridevoid getManResult(Man man) {System.out.println(man.getName(),这个男人给的评价是待定);}Overridevoid getWomanResult(Woman woman) {System.out.println(woman.getName(),这个女人给的评价是待定);} } 调用 main(…){//待定Action wait new Wait();objectStructure.display(wait); }

  60. 知识小结 优点 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高访问者模式可以对功能进行统一可以做报表、UI、拦截器与过滤器适用于数据结构相对稳定的系统缺点具体元素对访问者公布细节也就是说访问者关注了其他类的内部细节这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难违背了依赖倒转原则。访问者依赖的是具体元素而不是抽象元素因此如果一个系统有比较稳定的数据结构又有经常变化的功能需求那么访问者模式就是比较合适的. 四、迭代器模式

  61. 基本介绍 迭代器模式Iterator Pattern是常用的设计模式属于行为型模式如果我们的集合元素是用不同的方式实现的有数组还有 java 的集合类或者还有其他方式当客户端要遍历这些集合元素的时候就要使用多种遍历方式而且还会暴露元素的内部结构可以考虑使用迭代器模式解决。迭代器模式提供一种遍历集合元素的统一接口用一致的方法遍历集合元素不需要知道集合对象的底层表示即不暴露其内部的结构。 对原理类图的说明-即(迭代器模式的角色及职责) Iterator 迭代器接口是系统提供含义 hasNext, next, removeConcreteIterator : 具体的迭代器类管理迭代Aggregate :一个统一的聚合接口 将客户端和具体聚合解耦ConcreteAggreage : 具体的聚合持有对象集合 并提供一个方法返回一个迭代器 该迭代器可以正确遍历集合Client :客户端 通过 Iterator 和 Aggregate 依赖子类

  62. 应用案例一学校院系结构问题 需求 编写程序展示一个学校院系结构需求是这样要在一个页面中展示出学校的院系组成一个学校 有多个学院 一个学院有多个系。 传统的方式的问题分析 将学院看做是学校的子类系是学院的子类这样实际上是站在组织大小来进行分层次的实际上我们的要求是在一个页面中展示出学校的院系组成一个学校有多个学院一个学院有多个系因此这种方案不能很好实现的遍历的操作解决方案 迭代器模式

  63. 代码实现 应用实例要求 编写程序展示一个学校院系结构需求是这样要在一个页面中展示出学校的院系组成一个学校有多个学院 一个学院有多个系。设计思路分析 代码实现 ① 迭代器接口Iterator 使用jdk提供的java.util.Iterator ② 具体的迭代器类ConcreteIterator 角色 public class InfoCollegeIterator implements Iterator {ListDepartment departmentList;//信息工程学院是以List方式存放系int index -1;//遍历的位置public InfoCollegeIterator(ListDepartment departmentList) {this.departmentList departmentList;}Overridepublic boolean hasNext() {if (indexdepartmentList.size()-1){return false;}index 1;return true;}Overridepublic Object next() {Department department departmentList.get(index);return department;}//删除方法默认空实现Overridepublic void remove() {} } public class ComputerCollegeIterator implements Iterator {//需要知道Department是以怎样的方式存放 数组Department[] departments;int position 0;//遍历的位置public ComputerCollegeIterator(Department[] departments) {this.departments departments;}Overridepublic boolean hasNext() {if (positiondepartments.length||departments[position]null){return false;}return true;}Overridepublic Object next() {Department department departments[position];position 1;return department;}//删除方法默认空实现Overridepublic void remove() {} } ③ 统一的聚合接口 Aggregate 角色 public interface College {public String getName();//增加系的方法public void addDepartment(String name,String desc);//返回一个迭代器 遍历public Iterator createIterator(); } ④ 具体的聚合持有对象集合 (ConcreteAggreage 角色) public class ComputerColleage implements College {Department[] departments;int numOfDepartment 0;//保存当前数组的对象个数public ComputerColleage() {departments new Department[5];addDepartment(Java,java专业);addDepartment(PHP,PHP专业);addDepartment(大数据,大数据专业);}Overridepublic String getName() {return 计算机学院;}Overridepublic void addDepartment(String name, String desc) {Department department new Department(name,desc);departments[numOfDepartment] department;numOfDepartment 1;}Overridepublic Iterator createIterator() {return new ComputerCollegeIterator(departments);} } public class InfoCollegeIterator implements Iterator {ListDepartment departmentList;//信息工程学院是以List方式存放系int index -1;//遍历的位置public InfoCollegeIterator(ListDepartment departmentList) {this.departmentList departmentList;}Overridepublic boolean hasNext() {if (indexdepartmentList.size()-1){return false;}index 1;return true;}Overridepublic Object next() {Department department departmentList.get(index);return department;}//删除方法默认空实现Overridepublic void remove() {} } ⑤ 输出类个人认为有点像外观模式中的外观类 public class OutputImpl {//学院集合ListCollege collegeList;public OutputImpl(ListCollege collegeList) {this.collegeList collegeList;}//遍历所有的许愿 然后调用printDepartment 输出各个学院的系public void printCollege(){//从collegeList去除所有学院//java 中的List已经实现了iteratorIteratorCollege iterator collegeList.iterator();while (iterator.hasNext()){College c (College)iterator.next();System.out.println(c.getName());printDepartment(c.createIterator());}}//输出 学院输出系public void printDepartment(Iterator iterator){while (iterator.hasNext()){Department d (Department)iterator.next();System.out.println(d.getName() – d.getDesc());}} } ⑥ 客户端调用 public class Client {public static void main(String[] args) {//创建学院ArrayListCollege collegeList new ArrayList();ComputerColleage computerColleage new ComputerColleage();InfoColleage infoColleage new InfoColleage();collegeList.add(computerColleage);collegeList.add(infoColleage);OutputImpl output new OutputImpl(collegeList);output.printCollege();} }

  64. JDK源码ArrayList JDK 的 ArrayList集合中就使用了迭代器模式 public class IteratorDemo {public static void main(String[] args) {ListString a new ArrayList();a.add(jack);a.add(tom);IteratorString iterator a.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}} } 对类图的角色分析和说明 内部类 Itr 充当具体实现迭代器 Iterator 的类 作为 ArrayList 内部类List 就是充当了聚合接口含有一个 iterator() 方法返回一个迭代器对象ArrayList 是实现聚合接口 List 的子类实现了 iterator()Iterator 接口系统提供迭代器模式解决了 不同集合(ArrayList ,LinkedList) 统一遍历问题

  65. 知识小结 优点 提供一个统一的方法遍历对象客户不用再考虑聚合的类型使用一种方法就可以遍历对象了。隐藏了聚合的内部结构客户端要遍历聚合的时候只能取到迭代器而不会知道聚合的具体组成。提供了一种设计思想就是一个类应该只有一个引起变化的原因叫做单一责任原则。在聚合类中我们把迭代器分开就是要把管理对象集合和遍历对象集合的责任分开这样一来集合改变的话只影响到聚合对象。而如果遍历方式改变的话只影响到了迭代器。当要展示一组相似对象或者遍历一组相同对象时使用, 适合使用迭代器模式 缺点 每个聚合对象都要一个迭代器会生成多个迭代器不好管理类 五、观察者模式

  66. 基本介绍 观察者模式类似订牛奶业务奶站/气象局Subject用户/第三方网站Observer Subject登记注册、移除和通知 registerObserver 注 册removeObserver 移除notifyObservers() 通知所有的注册的用户根据不同需求可以是更新数据让用户来取也可能是实施推送 看具体需求定Observer接收输入观察者模式对象之间多对一依赖的一种设计方案被依赖的对象为 Subject依赖的对象为ObserverSubject 通知 Observer 变化,比如这里的奶站是 Subject是 1 的一方。用户时 Observer是多的一方。

  67. 应用案例一天气预报问题 需求 天气预报项目需求,具体要求如下 气象站可以将每天测量到的温度湿度气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。需要设计开放型 API便于其他第三方也能接入气象站获取数据。提供温度、气压和湿度的接口测量数据更新时要能实时的通知给第三方 传统方案 或者 传统方式代码实现 天气情况 CurrentConditions public class CurrentConditions {// 温度气压湿度private float temperature;private float pressure;private float humidity;//更新 天气情况是由 WeatherData 来调用我使用推送模式public void update(float temperature, float pressure, float humidity) {this.temperature temperature;this.pressure pressure;this.humidity humidity;display();}//显示public void display() {System.out.println(**Today mTemperature: temperature **);System.out.println(**Today mPressure: pressure **);System.out.println(**Today mHumidity: humidity **);} } 天气核心类 WeatherData /*** 类是核心* 1. 包含最新的天气情况信息* 2. 含有 CurrentConditions 对象* 3. 当数据有更新时就主动的调用 CurrentConditions 对象 update 方法(含 display), 这样他们接入方就看到最新的信息** author Administrator/ public class WeatherData {private float temperatrue;private float pressure;private float humidity;private CurrentConditions currentConditions;//加入新的第三方public WeatherData(CurrentConditions currentConditions) {this.currentConditions currentConditions;}public float getTemperature() {return temperatrue;}public float getPressure() {return pressure;}public float getHumidity() {return humidity;}public void dataChange() {//调用 接入方的 updatecurrentConditions.update(getTemperature(), getPressure(), getHumidity());}//当数据有更新时就调用 setDatapublic void setData(float temperature, float pressure, float humidity) {this.temperatrue temperature;this.pressure pressure;this.humidity humidity;//调用 dataChange 将最新的信息 推送给 接入方 currentConditionsdataChange();} } 客户端测试 public class Client {public static void main(String[] args) {//创建接入方 currentConditionsCurrentConditions currentConditions new CurrentConditions();//创建 WeatherData 并将 接入方 currentConditions 传递到 WeatherData 中WeatherData weatherData new WeatherData(currentConditions);//更新天气情况weatherData.setData(30, 150, 40);//天气情况变化System.out.println(天气情况变化);weatherData.setData(40, 160, 20);} } 传统方式问题分析 其他第三方接入气象站获取数据的问题无法在运行时动态的添加第三方 (新浪网站)违反 ocp 原则观察者模式//在 WeatherData 中当增加一个第三方都需要创建一个对应的第三方的公告板对象并加入到 dataChange, 不利于维护也不是动态加入 观测者模式实现 ① Subject角色(主题) 登记注册、移除和通知 抽象主题 public interface Subject {public void registerObserver(Observer observer);public void removeObserver(Observer observer);public void notifyObservers(); } 具体主题 /** 类是核心* 1. 包含最新的天气情况信息* 2. 含有 观察者 使用ArrayList管理* 3. 当数据有更新时就主动的调用 ArrayList 这样他们接入方就看到最新的信息** author Administrator/ public class WeatherData implements Subject{private float temperatrue;private float pressure;private float humidity;//观察者集合private ArrayListObserver observers;public WeatherData() {observers new ArrayList();}public float getTemperature() {return temperatrue;}public float getPressure() {return pressure;}public float getHumidity() {return humidity;}//当数据有更新时就调用 setDatapublic void setData(float temperature, float pressure, float humidity) {this.temperatrue temperature;this.pressure pressure;this.humidity humidity;dataChange();}public void dataChange() {notifyObservers();}Overridepublic void registerObserver(Observer observer) {observers.add(observer);}Overridepublic void removeObserver(Observer observer) {if (observers.contains(observer)){observers.remove(observer);}}Overridepublic void notifyObservers() {for (Observer observer: observers) {observer.update(getTemperature(),getPressure(),getHumidity());}}} ② Observer接收输入 抽象观察者 /** description 观察者接口由观察者来实现*/ public interface Observer {public void update(float temperature,float pressure,float humidity); } 具体观察者 public class CurrentConditions implements Observer {// 温度气压湿度private float temperature;private float pressure;private float humidity;//更新 天气情况是由 WeatherData 来调用我使用推送模式public void update(float temperature, float pressure, float humidity) {this.temperature temperature;this.pressure pressure;this.humidity humidity;display();}//显示public void display() {System.out.println(**Today mTemperature: temperature **);System.out.println(**Today mPressure: pressure **);System.out.println(**Today mHumidity: humidity **);} } 具体观察者扩展天气服务站点 public class BaiduSite implements Observer {// 温度气压湿度private float temperature;private float pressure;private float humidity;//更新 天气情况是由 WeatherData 来调用我使用推送模式public void update(float temperature, float pressure, float humidity) {this.temperature temperature;this.pressure pressure;this.humidity humidity;display();}//显示public void display() {System.out.println(**百度数据 气温: temperature **);System.out.println(**百度数据 气压: pressure **);System.out.println(**百度数据 湿度: humidity **);} } ③ 客户端调用 public class Client {public static void main(String[] args) {//创建一个WeatherDataSubject subject new WeatherData();//创建观察者Observer observer new CurrentConditions();Observer observer2 new BaiduSite();//注册到weatherDatasubject.registerObserver(observer);subject.registerObserver(observer2);//通知各个注册的观察者((WeatherData)subject).setData(10f,20f,30f);} }

  68. JDK源码Observable Jdk 的 Observable 类就使用了观察者模式 public interface Observer {//抽象观察者//只定义了一个update方法void update(Observable o, Object arg); }public class Observable {//抽象被观察者private boolean changed false;//定义改变状态默认为falseprivate final ArrayListObserver observers;//定义一个观察者listpublic Observable() {//构造函数初始化一个观察者list来保存观察者observers new ArrayList();}//添加观察者带同步字段的所以是线程安全的public synchronized void addObserver(Observer o) {if (o null)throw new NullPointerException();if (!observers.contains(o)) {observers.add(o);}}//删除观察者public synchronized void deleteObserver(Observer o) {observers.remove(o);}//通知所以观察者无参数public void notifyObservers() {notifyObservers(null);}//通知所有观察者带参数public void notifyObservers(Object arg) {Observer[] arrLocal;//加synchronized字段保证多线程下操作没有问题synchronized (this) {if (!hasChanged())//这里做了是否发生改变的判断是为了防止出现无意义的更新return;arrLocal observers.toArray(new Observer[observers.size()]);//ArrayList转换成一个临时的数组这样就防止了通知添加移除同时发生可能导致的异常clearChanged();///清除改变状态设置为false}//遍历逐一通知for (int i arrLocal.length-1; i0; i–)arrLocal[i].update(this, arg);}//清楚所有观察者public synchronized void deleteObservers() {observers.clear();}//设置被观察者为改变状态设置为trueprotected synchronized void setChanged() {changed true;}//清除改变状态设置为falseprotected synchronized void clearChanged() {changed false;}//返回当前的改变状态public synchronized boolean hasChanged() {return changed;}//观察者数量public synchronized int countObservers() {return observers.size();} } 模式角色分析 Observable 的作用和地位等价于 我们前面讲过SubjectObservable 是类不是接口类中已经实现了核心的方法 ,即管理 Observer 的方法 add.. delete ..notify…Observer 的作用和地位等价于我们前面讲过的 Observer, 有 updateObservable 和 Observer 的使用方法和前面讲过的一样只是 Observable 是类通过继承来实现观察者模式

  69. 知识小结 优点 观察者模式设计后会以集合的方式来管理用户(Observer)包括注册移除和通知。这样我们增加观察者(这里可以理解成一个新的公告板)就不需要去修改核心类 WeatherData 不会修改代码 遵守了 ocp 原则。解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。易于扩展对同一主题新增观察者时无需修改原有代码。 缺点 依赖关系并未完全解除抽象主题仍然依赖抽象观察者。使用观察者模式时需要考虑一下开发效率和运行效率的问题程序中包括一个被观察者、多个观察者开发、调试等内容会比较复杂而且在Java中消息的通知一般是顺序执行那么一个观察者卡顿会影响整体的执行效率在这种情况下一般会采用异步实现。可能会引起多余的数据通知。 六、中介者模式

  70. 基本介绍 中介者模式Mediator Pattern用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用从而使其耦合松散而且可以独立地改变它们之间的交互中介者模式属于行为型模式使代码易于维护比如 MVC 模式CController 控制器是 MModel 模型和 VView 视图的中介者在前后端交互时起到了中间人的作用 原理类图 对原理类图的说明-即(中介者模式的角色及职责) Mediator 就是抽象中介者,定义了同事对象到中介者对象的接口Colleague 是抽象同事类ConcreteMediator 具体的中介者对象, 实现抽象方法, 他需要知道所有的具体的同事类,即以一个集合来管理 HashMap,并接受某个同事对象消息完成相应的任务ConcreteColleague 具体的同事类会有很多, 每个同事只知道自己的行为 而不了解其他同事类的行为(方法) 但是他们都依赖中介者对象

  71. 应用案例一智能家庭管理问题 需求 智能家庭包括各种设备闹钟、咖啡机、电视机、窗帘 等主人要看电视时各个设备可以协同工作自动完成看电视的准备工作比如流程为闹铃响起-咖啡机开始做咖啡-窗帘自动落下-电视机开始播放 传统方式解决 传统的方式的问题分析 当各电器对象有多种状态改变时相互之间的调用关系会比较复杂各个电器对象彼此联系你中有我我中有你不利于松耦合.各个电器对象之间所传递的消息(参数)容易混乱当系统增加一个新的电器对象时或者执行流程改变时代码的可维护性、扩展性都不理想考虑中介者模式 代码实现 完成前面的智能家庭的项目使用中介者模式 中介者模式一智能家庭的操作流程: 创建ConcreMediator对象 public abstract class Mediator { //将给中介者对象加入到集合中 public abstract void Register(String colleagueName, Colleague colleague);//接收消息, 具体的同事对象发出 public abstract void GetMessage(int stateChange, String colleagueName);public abstract void SendMessage(); } 创建各个同事类对象比如 Alarm、CoffeeMachine. TV.. 在创建同事类对象的时候就直接通过构造器加入到 colleagueMap public abstract class Colleague {private Mediator mediator;public String name;public Colleague(Mediator mediator, String name) {this.mediator mediator;this.name name;}public Mediator getMediator() {return mediator;}public abstract void SendMessage(int stateChange); } public class TV extends Colleague {public TV(Mediator mediator, String name) {super(mediator, name);mediator.Register(name, this);}Overridepublic void SendMessage(int stateChange) {this.GetMediator().GetMessage(stateChange, this.name);}public void StartTv() {System.out.println(Its time to StartTv!);}public void StopTv() {System.out.println(StopTv!);} }//具体的同事类 public class Alarm extends Colleague {//构造器public Alarm(Mediator mediator, String name) {super(mediator, name);//在创建 Alarm 同事对象时将自己放入到 ConcreteMediator 对象中[集合]mediator.Register(name, this);}public void SendAlarm(int stateChange) {SendMessage(stateChange);}Overridepublic void SendMessage(int stateChange) {this.GetMediator().GetMessage(stateChange, this.name);}}public class CoffeeMachine extends Colleague {public CoffeeMachine(Mediator mediator, String name) {super(mediator, name);mediator.Register(name, this);}Overridepublic void SendMessage(int stateChange) {this.GetMediator().GetMessage(stateChange, this.name);}public void StartCoffee() {System.out.println(Its time to startcoffee!);}public void FinishCoffee() {System.out.println(After 5 minutes!);System.out.println(Coffee is ok!);SendMessage(0);} }public class Curtains extends Colleague {public Curtains(Mediator mediator, String name) { super(mediator, name);mediator.Register(name, this);}Overridepublic void SendMessage(int stateChange) {this.GetMediator().GetMessage(stateChange, this.name);}public void UpCurtains() {System.out.println(I am holding Up Curtains!);}} 同事类对象可以调用sendMessage 最终会去调用 ConcreteMediator的 getMessage方法 //具体的中介者类 public class ConcreteMediator extends Mediator {//集合放入所有的同事对象private HashMapString, Colleague colleagueMap;private HashMapString, String interMap;public ConcreteMediator() {colleagueMap new HashMapString, Colleague();interMap new HashMapString, String();}Overridepublic void Register(String colleagueName, Colleague colleague) {colleagueMap.put(colleagueName, colleague);if (colleague instanceof Alarm) {interMap.put(Alarm, colleagueName);} else if (colleague instanceof CoffeeMachine) {interMap.put(CoffeeMachine, colleagueName);} else if (colleague instanceof TV) {interMap.put(TV, colleagueName);} else if (colleague instanceof Curtains) {interMap.put(Curtains, colleagueName);}}//具体中介者的核心方法//1. 根据得到消息完成对应任务//2. 中介者在这个方法协调各个具体的同事对象完成任务Overridepublic void GetMessage(int stateChange, String colleagueName) {//处理闹钟发出的消息if (colleagueMap.get(colleagueName) instanceof Alarm) {if (stateChange 0) {((CoffeeMachine) (colleagueMap.get(interMap.get(CoffeeMachine)))).StartCoffee();((TV) (colleagueMap.get(interMap.get(TV)))).StartTv();} else if (stateChange 1) {((TV) (colleagueMap.get(interMap.get(TV)))).StopTv();}} else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {((Curtains) (colleagueMap.get(interMap.get(Curtains)))).UpCurtains();} else if (colleagueMap.get(colleagueName) instanceof TV) {//如果 TV 发现消息} else if (colleagueMap.get(colleagueName) instanceof Curtains) {//如果是以窗帘发出的消息这里处理…}}Overridepublic void SendMessage() {}} getMessage会根据接收到的同事对象发出的消息来协调调用其它的同事对象 完成任务 可以看到getMessage是核心方法完成相应任务 public class Client {public static void main(String[] args) {//创建一个中介者对象Mediator mediator new ConcreteMediator();//创建 Alarm 并且加入到 ConcreteMediator 对象的 HashMapAlarm alarm new Alarm(mediator, alarm);//创建了 CoffeeMachine 对象并 且加入到 ConcreteMediator 对象的 HashMapCoffeeMachine coffeeMachine new CoffeeMachine(mediator, coffeeMachine);//创建 Curtains , 并 且加入到 ConcreteMediator 对象的 HashMapCurtains curtains new Curtains(mediator, curtains);TV tV new TV(mediator, TV);//让闹钟发出消息alarm.SendAlarm(0);coffeeMachine.FinishCoffee();alarm.SendAlarm(1);} }

  72. 知识小结 多个类相互耦合会形成网状结构,使用中介者模式将网状结构分离为星型结构进行解耦减少类间依赖降低了耦合符合迪米特原则中介者承担了较多的责任一旦中介者出现了问题整个系统就会受到影响如果设计不当中介者对象本身变得过于复杂这点在实际使用时要特别注意 七、备忘录模式

  73. 基本介绍 备忘录模式Memento Pattern在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态可以这里理解备忘录模式现实生活中的备忘录是用来记录某些要去做的事情或者是记录已经达成的共同意见的事情以防忘记了。而在软件层面备忘录模式有着相同的含义备忘录对象主要用来记录一个对象的某种状态或者某些数据当要做回退时可以从备忘录对象里获取原来的数据进行恢复操作备忘录模式属于行为型模式

  74. 基本原理 原理图 对原理类图的说明-即(备忘录模式的角色及职责) originator : 对象(需要保存状态的对象)Memento 备忘录对象,负责保存好记录即 Originator 内部状态Caretaker: 守护者对象,负责保存多个备忘录对象 使用集合管理提高效率说明如果希望保存多个 originator 对象的不同时间的状态也可以只需要要 HashMap String, 集合

  75. 代码实现 ① Originator 需要保存状态的对象 public class Originator {private String state;//状态信息public String getState() {return state;}public void setState(String state) {this.state state;}//编写一个方法可以保存一个状态对象Memento// 因此编写一个方法返回Mementopublic Memento saveStateMemento(){return new Memento(state);}//通过备忘录对象恢复状态public String getStateFromMemento(Memento memento){state memento.getState();return state;}} ② Memento 备忘录对象 即Originator的内部状态 public class Memento {private String state;public Memento(String state) {this.state state;}public String getState() {return state;} } ③ Caretaker 守护者对象 public class Caretaker {//在list集合中会有很多的备忘录private ListMemento mementoList new ArrayList();public void add(Memento memento){mementoList.add(memento);}//获取到第index个Originator的备忘录对象public Memento get(int index){return mementoList.get(index);}} ④ 客户端调用 public class Client {public static void main(String[] args) {Originator originator new Originator();Caretaker caretaker new Caretaker();originator.setState( 状态#1 血槽全满 );//保存了当前的状态caretaker.add(originator.saveStateMemento());originator.setState( 状态#2 血槽还剩80% );caretaker.add(originator.saveStateMemento());originator.setState( 状态#3 血槽还剩50% );caretaker.add(originator.saveStateMemento());System.out.println(当前的状态是originator.getState());//希望恢复到状态1System.out.println(恢复到状态1originator.getStateFromMemento(caretaker.get(0)));} }

  76. 应用案例一游戏角色状态恢复问题 需求提出 游戏角色有攻击力和防御力在大战 Boss 前保存自身的状态(攻击力和防御力)当大战 Boss 后 攻击力和防御力下降从备忘录对象恢复到大战前的状态 传统的方式的问题分析 一个对象就对应一个保存对象状态的对象 这样当我们游戏的对象很多时不利于管理开销也很大.传统的方式是简单地做备份new 出另外一个对象出来再把需要备份的数据放到这个新对象但这就暴露了对象内部的细节解决方案 备忘录模式 代码实现 游戏角色有攻击力和防御力在大战 Boss 前保存自身的状态(攻击力和防御力)当大战 Boss 后 攻击力和防御力下降从备忘录对象恢复到大战前的状态 备忘录对象Originator内部状态 public class Memento {private int vit;//攻击力private int def;//防御力public Memento(int vit, int def) {this.vit vit;this.def def;}public int getVit() {return vit;}public int getDef() {return def;}} 游戏角色 originator角色需要保存状态的对象 public class GameRole {private int vit;private int def;public void setDef(int def) {this.def def;}public void setVit(int vit) {this.vit vit;}public Memento createMemento(){return new Memento(vit,def);}//恢复gameRole的状态public void recoverGameRoleFromMemento(Memento memento){this.vit memento.getVit();this.def memento.getDef();}//显示当前游戏角色的状态public void display(){System.out.println(游戏角色当前的攻击力this.vit当前游戏角色的防御力this.def);}} Caretaker: 守护者对象,负责保存多个备忘录对象 //守护者对象保存游戏角色的状态 public class Caretaker {//对游戏角色保存状态private Memento memento;public Memento getMemento() {return memento;}public void setMemento(Memento memento) {this.memento memento;} } 客户端测试代码 public class Client {public static void main(String[] args) {//创建游戏角色GameRole gameRole new GameRole();gameRole.setVit(100);gameRole.setDef(100);System.out.println(和boss大战前的状态);gameRole.display();//把当前状态保存caretakerCaretaker caretaker new Caretaker();caretaker.setMemento(gameRole.createMemento());System.out.println(和boss开始大战);gameRole.setDef(30);gameRole.setVit(30);gameRole.display();System.out.println(大战后使用备忘录恢复元气);gameRole.recoverGameRoleFromMemento(caretaker.getMemento());gameRole.display();} } 输出 和boss大战前的状态 游戏角色当前的攻击力100当前游戏角色的防御力100 和boss开始大战 游戏角色当前的攻击力30当前游戏角色的防御力30 大战后使用备忘录恢复元气 游戏角色当前的攻击力100当前游戏角色的防御力100

  77. 知识小结 给用户提供了一种可以恢复状态的机制可以使用户能够比较方便地回到某个历史的状态实现了信息的封装使得用户不需要关心状态的保存细节如果类的成员变量过多势必会占用比较大的资源而且每一次保存都会消耗一定的内存, 这个需要注意适用的应用场景1、后悔药。 2、打游戏时的存档。 3、Windows 里的 ctri z。 4、IE 中的后退。数据库的事务管理 为了节约内存备忘录模式可以和原型模式配合使用 八、解释器模式

  78. 基本介绍 1、在编译原理中一个算术表达式通过词法分析器形成词法单元而后这些词法单元再通过语法 分析器构建语法分析树最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以 看做是解释器 2、解释器模式Interpreter Pattern是指给定一个语言(表达式)定义它的文法的一种表示 并定义一个解释器使用该解释器来解释语言中的句子(表达式) 3、应用场景 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树一些重复出现的问题可以用一种简单的语言来表达一个简单语法需要解释的场景 4、这样的例子还有比如编译器、运算表达式计算、正则表达式、机器人等 2. 基本原理 对原理类图的说明-即(解释器模式的角色及职责) Context: 是环境角色,含有解释器之外的全局信息.AbstractExpression: 抽象表达式 声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享TerminalExpression: 为终结符表达式, 实现与文法中的终结符相关的解释操作NonTermialExpression: 为非终结符表达式为文法中的非终结符实现解释操作.说明 输入 Context 和 TerminalExpression 信息通过 Client 输入即可

  79. 应用案例一四则运算问题 需求 通过解释器模式来实现四则运算如计算 ab-c 的值具体要求 先输入表达式的形式比如 abc-de, 要求表达式的字母不能重复在分别输入 a ,b, c, d, e 的值 传统方案解决四则运算问题分析 编写一个方法接收表达式的形式然后根据用户输入的数值进行解析得到结果问题分析如果加入新的运算符比如 * / ( 等等不利于扩展另外让一个方法来解析会造成程序结构混乱 不够清晰.解决方案可以考虑使用解释器模式 即 表达式 - 解释器(可以有多种) - 结果 代码实现 应用实例要求 通过解释器模式来实现四则运算 如计算 ab-c 的值思路分析和图解(类图) ① 抽象表达式 /*** description 抽象类表达式通过hashmap键值对可以获取到变量的值/ public abstract class Expression {// a b - c//解释公式和数值key就是公式表达式 参数[a,b,c],value 就是具体值//hashmap {a10,b20}public abstract int interpreter(HashMapString,Integer var); } ② 具体表达式 /** 抽象运算符号解析器这里每个运算符号都只和自己左右两个数字有关系* 但左右两个数字有可能也是一个解析的结果无论何种类型都是Expression类的实现类/ public class SymbolExpression extends Expression{protected Expression left;protected Expression right;public SymbolExpression(Expression left, Expression right) {this.left left;this.right right;}//SymbolExpression 是让他的子类来实现的因此interpreter是一个默认实现Overridepublic int interpreter(HashMapString, Integer var) {return 0;} }/** 变量的解释器/ public class VarExpression extends Expression {private String key; //key a,key b,key c,public VarExpression(String key) {this.key key;}//interpreter根据变量名称 返回对应值Overridepublic int interpreter(HashMapString, Integer var) {return var.get(key);} } ③ 符号解释器 /** 加法解释器/ public class AddExpression extends SymbolExpression {public AddExpression(Expression left, Expression right) {super(left, right);}//处理相加Overridepublic int interpreter(HashMapString, Integer var) {// 返回left表达式对应的值 返回right表达式对应的值return super.left.interpreter(var)super.right.interpreter(var);} }/** description/ public class SubExpression extends SymbolExpression {public SubExpression(Expression left, Expression right) {super(left, right);}Overridepublic int interpreter(HashMapString, Integer var) {return super.left.interpreter(var)-super.right.interpreter(var);} } ④ 计算器 public class Calculator {// 定义表达式private Expression expression;// 构造函数传参并解析public Calculator(String expStr) { // expStr ab// 安排运算先后顺序StackExpression stack new Stack();// 表达式拆分成字符数组char[] charArray expStr.toCharArray();// [a, , b]Expression left null;Expression right null;//遍历我们的字符数组 即遍历 [a, , b]//针对不同的情况做处理for (int i 0; i charArray.length; i) {switch (charArray[i]) {case : //left stack.pop();// 从 stack 取 出 left aright new VarExpression(String.valueOf(charArray[i]));// 取出右表达式 bstack.push(new AddExpression(left, right));// 然后根据得到 left 和 right 构建 AddExpresson 加入stackbreak;case -: //left stack.pop();right new VarExpression(String.valueOf(charArray[i]));stack.push(new SubExpression(left, right));break;default://如果是一个 Var 就创建要给 VarExpression 对象并 push 到 stackstack.push(new VarExpression(String.valueOf(charArray[i])));break;}}//当遍历完整个 charArray 数组后stack 就得到最后 Expressionthis.expression stack.pop();}public int run(HashMapString, Integer var) {//最后将表达式 ab 和 var {a10,b20}//然后传递给 expression 的 interpreter 进行解释执行return this.expression.interpreter(var);}} ⑤ 客户端测试代码 /** description 解释器模式测试代码*/ public class Client {public static void main(String[] args) throws IOException {String expStr getExpStr(); // abHashMapString, Integer var getValue(expStr);// var {a10, b20}Calculator calculator new Calculator(expStr);System.out.println(运算结果 expStr calculator.run(var));}// 获得表达式public static String getExpStr() throws IOException {System.out.print(请输入表达式);return (new BufferedReader(new InputStreamReader(System.in))).readLine();}// 获得值映射public static HashMapString, Integer getValue(String expStr) throws IOException {HashMapString, Integer map new HashMap();for (char ch : expStr.toCharArray()) {if (ch ! ch ! -) {if (!map.containsKey(String.valueOf(ch))) {System.out.print(请输入 String.valueOf(ch) 的值);String in (new BufferedReader(new InputStreamReader(System.in))).readLine();map.put(String.valueOf(ch), Integer.valueOf(in));}}}return map;}} 输出 请输入表达式ab-c 请输入a的值10 请输入b的值5 请输入c的值3 运算结果ab-c12

  80. 知识小结 当有一个语言需要解释执行可将该语言中的句子表示为一个抽象语法树就可以考虑使用解释器模式 让程序具有良好的扩展性 应用场景编译器、运算表达式计算、正则表达式、机器人等使用解释器可能带来的问题解释器模式会引起类膨胀、解释器模式采用递归调用方法将会导致调试非 常复杂、效率可能降低. 九、状态模式

  81. 基本介绍 状态模式State Pattern它主要用来解决对象在多种状态转换时需要对外输出不同的行为的问题。状态和行为是一一对应的状态之间可以相互转换当一个对象的内在状态改变时允许改变其行为这个对象看起来像是改变了其类

  82. 基本原理 原理类图 对原理类图的说明-即(状态模式的角色及职责) Context 类为环境角色, 用于维护 State 实例,这个实例定义当前状态State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为ConcreteState 具体的状态角色每个子类实现一个与 Context 的一个状态相关行为

  83. 应用案例一APP 抽奖活动问题 需求提出 请编写程序完成 APP 抽奖活动 具体要求如下: 假如每参加一次这个活动要扣除用户 50 积分中奖概率是 10%奖品数量固定抽完就不能抽奖活动有四个状态: 可以抽奖、不能抽奖、发放奖品和奖品领完活动的四个状态转换关系图(右图) 代码实现 应用实例要求 完成 APP 抽奖活动项目使用状态模式.思路分析和图解(类图) -定义出一个接口叫状态接口每个状态都实现它。 -接口有扣除积分方法、抽奖方法、发放奖品方法 ① 抽象状态State角色 public abstract class State {abstract void deduceMoney();//扣除积分 -50abstract boolean raffle();//是否抽中奖品abstract void dispensePrize();//发放奖品 } ② 具体状态 ConcreteState角色 public class CanRaffleState extends State {RaffleActivity activity;public CanRaffleState(RaffleActivity activity) {this.activity activity;}//已经扣除了积分不能再扣Overridepublic void deduceMoney() {System.out.println(已经扣取过了积分);}//可以抽奖, 抽完奖后根据实际情况改成新的状态Overridepublic boolean raffle() {System.out.println(正在抽奖请稍等);Random r new Random();int num r.nextInt(10);// 10%中奖机会if (num 0) {// 改 变 活 动 状 态 为 发 放 奖 品 contextactivity.setState(activity.getDispenseState());return true;} else {System.out.println(很遗憾没有抽中奖品);// 改变状态为不能抽奖activity.setState(activity.getNoRafflleState());return false;}}// 不能发放奖品Overridepublic void dispensePrize() {System.out.println(没中奖不能发放奖品);}}public class NoRaffleState extends State {// 初始化时传入活动引用扣除积分后改变其状态RaffleActivity activity;public NoRaffleState(RaffleActivity activity) {this.activity activity;}//当前状态是可以扣积分的扣除后将状态设置成抽象状态Overridepublic void deduceMoney() {System.out.println(扣除 50 积分成功您可以抽奖了);activity.setState(activity.getCanRaffleState());}Overridepublic boolean raffle() {System.out.println(扣了积分才能抽奖喔);return false;}Overridepublic void dispensePrize() {System.out.println(不能发放奖品);} }public class DispenseState extends State {// 初始化时传入活动引用发放奖品后改变其状态RaffleActivity activity;public DispenseState(RaffleActivity activity) {this.activity activity;}Overridepublic void deduceMoney() {System.out.println(不能扣除积分);}Overridepublic boolean raffle() {System.out.println(不能抽奖);return false;}Overridepublic void dispensePrize() {if (activity.getCount() 0) {System.out.println(恭喜中奖了);// 改变状态为不能抽奖activity.setState(activity.getNoRafflleState());} else {System.out.println(很遗憾奖品发送完了);// 改变状态为奖品发送完毕, 后面我们就不可以抽奖activity.setState(activity.getDispensOutState());//System.out.println(抽奖活动结束);//System.exit(0);}} }public class DispenseOutState extends State {// 初始化时传入活动引用RaffleActivity activity;public DispenseOutState(RaffleActivity activity) {this.activity activity;}Overridepublic void deduceMoney() {System.out.println(奖品发送完了请下次再参加);}Overridepublic boolean raffle() {System.out.println(奖品发送完了请下次再参加);return false;}Overridepublic void dispensePrize() {System.out.println(奖品发送完了请下次再参加);} }③ 环境 Context角色 public class RaffleActivity {// state 表示活动当前的状态是变化State state null;// 奖品数量int count 0;// 四个属性表示四种状态State noRafflleState new NoRaffleState(this);State canRaffleState new CanRaffleState(this);State dispenseState new DispenseState(this);State dispensOutState new DispenseOutState(this);//构造器//1. 初始化当前的状态为 noRafflleState即不能抽奖的状态//2. 初始化奖品的数量public RaffleActivity(int count) {this.state getNoRafflleState();this.count count;}//扣分, 调用当前状态的 deductMoneypublic void debuctMoney() {state.deduceMoney();}//抽奖public void raffle() {// 如果当前的状态是抽奖成功if (state.raffle()) {//领取奖品state.dispensePrize();}}public State getState() {return state;}public void setState(State state) {this.state state;}//这里请大家注意每领取一次奖品count–public int getCount() {int curCount count;count–;return curCount;}public void setCount(int count) {this.count count;}public State getNoRafflleState() {return noRafflleState;}public void setNoRafflleState(State noRafflleState) {this.noRafflleState noRafflleState;}public State getCanRaffleState() {return canRaffleState;}public void setCanRaffleState(State canRaffleState) {this.canRaffleState canRaffleState;}public State getDispenseState() {return dispenseState;}public void setDispenseState(State dispenseState) {this.dispenseState dispenseState;}public State getDispensOutState() {return dispensOutState;}public void setDispensOutState(State dispensOutState) {this.dispensOutState dispensOutState;} } ④ 客户端测试代码 public class Client {public static void main(String[] args) {// 创建活动对象奖品有 1 个奖品RaffleActivity activity new RaffleActivity(1);// 我们连续抽 300 次奖for (int i 0; i 30; i) {System.out.println(——–第 (i 1) 次抽奖———-);// 参加抽奖第一步点击扣除积分activity.debuctMoney();// 第二步抽奖activity.raffle();}} }

  84. 源码剖析借贷平台
    需求提出 借贷平台的订单有审核-发布-抢单 等等 步骤随着操作的不同会改变订单的状态, 项目中的这个模块实现就会使用到状态模式使用状态模式完成 借贷平台项目的审核模块 [设计代码] 代码实现 ① 状态接口 public interface State {/*** 电 审/void checkEvent(Context context);/** 电审失败/void checkFailEvent(Context context);/** 定价发布/void makePriceEvent(Context context);/** 接 单/void acceptOrderEvent(Context context);/** 无人接单失效/void notPeopleAcceptEvent(Context context);/** 付 款/void payOrderEvent(Context context);/** 接单有人支付失效/void orderFailureEvent(Context context);/** 反 馈*/void feedBackEvent(Context context);String getCurrentState(); } public abstract class AbstractState implements State {protected static final RuntimeException EXCEPTION new RuntimeException(操作流程不允许);//抽象类默认实现了 State 接口的所有方法//该类的所有方法其子类(具体的状态类)可以有选择的进行重写Overridepublic void checkEvent(Context context) { throw EXCEPTION;}Overridepublic void checkFailEvent(Context context) { throw EXCEPTION;}Overridepublic void makePriceEvent(Context context) { throw EXCEPTION;}Overridepublic void acceptOrderEvent(Context context) { throw EXCEPTION;}Overridepublic void notPeopleAcceptEvent(Context context) { throw EXCEPTION;}Overridepublic void payOrderEvent(Context context) { throw EXCEPTION;}Overridepublic void orderFailureEvent(Context context) { throw EXCEPTION;}Overridepublic void feedBackEvent(Context context) { throw EXCEPTION;} } ② 具体状态及枚举 public enum StateEnum {//订单生成GENERATE(1, GENERATE),//已审核REVIEWED(2, REVIEWED),//已发布PUBLISHED(3, PUBLISHED),//待付款NOT_PAY(4, NOT_PAY),//已付款PAID(5, PAID),//已完结FEED_BACKED(6, FEED_BACKED);private int key; private String value;StateEnum(int key, String value) { this.key key;this.value value;}public int getKey() {return key;} public String getValue() {return value;}}//各种具体状态类 class FeedBackState extends AbstractState {Overridepublic String getCurrentState() {return StateEnum.FEED_BACKED.getValue();} }public class GenerateState extends AbstractState {Overridepublic void checkEvent(Context context) { context.setState(new ReviewState());}Overridepublic void checkFailEvent(Context context) { context.setState(new FeedBackState());}Overridepublic String getCurrentState() {return StateEnum.GENERATE.getValue();}}public class NotPayState extends AbstractState{Overridepublic void payOrderEvent(Context context) { context.setState(new PaidState());}Overridepublic void feedBackEvent(Context context) { context.setState(new FeedBackState());}Overridepublic String getCurrentState() {return StateEnum.NOT_PAY.getValue();}}public class PaidState extends AbstractState {Overridepublic void feedBackEvent(Context context) { context.setState(new FeedBackState());}Overridepublic String getCurrentState() {return StateEnum.PAID.getValue();}}public class PublishState extends AbstractState {Overridepublic void acceptOrderEvent(Context context) {//把当前状态设置为 NotPayState。。。//至于应该变成哪个状态有流程图来决定context.setState(new NotPayState());}Overridepublic void notPeopleAcceptEvent(Context context) { context.setState(new FeedBackState());}Overridepublic String getCurrentState() {return StateEnum.PUBLISHED.getValue();}}public class ReviewState extends AbstractState{Overridepublic void makePriceEvent(Context context) { context.setState(new PublishState());}Overridepublic String getCurrentState() {return StateEnum.REVIEWED.getValue();} } ③ 上下文环境 public class Context extends AbstractState{//当前的状态 state, 根据我们的业务流程处理不停的变化private State state;Overridepublic void checkEvent(Context context) { state.checkEvent(this); getCurrentState();}Overridepublic void checkFailEvent(Context context) { state.checkFailEvent(this); getCurrentState();}Overridepublic void makePriceEvent(Context context) { state.makePriceEvent(this); getCurrentState();}Overridepublic void acceptOrderEvent(Context context) { state.acceptOrderEvent(this); getCurrentState();}Overridepublic void notPeopleAcceptEvent(Context context) { state.notPeopleAcceptEvent(this); getCurrentState();}Overridepublic void payOrderEvent(Context context) { state.payOrderEvent(this); getCurrentState();}Overridepublic void orderFailureEvent(Context context) { state.orderFailureEvent(this); getCurrentState();}Overridepublic void feedBackEvent(Context context) { state.feedBackEvent(this); getCurrentState();}public State getState() { return state;}public void setState(State state) { this.state state;}Overridepublic String getCurrentState() {System.out.println(当前状态 : state.getCurrentState()); return state.getCurrentState();}} ④ 客户端测试 public class ClientTest {public static void main(String[] args) {// TODO Auto-generated method stub//创建 context 对象Context context new Context();//将当前状态设置为 PublishStatecontext.setState(new PublishState());System.out.println(context.getCurrentState());// //publish – not paycontext.acceptOrderEvent(context);// //not pay – paidcontext.payOrderEvent(context);// // 失败, 检测失败时会抛出异常try {context.checkFailEvent(context);System.out.println(流程正常..);} catch (Exception e) {// // TODO: handle exception// System.out.println(e.getMessage());// }}} } 输出 当前状态 : PUBLISHED PUBLISHED 当前状态 : NOT_PAY 当前状态 : PAID

  85. 知识小结 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中方便维护。将容易产生问题的 if-else 语句删除了如果把每个状态的行为都放到一个类中每次调用方法时都要判断当前是什么状态不但会产出很多 if-else 语句而且容易出错符合“开闭原则”。容易增删状态会产生很多类。每个状态都要一个对应的类当状态过多时会产生很多类加大维护难度应用场景当一个事件或者对象有很多种状态状态之间会相互转换对不同的状态要求有不同的行为的时候 可以考虑使用状态模式 十、策略模式

  86. 基本介绍 策略模式Strategy Pattern中定义算法族策略组分别封装起来让他们之间可以互相替换此模式让算法的变化独立于使用算法的客户这算法体现了几个设计原则第一、把变化的代码从不变的代码中分离出来第二、针对接口编程而不是具体类定义了策略接口第三、多用组合/聚合少用继承客户通过组合方式使用策略 说明从上图可以看到客户 context 有成员变量 strategy 或者其他的策略接口 ,至于需要使用到 哪个策略我们可以在构造器中指定

  87. 应用案例一鸭子飞行 需求分析 编写鸭子项目具体要求如下: 有各种鸭子(比如 野鸭、北京鸭、水鸭等 鸭子有各种行为比如 叫、飞行等)显示鸭子的信息 传统方式解决问题类图 传统的方式实现的问题分析和解决方案 其它鸭子都继承了 Duck 类所以 fly 让所有子类都会飞了这是不正确的上面说的 1 的问题其实是继承带来的问题对类的局部改动尤其超类的局部改动会影响其他部分。会有溢出效应为了改进 1 问题我们可以通过覆盖 fly 方法来解决 覆盖解决问题又来了如果我们有一个玩具鸭子 ToyDuck, 这样就需要 ToyDuck 去覆盖 Duck 的所有实现的方法 解决思路 - 策略模式 (strategy pattern) 代码实现 ① 行为接口 public interface FlyBehavior {void fly(); } ② 具体行为 public class GoodFlyBehavior implements FlyBehavior {Overridepublic void fly() {System.out.println(自由飞翔飞翔能力max);} }public class BadFlyBehavior implements FlyBehavior {Overridepublic void fly() {System.out.println(飞翔技术不太行);} }public class NoFlyBehavior implements FlyBehavior {Overridepublic void fly() {System.out.println(不会飞);} } ③ 行为执行者 组合不同的行为 public class WildDuck extends Duck {public WildDuck() {flyBehavior new GoodFlyBehavior();}Overridevoid display() {System.out.println(野鸭子);}}public class PekingDuck extends Duck {public PekingDuck() {flyBehavior new BadFlyBehavior();}Overridevoid display() {System.out.println(北京鸭);}}public class ToyDuck extends Duck{public ToyDuck() {flyBehavior new NoFlyBehavior();}Overridevoid display() {System.out.println(玩具鸭);}} ④ 客户端测试 public class Client {public static void main(String[] args) {WildDuck wildDuck new WildDuck();wildDuck.display();wildDuck.fly();PekingDuck pekingDuck new PekingDuck();pekingDuck.display();pekingDuck.fly();} }

  88. 应用案例二旅游出行 简介 先看下面的图片我们去旅游选择出行模式有很多种可以骑自行车、可以坐汽车、可以坐火车、可以坐飞 机。 作为一个程序猿开发需要选择一款开发工具当然可以进行代码开发的工具有很多可以选择 Idea进行开发也可以使用eclipse进行开发也可以使用其他的一些开发工具。 定义 该模式定义了一系列算法并将每个算法封装起来使它们可以相互替换且算法的变化不会影响 使用算法的客户。策略模式属于对象行为模式它通过对算法进行封装把使用算法的责任和算法 的实现分割开来并委派给不同的对象对这些算法进行管理。 结构 策略模式的主要角色如下 抽象策略Strategy类这是一个抽象角色通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。具体策略Concrete Strategy类实现了抽象策略定义的接口提供具体的算法实现或行为。环境Context类持有一个策略类的引用最终给客户端调用。 三案例实现 【例】促销活动 一家百货公司在定年度的促销活动。针对不同的节日春节、中秋节、圣诞节推出不同的促销活 动由促销员将促销活动展示给客户。 类图如下 聚合关系可以用带空心菱形的实线来表示 代码如下 定义百货公司所有促销活动的共同接口 public interface Strategy {void show(); } 定义具体策略角色Concrete Strategy每个节日具体的促销活动 //为春节准备的促销活动A public class StrategyA implements Strategy {public void show() {System.out.println(买一送一);} }//为中秋准备的促销活动B public class StrategyB implements Strategy {public void show() {System.out.println(满200元减50元);} }//为圣诞准备的促销活动C public class StrategyC implements Strategy {public void show() {System.out.println(满1000元加一元换购任意200元以下商品);} } 定义环境角色Context用于连接上下文即把促销活动推销给客户这里可以理解为销售员 public class SalesMan { //持有抽象策略角色的引用 private Strategy strategy; public SalesMan(Strategy strategy) { this.strategy strategy; } //向客户展示促销活动 public void salesManShow(){ strategy.show(); }
    }

  89. 应用案例三综合案例 简介 下图是gitee的登录的入口其中有多种方式可以进行登录 用户名密码登录短信验证码登录微信登录QQ登录…. 目前已实现的代码 (1)登录接口 说明 请求方式 POST 路径 /api/user/login 参数 LoginReq 返回值 LoginResp
    请求参数LoginReq Data public class LoginReq {private String name;private String password;private String phone;private String validateCode;//手机验证码private String wxCode;//用于微信登录/*** account : 用户名密码登录* sms : 手机验证码登录* we_chat : 微信登录/private String type; } 响应参数LoginResp Data public class LoginResp{private Integer userId;private String userName;private String roleCode;private String token; //jwt令牌private boolean success;} 控制层LoginController RestController RequestMapping(/api/user) public class LoginController {Autowiredprivate UserService userService;PostMapping(/login)public LoginResp login(RequestBody LoginReq loginReq){return userService.login(loginReq);} } 业务层UserService Service public class UserService {public LoginResp login(LoginReq loginReq){if(loginReq.getType().equals(account)){System.out.println(用户名密码登录);//执行用户密码登录逻辑return new LoginResp();}else if(loginReq.getType().equals(sms)){System.out.println(手机号验证码登录);//执行手机号验证码登录逻辑return new LoginResp();}else if (loginReq.getType().equals(we_chat)){System.out.println(微信登录);//执行用户微信登录逻辑return new LoginResp();}LoginResp loginResp new LoginResp();loginResp.setSuccess(false);System.out.println(登录失败);return loginResp;} } 注意我们重点讲的是设计模式并不是登录的逻辑所以以上代码并没有真正的实现登录功能 (2)问题分析 业务层代码大量使用到了if…else在后期阅读代码的时候会非常不友好大量使用if…else性能也不高如果业务发生变更比如现在新增了QQ登录方式这个时候需要修改业务层代码违反了开闭原则 解决使用工厂方法设计模式策略模式解决 代码改造工厂策略 1整体思路 改造之后不在service中写业务逻辑让service调用工厂然后通过service传递不同的参数来获 取不同的登录策略登录方式 2具体实现 抽象策略类UserGranter /** 抽象策略类/ public interface UserGranter{/** 获取数据* param loginReq 传入的参数* return map值/LoginResp login(LoginReq loginReq); } 具体的策略AccountGranter、SmsGranter、WeChatGranter /** 策略账号登录/ Component public class AccountGranter implements UserGranter{Overridepublic LoginResp login(LoginReq loginReq) {System.out.println(登录方式为账号登录 loginReq);// TODO// 执行业务操作 return new LoginResp();} } /* 策略:短信登录/ Component public class SmsGranter implements UserGranter{Overridepublic LoginResp login(LoginReq loginReq) {System.out.println(登录方式为短信登录 loginReq);// TODO// 执行业务操作return new LoginResp();} } /** 策略:微信登录/ Component public class WeChatGranter implements UserGranter{Overridepublic LoginResp login(LoginReq loginReq) {System.out.println(登录方式为微信登录 loginReq);// TODO// 执行业务操作return new LoginResp();} } 工程类UserLoginFactory /** 操作策略的上下文环境类 工具类* 将策略整合起来 方便管理/ Component public class UserLoginFactory implements ApplicationContextAware {private static MapString, UserGranter granterPool new ConcurrentHashMap();Autowiredprivate LoginTypeConfig loginTypeConfig;/** 从配置文件中读取策略信息存储到map中* {* account:accountGranter,* sms:smsGranter,* we_chat:weChatGranter* }** param applicationContext* throws BeansException/Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {loginTypeConfig.getTypes().forEach((k, y) - {granterPool.put(k, (UserGranter) applicationContext.getBean(y));});}/** 对外提供获取具体策略** param grantType 用户的登录方式需要跟配置文件中匹配* return 具体策略*/public UserGranter getGranter(String grantType) {UserGranter tokenGranter granterPool.get(grantType);return tokenGranter;}} 在application.yml文件中新增自定义配置 login:types:account: accountGrantersms: smsGranterwe_chat: weChatGranter 新增读取数据配置类 Getter Setter Configuration ConfigurationProperties(prefix login) public class LoginTypeConfig {private MapString,String types;}改造service代码 Service public class UserService {Autowiredprivate UserLoginFactory factory;public LoginResp login(LoginReq loginReq){UserGranter granter factory.getGranter(loginReq.getType());if(granter null){LoginResp loginResp new LoginResp();loginResp.setSuccess(false);return loginResp;}LoginResp loginResp granter.login(loginReq);return loginResp;} } 大家可以看到我们使用了设计模式之后业务层的代码就清爽多了如果后期有新的需求改动比如加入了QQ登录我们只需要添加对 应的策略就可以无需再改动业务层代码。 举一反三 其实像这样的需求在日常开发中非常常见场景有很多以下的情景都可以使用工厂模式策略模式解决比 如 订单的支付策略 支付宝支付微信支付银行卡支付现金支付 解析不同类型excel xls格式xlsx格式 打折促销 满300元9折满500元8折满1000元7折 物流运费阶梯计算 5kg以下5kg-10kg10kg-20kg20kg以上 一句话总结只要代码中有冗长的 if-else 或 switch 分支判断都可以采用策略模式优化

  90. JDK源码Arrays JDK 的 Arrays 的 Comparator 就使用了策略模式 public class Strategy {public static void main(String[] args) {//数组Integer[] data {9, 1, 2, 8, 4, 3};// 实现降序排序返回-1 放左边1 放右边0 保持不变// 说 明// 1. 实现了 Comparator 接口策略接口 , 匿名类 对象 new ComparatorInteger(){..}// 2. 对象 new ComparatorInteger(){..} 就是实现了 策略接口 的对象// 3. public int compare(Integer o1, Integer o2){} 指定具体的处理方式ComparatorInteger comparator new ComparatorInteger() {public int compare(Integer o1, Integer o2) {if (o1 o2) {return -1;} else {return 1;}};};// 说 明/public static T void sort(T[] a, Comparator? super T c) {if (c null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);}}///方式 1Arrays.sort(data, comparator);System.out.println(Arrays.toString(data)); // 降序排序//方式 2- 同时 lambda 表达式实现 策略模式Integer[] data2 {19, 11, 12, 18, 14, 13};Arrays.sort(data2, (var1, var2) - {if (var1.compareTo(var2) 0) {return -1;} else {return 1;}});System.out.println(data2 Arrays.toString(data2));} } 在Android中使用ListView时都需要设置一个Adapter而这个Adapter根据我们实际的需求可以 用ArrayAdapter、SimpleAdapter等等这里就运用到策略模式。

  91. 知识小结 策略模式的关键是分析项目中变化部分与不变部分策略模式的核心思想是多用组合/聚合 少用继承用行为类组合而不是行为的继承。更有弹性体现了“对修改关闭对扩展开放”原则客户端增加行为不用修改原有代码只要添加一种策略或者行为 即可避免了使用多重转移语句if..else if..else提供了可以替换继承关系的办法 策略模式将算法封装在独立的 Strategy 类中使得你可以独立于其Context 改变它使它易于切换、易于理解、易于扩展需要注意的是每添加一个策略就要增加一个类当策略过多是会导致类数目庞大 十一、职责链模式

  92. 基本介绍 职责链模式Chain of Responsibility Pattern, 又叫 责任链模式为请求创建了一个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求那么它会把相同的请求传给下一个接收者依此类推。这种类型的设计模式属于行为型模式 对原理类图的说明-即(职责链模式的角色及职责) Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外 HandlerConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求则处理否则就将该请求交个 后继者去处理从而形成一个职责链Request 含义很多属性表示一个请求

  93. 应用案例一学校OA系统采购审批 需求分析 需求学校 OA 系统的采购审批项目 采购员采购教学器材 如果金额 小于等于 5000, 由教学主任审批 0x5000如果金额 小于等于 10000, 由院长审批 (5000x10000)如果金额 小于等于 30000, 由副校长审批 (10000x30000)如果金额 超过 30000 以上有校长审批 ( 30000x) 请设计程序完成采购审批项目 传统设计方案 传统方案解决 OA 系统审批问题分析 传统方式是接收到一个采购请求后根据采购金额来调用对应的 Approver (审批人)完成审批。传统方式的问题分析 : 客户端这里会使用到 分支判断(比如 switch) 来对不同的采购请求处理 这样就存在如下问题 (1) 如果各个级别的人员审批金额发生变化在客户端的也需要变化 (2) 客户端必须明确的知道 有多少个审批级别和访问这样 对一个采购请求进行处理 和 Approver (审批人) 就存在强耦合关系不利于代码的扩展和维护解决方案 职责链模式 代码实现 ① 编写请求 Request角色 public class PurchaseRequest {private int type 0;private float price 0.0f;private int id 0;public PurchaseRequest(int id, int type, float price) {this.type type;this.id id;this.price price;}public int getType() {return type;}public float getPrice() {return price;}public int getId() {return id;} } ② 抽象的请求处理者 Handler角色 public abstract class Approver {protected Approver approver;//下一个处理者protected String name;//名字public Approver(String name) {this.name name;}public void setApprover(Approver approver) {this.approver approver;}abstract void processRequest(PurchaseRequest request); } ③ 具体的请求处理者 ConcreteHandler角色 public class DepartmentApprover extends Approver{public DepartmentApprover(String name) {super(name);}Overridevoid processRequest(PurchaseRequest request) {if (request.getPrice()5000){System.out.println(请求编号idrequest.getId() 被 this.name处理);}else {System.out.println(this.name无法处理交给上一级处理 - approver.name);approver.processRequest(request);}}}public class CollegeApprover extends Approver{public CollegeApprover(String name) {super(name);}Overridevoid processRequest(PurchaseRequest request) {if (request.getPrice()5000request.getPrice()10000){System.out.println(请求编号idrequest.getId() 被 this.name处理);}else {System.out.println(this.name无法处理交给上一级处理 - approver.name);approver.processRequest(request);}} }public class ViceSchoolMasterApprover extends Approver{public ViceSchoolMasterApprover(String name) {super(name);}Overridevoid processRequest(PurchaseRequest request) {if (request.getPrice()10000request.getPrice()30000){System.out.println(请求编号idrequest.getId() 被 this.name处理);}else {System.out.println(this.name无法处理交给上一级处理 - approver.name);approver.processRequest(request);}}}public class SchoolMasterApprover extends Approver{public SchoolMasterApprover(String name) {super(name);}Overridevoid processRequest(PurchaseRequest request) {if (request.getPrice()30000){System.out.println(请求编号idrequest.getId() 被 this.name处理);}else {System.out.println(this.name无法处理交给下一级处理 - approver.name);approver.processRequest(request);}}} ④ 客户端调用 public class Client {public static void main(String[] args) {//创建一个审批请求PurchaseRequest request new PurchaseRequest(1,1,13200);//创建相关的审批人DepartmentApprover departmentApprover new DepartmentApprover(主任);CollegeApprover collegeApprover new CollegeApprover(院长);ViceSchoolMasterApprover viceSchoolMasterApprover new ViceSchoolMasterApprover(副校长);SchoolMasterApprover schoolMasterApprover new SchoolMasterApprover(校长);//需要将各个审批节点的下一级设置好departmentApprover.setApprover(collegeApprover);collegeApprover.setApprover(viceSchoolMasterApprover);viceSchoolMasterApprover.setApprover(schoolMasterApprover);schoolMasterApprover.setApprover(departmentApprover);//处理请求departmentApprover.processRequest(request);} } 输出 主任无法处理交给上一级处理 - 院长 院长无法处理交给上一级处理 - 副校长 请求编号id1 被 副校长处理 3. 应用案例二订单处理 基本介绍 在现实生活中常常会出现这样的事例一个请求有多个对象可以处理但每个对象的处理条件或 权限不同。 例如公司员工请假可批假的领导有部门负责人、副总经理、总经理等但每个领导能批准的天 数不同员工必须根据自己要请假的天数去找不同的领导签名也就是说员工必须记住每个领导的 姓名、电话和地址等信息这增加了难度。这样的例子还有很多如找领导出差报销、生活中 的“击鼓传花”游戏等。 定义 又名职责链模式为了避免请求发送者与多个请求处理者耦合在一起将所有请求的处理者通过前 一对象记住其下一个对象的引用而连成一条链当有请求发生时可将请求沿着这条链传递直到 有对象处理它为止。 比较常见的springmvc中的拦截器web开发中的filter过滤器 基本结构 职责链模式主要包含以下角色: 抽象处理者Handler角色定义一个处理请求的接口包含抽象处理方法和一个后继连接。具体处理者Concrete Handler角色实现抽象处理者的处理方法判断能否处理本次请求如果可以处理请求则处理否则将该请求转给它的后继者。客户类Client角色创建处理链并向链头的具体处理者对象提交请求它不关心处理细节和请求的传递过程。 案例实现 处理订单的操作 类图 代码 抽象处理者 package com.itheima.designpattern.chain;/*** 抽象处理者/ public abstract class Handler {protected Handler handler;public void setNext(Handler handler) {this.handler handler;}/** 处理过程* 需要子类进行实现/public abstract void process(OrderInfo order); } 订单信息类 package com.itheima.designpattern.chain;import java.math.BigDecimal;public class OrderInfo {private String productId;private String userId;private BigDecimal amount;public String getProductId() {return productId;}public void setProductId(String productId) {this.productId productId;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId userId;}public BigDecimal getAmount() {return amount;}public void setAmount(BigDecimal amount) {this.amount amount;} } 具体处理者 /** 订单校验/ public class OrderValidition extends Handler {Overridepublic void process(OrderInfo order) {System.out.println(校验订单基本信息);//校验handler.process(order);}}/** 补充订单信息/ public class OrderFill extends Handler {Overridepublic void process(OrderInfo order) {System.out.println(补充订单信息);handler.process(order);}}/** 计算金额/ public class OrderAmountCalcuate extends Handler {Overridepublic void process(OrderInfo order) {System.out.println(计算金额-优惠券、VIP、活动打折);handler.process(order);}}/** 订单入库*/ public class OrderCreate extends Handler {Overridepublic void process(OrderInfo order) {System.out.println(订单入库);} }客户类 public class Application {public static void main(String[] args) {//检验订单Handler orderValidition new OrderValidition();//补充订单信息Handler orderFill new OrderFill();//订单算价Handler orderAmountCalcuate new OrderAmountCalcuate();//订单落库Handler orderCreate new OrderCreate();//设置责任链路orderValidition.setNext(orderFill);orderFill.setNext(orderAmountCalcuate);orderAmountCalcuate.setNext(orderCreate);//开始执行orderValidition.process(new OrderInfo());}} 优缺点 优点 降低了对象之间的耦合度该模式降低了请求发送者和接收者的耦合度。增强了系统的可扩展性可以根据需要增加新的请求处理类满足开闭原则。增强了给对象指派职责的灵活性当工作流程发生变化可以动态地改变链内的成员或者修改它们的次序也可动态地新增或者删除责任。责任链简化了对象之间的连接一个对象只需保持一个指向其后继者的引用不需保持其他所有处理者的引用这避免了使用众多的 if 或者 if···else 语句。责任分担每个类只需要处理自己该处理的工作不能处理的传递给下一个对象完成明确各类的责任范围符合类的单一职责原则。 缺点 不能保证每个请求一定被处理。由于一个请求没有明确的接收者所以不能保证它一定会被处理该请求可能一直传到链的末端都得不到处理。对比较长的职责链请求的处理可能涉及多个处理对象系统性能将受到一定影响。职责链建立的合理性要靠客户端来保证增加了客户端的复杂性可能会由于职责链的错误设置而导致系统出错如可能会造成循环调用。 举一反三 订单创建 4. Andorid 应用 Android中的事件分发机制就是类似于责任链模式。 另外OKhttp中对请求的处理也是用到了责任链模式。

  94. 知识小结 将请求和处理分开实现解耦提高系统的灵活性简化了对象使对象不需要知道链的结构性能会受到影响特别是在链比较长的时候因此需控制链中最大节点数量一般通过在 Handler 中设置一个最大节点数量在 setNext()方法中判断是否已经超过阀值超过则不允许该链建立避免出现超长链无意识地破坏系统性能调试不方便。采用了类似递归的方式调试时逻辑可能比较复杂最佳应用场景有多个对象可以处理同一个请求时比如多级请求、请假/加薪等审批流程、Java Web中 Tomcat 对 Encoding 的处理、拦截器