场景:
– 公司里面,报销个单据需要经过流程:
• 申请人填单申请,申请给经理
• 小于1000,经理审查。
• 超过1000,交给总经理审批。
• 总经理审批通过
– 公司里面,请假条的审批过程:
• 如果请假天数小于3天,主任审批
• 如果请假天数大于等于3天,小于10天,经理审批
• 如果大于等于10天,小于30天,总经理审批
• 如果大于等于30天,提示拒绝
场景:
– 公司里面,SCM(Supply Chain Management供应链管理)系统中,
采购审批子系统的设计:
• 采购金额小于5万,主任审批
• 采购金额大于等于5万,小于10万,经理审批
• 采购金额大于等于10万,小于20万,副总经理审批
• 采购金额大于等于20万,总经理审批
请假条审批流程案例
添加新的处理对象:
– 由于责任链的创建完全在客户端,因此新增新的具体处理者对原有类库没有任何影响,只需添加新的类,然后在客户端调用时添加即可。
符合开闭原则。
– 案例:
• 我们可以在请假处理流程中,增加新的“副总经理”角色,审批大于等于
10天,小于20天的请假。审批流程变为:
① 如果请假天数小于3天,主任审批
② 如果请假天数大于等于3天,小于10天,经理审批
③ 大于等于10天,小于20天的请假,副总经理审批
④ 如果大于等于20天,小于30天,总经理审批
⑤ 如果大于等于30天,提示拒绝
链表方式定义职责链(上一个案例)
• 非链表方式实现职责链
– 通过集合、数组生成职责链更加实用!实际上,很多项目中,每个具体的Handler并不是由开发团队定义的,而是项目上线后由外部单位追加的,所以使用链表方式定义COR链就很困难。
开发中常见的场景:
– Java中,异常机制就是一种责任链模式。一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch.
– Javascript语言中,事件的冒泡和捕获机制。Java语言中,事件的处理采用观察者模式。
– Servlet开发中,过滤器的链式处理
– Struts2中,拦截器的调用也是典型的责任链模式
迭代器模式:
场景:
– 提供一种可以遍历聚合对象的方式。又称为:游标cursor模式
– 聚合对象:存储数据
– 迭代器:遍历数据
结构:
– 聚合对象:存储数据
– 迭代器:遍历数据
基本案例:
– 实现正向遍历的迭代器
– 实现逆向遍历的迭代器
开发中常见的场景:
– JDK内置的迭代器(List/Set)
中介模式:
场景(中介大家熟悉吗?房产中介?):
– 假如没有总经理。下面三个部门:财务部、市场部、研发部。财务部要发工资,让大家核对公司需要跟市场部和研发部都通气;市场部要接个新项目,需要研发部处理技术、 需要财务部出资金。市场部跟各个部门打交道。 虽然只有三个部门,但是关系非常乱。
实际上,公司都有总经理。各个部门有什么事情都通报到总经理这里,总经理再通知各个相关部门。
这就是一个典型的“中介者模式”总经理起到一个中介、协调的作用
中介者模式的本质:
– 解耦多个同事对象之间的交互关系。每个对象都持有中介者对象的引用,只跟中介者对象打交道。我们通过中介者对象统一管理这些交互关系
开发中常见的场景:
– MVC模式(其中的C,控制器就是一个中介者对象。M和V都和他打交道)
– 窗口游戏程序,窗口软件开发中窗口对象也是一个中介者对象
– 图形界面开发GUI中,多个组件之间的交互,可以通过引入一个中介者对象来解决,可以是整体的窗口对象或者DOM对象
– Java.lang.reflect.Method#invoke()
命令模式:
开发中常见的场景:
– Struts2中,action的整个调用过程中就有命令模式。
– 数据库事务机制的底层实现
– 命令的撤销和恢复
解释器模式:
介绍:
– 是一种不常用的设计模式
– 用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计。
– 当我们需要开发一种新的语言时,可以考虑使用解释器模式。
– 尽量不要使用解释器模式,后期维护会有很大麻烦。在项目中,可以使用Jruby,Groovy、java的js引擎来替代解释器的作用,弥补java语言的不足。
开发中常见的场景:
– EL表达式式的处理
– 正则表达式解释器
– SQL语法的解释器
– 数学表达式解析器
• 如现成的工具包:Math Expression String Parser、Expression4J等。
– MESP的网址: http://sourceforge.net/projects/expression-tree/
– Expression4J的网址: http://sourceforge.net/projects/expression4j/
访问者模式:
模式动机:
– 对于存储在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口),对于该集合中的对象,可以接受一类称为访问者的对象来访问,不同的访问者其访问方式也有所不同。
• 定义:
– 表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变个元素的类的前提下定义作用于这些元素的新操作。
• 开发中的场景(应用范围非常窄,了解即可):
– XML文档解析器设计
– 编译器的设计
– 复杂集合对象的处理
策略模式:
场景:
– 某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂,可以简单作如下分类:
• 普通客户小批量报价
• 普通客户大批量报价
• 老客户小批量报价
• 老客户大批量报价
– 具体选用哪个报价策略,这需要根据实际情况来确定。这时候,我们采用策略模式即可。
我们先可以采用条件语句处理:
假如,类型特别多,算法比较复杂时,整个条件控制代码会变得很长,难于维护。
策略模式
– 策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。
本质:
– 分离算法,选择实现。
• 开发中常见的场景:
– JAVASE中GUI编程中,布局管理
– Spring框架中,Resource接口,资源访问策略
– javax.servlet.http.HttpServlet#service()
模板方法模式:
状态模式:
场景:
– 电梯的运行
• 维修、正常、自动关门、自动开门、向上运行、向下运行、消防状态
– 红绿灯
• 红灯、黄灯、绿灯
– 企业或*系统
• 公文的审批状态
– 报销单据审批状态
– 假条审批
– 网上购物时,订单的状态
• 下单
• 已付款
• 已发货
• 送货中
• 已收货
场景:
– 酒店系统中,房间的状态变化:
• 已预订
• 已入住
• 空闲
酒店系统中,房间状态变化的相关类图结构:
核心:
– 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
• 结构:
– Context环境类
• 环境类中维护一个State对象,他是定义了当前的状态。
– State抽象状态类
– ConcreteState具体状态类
• 每一个类封装了一个状态对应的行为
开发中常见的场景:
– 银行系统中账号状态的管理
– OA系统中公文状态的管理
– 酒店系统中,房间状态的管理
– 线程对象各状态之间的切换
观察者模式:
场景:
– 聊天室程序的创建。服务器创建好后,A,B,C三个客户端连上来公开聊天。A向服务器发送数据,服务器端聊天数据改变。我们希望将这些聊天数据分别发给其他在线的客户。也就是说,每个客户端需要更新服务器端得数据。
– 网站上,很多人订阅了”java主题”的新闻。当有这个主题新闻时,就会将这些新闻发给所有订阅的人。
– 大家一起玩CS游戏时,服务器需要将每个人的方位变化发给所有的客户。
上面这些场景,我们都可以使用观察者模式来处理。我们可以把多个订阅者、客户称之为观察者; 需要同步给多个订阅者的数据封装到对象中,称之为目标。
开发中常见的场景:
– 聊天室程序的,服务器转发给所有客户端
– 网络游戏(多人联机对战)场景中,服务器将客户端的状态进行分发
– 邮件订阅
– Servlet中,监听器的实现
– Android中,广播机制
– JDK的AWT中事件处理模型,基于观察者模式的委派事件模型(Delegation Event Model)
• 事件源----------------目标对象
• 事件监听器------------观察者
– 京东商城中,群发某商品打折信息
备忘录模式:
场景:
– 录入大批人员资料。正在录入当前人资料时,发现上一个人录错了,此时需要恢复上一个人的资料,再进行修改。
– Word文档编辑时,忽然电脑死机或断电,再打开时,可以看到word提示你恢复到以前的文档
– 管理系统中,公文撤回功能。公文发送出去后,想撤回来。
核心
– 就是保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态。
• 结构:
– 源发器类Originator
– 备忘录类Memento
– 负责人类CareTake
备忘点较多时:
– 将备忘录压栈
– 将多个备忘录对象,序列化和持久化
开发中常见的应用场景:
– 棋类游戏中的,悔棋
– 普通软件中的,撤销操作
– 数据库软件中的,事务管理中的,回滚操作
– Photoshop软件中的,历史记录