责任链模式(Chain of Responsibility Pattern)

顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式.

介绍

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
何时使用:在处理消息的时候以过滤很多道
如何解决:拦截的类都实现统一接口
关键代码:Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去
应用实例: 1.JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter
优点: 1.降低耦合度。它将请求的发送者和接收者解耦 2.简化了对象。使得对象不需要知道链的结构
缺点: 1.不能保证请求一定被接收 2.系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用

实现

我们创建抽象类 AbstractLogger,带有详细的日志记录级别.然后我们创建三种类型的记录器,都扩展了 AbstractLogger.每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器
行为型模式 - 图1

命令模式(Command Pattern)

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调用对象.调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令

介绍

意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适
何时使用:在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合
如何解决:通过调用者调用接受者执行命令,顺序:调用者→命令→接受者
关键代码:定义三个角色:1.received 真正的命令执行对象 2.Command 3.invoker 使用命令对象的入口
应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command
优点: 1.降低了系统耦合度。 2.新的命令可以很容易添加到系统中去
缺点:使用命令模式可能会导致某些系统有过多的具体命令类
行为型模式 - 图2

实现

我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类.实体命令类 BuyStockSellStock,实现了 Order 接口,将执行实际的命令处理.创建作为调用对象的类 Broker,它接受订单并能下订单
Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令.CommandPatternDemo 类使用 Broker 类来演示命令模式
行为型模式 - 图3

解释器模式(Interpreter Pattern)

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式.这种模式实现了一个表达式接口,该接口解释一个特定的上下文.这种模式被用在 SQL 解析、符号处理引擎等

介绍

意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子
主要解决:对于一些固定文法构建一个解释句子的解释器
何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子.这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题
如何解决:构建语法树,定义终结符与非终结符
关键代码:构建环境类,包含解释器之外的一些全局信息,一般是 HashMap
应用实例:编译器、运算表达式计算
优点: 1.可扩展性比较好,灵活. 2.增加了新的解释表达式的方式
缺点: 1.可利用场景比较少. 2.对于复杂的文法比较难维护

实现

我们将创建一个接口 Expression 和实现了 Expression 接口的实体类.定义作为上下文中主要解释器的 TerminalExpression
其他的类 OrExpressionAndExpression 用于创建组合式表达式
InterpreterPatternDemo,我们的演示类使用 Expression 类创建规则和演示表达式的解析
行为型模式 - 图4

迭代器模式(Iterator Pattern)

迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式.这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示

介绍

意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示
主要解决:不同的方式来遍历整个整合对象
何时使用:遍历一个聚合对象
如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象
关键代码:定义接口:hasNext, next
应用实例:JAVA 中的 iterator
优点: 1.它支持以不同的方式遍历一个聚合对象
缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性

实现

我们将创建一个叙述导航方法的 Iterator 接口和一个返回迭代器的 Container 接口.实现了 Container 接口的实体类将负责实现 Iterator 接口
IteratorPatternDemo,我们的演示类使用实体类 NamesRepository 来打印 NamesRepository 中存储为集合的 Names
行为型模式 - 图5

中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性,这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行为型模式

介绍

意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理
何时使用:多个类相互耦合,形成了网状结构
如何解决:将上述网状结构分离为星型结构
关键代码:对象 Colleague 之间的通信封装到一个类中单独处理
应用实例: 1.MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者
优点:1.降低了类的复杂度,将一对多转化成了一对一
缺点:中介者会庞大,变得复杂难以维护

实现

我们通过聊天室实例来演示中介者模式.实例中,多个用户可以向聊天室发送消息,聊天室向所有的用户显示消息.我们将创建两个类 ChatRoomUser.User 对象使用 ChatRoom 方法来分享他们的消息
MediatorPatternDemo,我们的演示类使用 User 对象来显示他们之间的通信
行为型模式 - 图6

备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象

介绍

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态
何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有”后悔药”可吃
如何解决:通过一个备忘录类专门存储对象状态
关键代码:客户不与备忘录类耦合,与备忘录管理类耦合
应用实例: 1.Windows 里的 ctrl + z
优点: 1.给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态
缺点:消耗资源.如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存
使用场景: 1.需要保存/恢复数据的相关状态场景
注意事项:1.为了符合迪米特原则,还要增加一个管理备忘录的类

实现

备忘录模式使用三个类 MementoOriginatorCareTaker.Memento 包含了要被恢复的对象的状态.Originator 创建并在 Memento 对象中存储状态.Caretaker 对象负责从 Memento 中恢复对象的状态
MementoPatternDemo,我们的演示类使用 CareTakerOriginator 对象来显示对象的状态恢复
行为型模式 - 图7

观察者模式(Observer Pattern)

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)比如,当一个对象被修改时,则会自动通知依赖它的对象

介绍

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作
何时使用:一个对象的状态发生改变,所有的依赖对象都将得到通知,进行广播通知
如何解决:使用面向对象技术,可以将这种依赖关系弱化
关键代码:在抽象类里有一个 ArrayList 存放观察者们
应用实例: 1.拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价
优点:1.观察者和被观察者是抽象耦合的
缺点:1.如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间

实现

观察者模式使用三个类 Subject、Observer 和 Client.Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法
我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类
ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式.
行为型模式 - 图8

状态模式(State Pattern)

在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象

介绍

意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类
主要解决:对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为
何时使用:代码中包含大量与对象状态有关的条件语句
如何解决:将各种具体的状态类抽象出来
关键代码:通常命令模式的接口中只有一个方法.而状态模式的接口中有一个或者多个方法.而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值.也就是说,状态模式一般和对象的状态有关.实现类的方法有不同的功能,覆盖接口中的方法.状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句
应用实例: 1.打篮球的时候运动员可以有正常状态、不正常状态和超常状态
优点: 1.封装了转换规则
缺点: 1.状态模式的使用必然会增加系统类和对象的个数

实现

我们将创建一个 State 接口和实现了 State 接口的实体状态类.Context 是一个带有某个状态的类
StatePatternDemo,我们的演示类使用 Context 和状态对象来演示 Context 在状态改变时的行为变化
行为型模式 - 图9

策略模式(Strategy Pattern)

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

介绍

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

实现

我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。
StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。
行为型模式 - 图10

模板模式(Template Pattern)

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

介绍

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
何时使用:有一些通用的方法。
如何解决:将这些通用算法抽象出来。
关键代码:在抽象类实现,其他步骤在子类实现。
应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

实现

我们将创建一个定义操作的 Game 抽象类,其中,模板方法设置为 final,这样它就不会被重写。CricketFootball 是扩展了 Game 的实体类,它们重写了抽象类的方法。
TemplatePatternDemo,我们的演示类使用 Game 来演示模板模式的用法。
行为型模式 - 图11

访问者模式(Visitor Pattern)

在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

介绍

意图:主要将数据结构与数据操作分离。
主要解决:稳定的数据结构和易变的操作耦合问题。
何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,使用访问者模式将这些封装到类中。
如何解决:在被访问的类里面加一个对外提供接待访问者的接口。
关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

实现

我们将创建一个定义接受操作的 ComputerPart 接口。KeyboardMouseMonitorComputer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。
VisitorPatternDemo,我们的演示类使用 ComputerComputerPartVisitor 类来演示访问者模式的用法。
行为型模式 - 图12