java模式笔记(五)——行为模式

不变模式

    一个类创建后,在整个生命周期内都不会变化。有两种:弱不变模式和强不变模式。

    弱不变模式:该类不变,子类有可能变化。1. 引用到其他对象时,在类内部初始化,如果必须在客户端初始化的,则在类内部使用复制方式进行初始化。 实现方法: 不提供set函数

    强不变模式: 在满足弱不变模式的情况下,类或方法在子类中不能修改,实现方法:函数为final或类为final

与其他模式关系:

    享元模式内部可以有变化,但和环境无关即可

策略模式

作用:

更换整个算法,改为其他方法来解决同样的问题。

模式将行为和环境分开。

应用场景:

    多个类的区别只是行为

    系统动态地在多个行为间进行选择

    策略使用的数据不需要让客户知道

角色:

    Strategy:行为类接口,规定API

    ConcreteStrategy:具体的行为类

    Context:环境部分,维持和查询行为类,有成员对象 strategy

注意:

    使用时,考察算法是否可从环境中分割,再考察算法如何变化 

    使用何种算法由Context决定

    如果一次使用多种策略,需要使用装饰模式

优缺点

    1.策略模式保证了采取哪种算法的逻辑和算法可以单独变化

    2.避免使用多重条件语句

和其他模式关系:

    创建模式:创建专注于创建,策略的使用更广一些

    享元模式:如果某些策略的区别只是客户状态 context不同,则可以将这些信息抽象出来由客户端注入,从而减少策略类

    模板方法:模板使用继承提供不同的算法行为,策略使用委派提供不同的算法行为

    装饰模式:是否增强功能, 当策略需要同时使用一个以上的算法时,可同时使用策略和装饰

模板方法

作用:

    父类指定处理的骨架,子类规定具体内容(抽象类与实现类)

角色:

    AbstractClass父类模板,骨架算法函数使用final修饰

    ConcreteClass子类的实现    

在重构中的应用

   big method:  extrract method; 将函数局部变量使用函数返回;将常量使用函数返回

观察者模式(发布和订阅模式)

作用:

    给类加入观察者后,当类的状态发生变化,就会通知观察者,在写一些和状态变化有关的处理时,很有用。

    观察者类似于事件中的发布订阅模式

角色:

    Subject:抽象类,表示被观察者,属性有List<Observer>,函数有增加和删除观察者,通知观察者方法 notify()。

    ConcreteSubject:表示实际的观察者,改变内部状态的方法 change。

    Observer:表示观察者,有方法update(Subject s)由subject.notify()调用。

    ConcreteObserver:表示实际的Observer。调用update方法,可获得ConcreteSubject的当前状态。

优缺点:

    1. 松散耦合

    2.广播通信

    1.观察者之间如果有循环调用,可能会系统崩溃

    2.观察者不知道Subject是怎么发生变化的

注意:

   使用 java.util 支持的观察者模式

Observer可以存在Subject,或者ConcreteSubject中,优先放在Subject中。

Java支持

java.util中提供了Observable(类似Subject)类和Observer接口, 实现时:

l  ConcreteSubject继承Observable类 ,状态变化时setChange()置位;调用notifyObservers 通知Observer;

l  ConcreteObserver实现Observer接口,定义update方法,第一个参数是ConcreteSubject

l  客户端:创建Observer和Observable对象;加入Observer:add(Observer);  改变Observable的状态(setChanged(),  notifyObservers() 两个都要调用)

l  有多个observer时,确保update方法调用顺序改变时也不会发生问题。

 

和其他模式关系:

    备忘录模式:subject将observer以备忘录模式存储在体内

 

应用实例:

Tomcat的声明周期管理,如下:

LifecycleListener 代表的是抽象观察者,它定义一个 lifecycleEvent 方法,这个方法就是当主题变化时要执行的 方法。

ServerLifecycleListener 代表的是具体的观察者,它实现了 LifecycleListener 接口的方法。

Lifecycle 接口代表的是抽象主题,它定义了管理观察者的方法和它要所做的其它方法。StandardServer代表的是具体主题,它实现了抽象主题的所有方法。

这里 Tomcat 对观察者做了扩展,增加了另外两个类:LifecycleSupport、LifecycleEvent,它们作为辅助类扩展了观察者的功能。

LifecycleEvent 使得可以定义事件类别,不同的事件可区别处理,更加灵活。

LifecycleSupport 类代理了主题对 多观察者的管理,将这个管理抽出来统一实现,以后如果修改只要修改LifecycleSupport 类就可以了,不需要去修改所有具体主题,因为 所有具体主题的对观察者的操作都被代理给 LifecycleSupport 类了。这可以认为是观察者模式的改进版。

迭代器

作用:

    将iterator和Aggregate分开,使得iterator和Aggregate分开变化。比如以前用数组实现,现在改成列表,则用iterator的遍历不用做任何修改

角色:

    Iterator:定义遍历元素的接口。定义next()和hasNext()方法

    ConcreteIterator:实现iterator所定义的接口,一种是包括ConcreteAggregator对象,另一种是作为ConcreteAggregate的成员类

    Aggregate:要访问的集合,定义了iterator()方法 

    ConcreteAggregate:实现了Aggregate接口,

宽接口和窄接口

宽接口支持修改,窄接口只能访问

ConcreteAggregate为客户端提供窄接口,为ConcreteIterator提供宽接口

    实现双重接口的方法:将ConcreteIterator作为ConcreteAggregate的内部成员类

模式的实现:

    ConcreteIterator 为单独类:可以被不同的对象共同控制

    ConcreteIterator 为成员类:不破坏对聚集的封装

优缺点:

    1.一个聚集上可以定义多个Iterator

    2.Iterator返回的对象无类型特征(1.5以上可通过泛型支持)

1.Iterator给人一种顺序化的错觉,客户端如果依赖顺序会出错

和其他模式关系:

    合成模式:迭代子遍历树结构

    命令模式:命令维护历史清单聚集,并使用迭代子遍历历史清单元素

    工厂模式:聚集角色提供一工厂方法,向外界提供自己的迭代子对象,如 iterator()

说明:

    遍历功能的进一步扩展,如Predicate,Closure等。

java集合

   Collection  代表聚集;

    List  表示聚集有顺序,所以 get(inex) 在中间增加和删除用户

   Set  元素必须唯一

   Map 

   Iterator 对象通过 Collection.iterator() 得到,还有remove()方法

   ListIterator 通过 List.listIterator() 得到,支持正向和逆向迭代,set,add(当前的后边)和remove

   Collection List   Iterator和ListIterator 四个很好地阐述了迭代子模式,使用内部成员类实现

责任链模式

作用:

由多个对象构成链,客户端发出请求时,该请求在链上传递,如果当前对象不能处理继续传递给下一个。

请求端(客户端)并不知道哪一个处理端完成处理。

角色:

    Handler:处理端的抽象类,包含函数setSuccesor,handle, 属性 Handler succesor

    ConcreteHandler:具体处理类,实现handl函数

    Client: 定义多个handler,完成责任链的组装,调用handler1.handle();

注意:

    如果是线性单一处理就是责任链模式,如果是线性多个处理就是装饰器模式,如果是单一处理就是策略模式。

    使用spring可以更简单的实现,只要在新增加一个HandlerManager类,在其中实现具体的处理逻辑如线性单一,线性多个,单一处理就可以了。

    命令只能传给一个处理器

    责任链可以是线、树(合成模式),环(next()不为空)

使用场景:

    系统有处理者对象组成的链,可能有合成模式构成

    多于一个处理器对象,而且哪个处理器完成处理动态确定的

    请求者不明确指定那个处理器处理

    处理者对象的链是动态指定的

案例:

   是 Tomcat 中 Container 设计的基础,整个容器的就是通过一 个链连接在一起,,从Engine 到 Host 再到 Context 一直到 Wrapper 都是通过一个链传递请求,这个链一直将请求正确的传递给最终处理请求的那个 Servlet。

    击鼓传花: 击鼓者是Client,传花者是Handler,具体的人是ConcreteHandler, 花是传递的具体数据

和其他模式关系

    合成模式:完成处理者的组成

命令模式

作用:

    产生请求时,根据请求创建对象实例,按照发生顺序排入等候序列中。接着,根据顺序执行相应的command。

可以将command对象保存起来,下次使用

多个command组成一个新的command(宏命令)

   

应用场合;

   callBack的实现,将invoker传入comand中,command的执行完成回调

    接收端可以否决请求或者记录日志,方便后期恢复

    较容易设计一命令队列,对请求排队

    命令的undo和redo: 需要保存动作(命令)和状态

角色:

    Command:命令的interface,方法 execute()

    ConcreteCommand:具体的命令,可以是宏命令和一般命令,调用receiver.action()方法

    Receiver:接受者,具体执行请求

    Client:产生ConcreteCommand和Receiver、Invoker对象,并进行组装; 调用invoker.action() 启动执行。Client知道执行什么(ConcreteCommand)和谁(Receiver)来执行,由谁(Invoker)跟进

    Invoker:请求者,调用command.execute()执行请求。

优缺点:

   invoker 和 receiver 分开,请求方不知道接收方的接口,更不知道数据如何接受,操作是否完成

    非常容易加入新的命令

    可能会导致过多的ConcreteCommand类

注意:

    宏命令: 将多个命令一次执行: 使用合成模式处理 Command

    支持undo和redo:Command提供 unExecute方法可以恢复操作的效果;Receiver保存最初状态数据,并提供方法可以返回到最初状态

    如果只是一层的undo和redo,只要存储最后执行的命令。如果是多层的undo和redo,需要存储曾经被执行过的命令清单。

案例:

tomcat:

    Connector作为抽象请求者

    HttpConnector作为具体请求者。

    HttpProcessor作为命令。

    Container作为命令的抽象接受者, ContainerBase 作为具体的接受者。

    应用服务器 Server 作为Client。

    Server首先创建命令请求者 HttpConnector 对象,然后创建命令 HttpProcessor对象。再把命令对象交给命令接受者 ContainerBase 容器来处理命令。命令的最终是被 Tomcat 的 Container 执行的。命令可以以队列的方式进来,Container 也可以以不同的方式来处理请求,如 HTTP1.0 协议和 HTTP1.1 的处理方式就会不同。

西游记:

    圣旨是Command,定义执行接口;

    宣孙悟空上天的圣旨是ConcreteCommand;

    玉皇大帝是client: 创建具体的圣旨和谁来执行, 委托太白金星执行

    太白金星是Invoker

    孙悟空是 Receiver:完成具体的执行

其他模式关系:

    合成模式: 构造宏命令

    备忘录模式:redo和undo功能中,备忘录模式存储命令的执行效果状态

    原始模式:命令类带有clone的话,可以复制

备忘录模式(Memento)

作用:

    不破坏封装前提下,捕捉对象状态,并外部存储。

    可利用该模式,执行以下操作:undo  redo   history(产生操作记录)  snapshot(存储当前状态),使用数组存储多个状态。

    常与命令模式和迭代模式一起使用。

角色:

    Originator:方法 Memento store() 创建Memento,并使用其保存对象状态,load(Memento) 恢复以前状态。

   Memento:Originator要保存的内部信息。Memento有俩种接口:wideinterface供Originator使用,提供存取的所有方法。Narrow interface供包外的相关类使用。

    Caretaker:函数 save(Memento) 保存对象,只能使用Memento的“狭义接口”。

   Client:决定保存、复原和做快照的时间点。创建Originator和Caretaker对象,调用Originator.store()产生Memento,并传递给Caretaker。

变种:

   CareTaker增强:可以将创建Originator和调用save方法移入 CareTaker中

    将 Caretaker和Originator的角色合并

注意:

    多检查点的实现:Caretaker持有map,每个entry为<checkpoint,Memento>,Client传入要返回到的checkpoint

    双重接口的实现(以Originator Mentento  MententoNarrow Caretaker 为例):

       class Originator {

              //  作为Originator的内部类实现宽接口

               private class Memento implements MementoNarrow {

                       //除了 MementoNarrow定义的函数,其他都为静态

               }

               // 外部只能通过这个函数访问

               public MementoNarrow  store() {

                    return new Memento();

               }

        }

备忘录模式操作步骤:

    1. Originator 创建一个Memento

    2. Originator 执行一个可撤销的操作(多是对自己状态的改变)

    3. 如果要撤销,通过 Originator.load(Memento) 撤销改变

假如模式操作步骤:

    当恢复Originator比较复杂时使用,可保证Originator永远有效;缺点是操作执行两次,如果拷贝和源对象共享数据就麻烦了。

    1.创建Originator的一个拷贝

    2.在拷贝上执行某个操作

    3.检查拷贝状态是否合法,正确就在Originator上执行,错误则丢弃并抛出异常

和其他模式关系

    命令模式:如果命令需要撤销,则命令使用备忘录存储可撤销操作的状态

    原始模式:使用原始进行备忘录的创建

优缺点:

    1. 简化了Originator类

    1.  如果Originator所有信息都要保存,Memento类会比较昂贵

    2.Caretaker 保存Memento时,并不知道该对象占用多少存储空间

 

状态模式

作用:

    对象在不同的状态下有不同的行为。

应用场合:

    多个方法写同样的条件判断

扩展新的状态不影响已有类

角色:

   State:表示状态的interface,规定行为 method。

   ConcreteState:实现类,对应一种状态,该状态下的属性和行为

    Context:定义客户端感兴趣的接口,具体实现委派给持有的ConcreteState实例,调用其函数。

注意:

    具体的状态类使用了单例模型

    状态的转换可以由Client Context 和State实现,如果转换条件固定,可使用Context;State子类决定就更有灵活性。

    状态对象的创建和销毁: 状态变化频繁,创建成本高时(预先创建);不频繁变更(使用时创建)

   可以使用状态图描述对象系统:画出对象的状态图;有几种状态;每种状态下完成的工作(状态和行为组成二维图形)

优缺点:    

    1。需要为每种状态创建一个ConcreteState,可能会造成类过多

    1. 减少大量的判断语句

与其他模式关系:

    享元模式:保存状态间公共属性

    单例模式:状态唯一 

    策略模式: 看Context是否有状态切换,在策略模式中,Context的整个生命周期内Strategy不会变化,而状态模式中不同的状态会使用;

访问者模式

作用:

    把聚集和处理俩者分开,一个变化不会影响另一个

    聚集中元素类型复杂(树形),不同类型有特定的操作(处理细节和元素类型相关,有多个if)

不当应用场合:

    1. Node体系频繁发生变化:比如需要实现新的Node子类时,需要在每一个Visitor中加入相应方法。

应用场合:

    1.比较稳定的数据结构和 易于变化的算法

角色:

    Visitor:接口,声明对元素的访问方法 visit(Node n)

    ConcreteVisitor:实现类

    Node:聚集中的元素,具有 boolean accept(Visitor v)  返回值表明是否接受visitor的访问

    ConcreteNode:实现了accept 方法

    ObjectStructrue:包含ConcreteNode的聚集,提供遍历方法。

双重委派:

     动态地根据函数所属类和参数选择正确的函数:实现方法:1. 使用 instanceof 对参数 obj类型做判断。 2. 返还球:调用传入参数obj.fun()第二次动态分派 

     单个元素处理时的双重委派: 

            NodeA.accept(Visitor v) 中调用VisitorA.visitA(this) , 再调用 NodeA.operationA() 完成(重构的时候可能会出现,否则谁第一次会想这么复杂,而且我觉得不需要设计这么负责,可以根据实际情况简化)。

    

优缺点:

    1.在Node体系中加入新操作比较容易

    2.将多个Node都有的行为集中到Visitor中,而不是分散到各个Node类中

  

    1. 增加新的节点类型比较困难

    2. 破坏Node的封装,从而访问者模式是一个有争议的模式 

与其他模式关系:

    迭代子模式: 针对不同元素类是否行为不同

解释器模式

作用:

    使用“迷你”语言描述问题,使用“解释器模式”编译成JAVA程序,当程序发生变化时,只需要修改“迷你”语言。如:海龟图的例子。

应用场合:

    重复发生的问题可以用这种简单语言表示

   效率不是问题

角色:

    抽象表达式:接口定义intercept() 该函数对表达式进行解析

    终结表达式:实现抽象表达式,不包含其他表达式。如 NUM1+NUM2 中的NUM2,intercept()只需要对自身解析

    非终结表达式:实现抽象表达式,本身包含其他的 表达式,如上面的 +,intercept()递归调用

    客户端:构造抽象语法树(AST,表达式),调用Intercept函数

   Context:提供map完成表达式和真实量值的转换,如NUM1 为124;

和其他模式的关系:

    合成模式: 抽象语法树(AST)的表达式就构成一个合成模式(抽象表达式,非终结表达式为树枝,终结表达式为树叶)

    不变模式:某些表达式可以设计为不变模式

    访问者模式:如果将AST节点中的共有操作放在visitor中

中介者模式

作用:

    对对象间的调用进行管理

    多个成员中引入经理,彼此之间的交互转变为和经理的交互。

角色:

    Mediator:定义同事到Mediator的interface,声明一个或多个事件方法change(Colleague c)。

    ConcreteMediator:持有所有的ConcreteColleague对象,实现change,从ConcreteCollegue接收消息,向相应的Colleague发成命令

    Colleague:定义Mediator到同事的interface,持有Mediator对象

    ConcreteColleague:

特点:

    部分交互关系变化不会影响到其他成员

    容易实现colleague的扩展,而mediator的扩展不太容易 

   Colleague作为参量传递到Mediator的事件方法; Mediator在Colleague中是实例变量   

优缺点:

    1. 将对象在小尺度的行为和与其他对象的协作分开

    2. 减少继承的出现

    1.同事类的复用是以 Mediator的不可复用为代价的

应用场景:

    1.对象责任划分混乱时,应当进行重构而不是使用中介者模式

    2.中介者模式是对协作进行封装,不要认为割裂纯数据类和纯行为类

其他模式关系

    1.适配器模式: Mediator ConcreteMediator和Colleague构成一适配器

    2.门面模式:两者都是简化调用,门面是外对内单向的,中介者是双向的

    3.观察者模式:两者是二选一,观察者通过引入主题和观察者解耦协作;中介者引入中介解耦协作。中介者不适于设计一个大型系统的事件处理机制,建议使用观察者,毕竟java支持了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值