设计模式
一、设计模式的概念和分类
1.1 设计模式介绍
- 设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通用解决方案,设计模式(Design pattern)代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
- 设计模式的本质提高 软件的维护性,通用性和扩展性,并降低软件的复杂度。
- 《设计模式》是经典的书,作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗称 “四人组 GOF”)
- 设计模式并不局限于某种语言,java,php,c++ 都有设计模式.
1.2 设计模式类型
设计模式分为三种类型,共23种
-
创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。 -
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 -
行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)。
注意:不同的书籍上对分类和名称略有差别
1.2.1 创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
1.2.2 结构型模式
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
1.2.3 行为型模式
这些设计模式特别关注对象之间的通信。
1.3 设计模式的七大原则
是设计模式为什么这样设计的依据
设计模式常用的七大原则有:
- 单一职责原则
- 接口隔离原则
- 一个类对另一个类的依赖应该建立在最小的接口上
- 使用多个隔离的接口,比使用单个接口要好
- 依赖倒转(倒置)原则
- 开闭原则的基础,依赖倒转(倒置)的中心思想是面向接口编程,依赖于抽象而不依赖于具体
- 里氏替换原则
- 对开闭原则的补充
- 如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象。
- 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
- 里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖 来解决问题。.
- 开闭原则
- 对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果
- 迪米特法则
- 一个对象应该对其他对象保持最少的了解,一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public 方法,不对外泄露任何信息
- 迪米特法则还有个更简单的定义:只与直接的朋友通信
- 直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。
- 合成复用原则
详细说明
设计模式:设计模式的七大原则
二、创建型
2.1 单例模式(Singleton)
- 简单介绍
- 保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
- 主要解决
- 何时使用
- 关键代码
- 类图
SingleObject 类有它的私有构造函数和本身的一个静态实例。并提供了一个静态方法,供外界获取它的静态实例。SingletonPatternDemo 类使用 SingleObject 类来获取 SingleObject 对象。
设计模式:单例模式
2.2 工厂模式(Factory)
设计模式:工厂模式
2.3 原型模式(Prototype)
- 简单介绍
- 用于创建重复的对象,同时又能保证性能。
- 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
- 主要解决
- 何时使用
- 当一个系统应该独立于它的产品创建,构成和表示时。
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
- 关键代码
- 类图
我们将创建一个抽象类 Shape 和扩展了 Shape 类的实体类。下一步是定义类 ShapeCache,该类把 shape 对象存储在一个 Hashtable 中,并在请求的时候返回它们的克隆。
PrototypePatternDemo 类使用 ShapeCache 类来获取 Shape 对象。
设计模式:原型模式
2.4 建造者模式(Builder)
- 简单介绍
- 使用多个简单的对象一步一步构建成一个复杂的对象。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
- 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
- 主要解决
- 主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
- 何时使用
- 关键代码
- 建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
- 类图
我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。
然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。BuilderPatternDemo 类使用 MealBuilder 来创建一个 Meal。
设计模式:建造者模式
三、结构型
3.1 适配器模式(Adapter)
- 简单介绍
- 是作为两个不兼容的接口之间的桥梁,将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 主要解决
- 主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
- 何时使用
- 系统需要使用现有的类,而此类的接口不符合系统的需要。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
- 通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
- 关键代码
- 类图
我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。
我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。
AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。AdapterPatternDemo 类使用 AudioPlayer 类来播放各种格式。
设计模式:设配器模式
3.2 桥接模式(Bridge)
- 简单介绍
- 用于把抽象化与实现化解耦,使得二者可以独立变化。
- **抽象化:**其概念是将复杂物体的一个或几个特性抽出去而只注意其他特性的行动或过程。在面向对象就是将对象共同的性质抽取出去而形成类的过程。
- 实现化:针对抽象化给出的具体实现。它和抽象化是一个互逆的过程,实现化是对抽象化事物的进一步具体化。
- 主要解决
- 在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
- 何时使用
- 实现系统可能有多个角度分类,每一种角度都可能变化。
- 替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本
- 关键代码
- 类图
我们有一个作为桥接实现的 DrawAPI 接口和实现了 DrawAPI 接口的实体类 RedCircle、GreenCircle。Shape 是一个抽象类,将使用 DrawAPI 的对象。BridgePatternDemo 类使用 Shape 类来画出不同颜色的圆。
设计模式:桥接模式
3.3 装饰模式(Decorator)
- 简单介绍
- 允许向一个现有的对象添加新的功能,同时又不改变其结构。
- 主要解决
- 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
- 何时使用
- 关键代码
- Component 类充当抽象角色,不应该具体实现。
- 修饰类引用(聚合)和继承 Component 类,具体扩展类重写父类方法。
- 类图
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape对象作为它的实例变量。
RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。
设计模式:装饰者模式
3.4 组合模式(Composite)
- 简单介绍
- 部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
- 将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 主要解决
- 它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
- 何时使用
- 您想表示对象的部分-整体层次结构(树形结构)。
- 您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
- 关键代码
- 非叶子节点树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
- 类图
设计模式:组合模式
3.5 外观模式(Facade)
- 简单介绍
- 隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。
- 为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 主要解决
- 降低访问复杂系统的内部子系统时的复杂度,简化客户端之间的接口。
- 何时使用
- 客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。
- 定义系统的入口。
- 关键代码
- 在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。
- 类图
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。
ShapeMaker 类使用实体类来代表用户对这些类的调用。FacadePatternDemo 类使用 ShapeMaker 类来显示结果。
设计模式:外观模式
3.6 享元模式(Flyweight)
- 简单介绍
- 主要用于减少创建对象的数量,以减少内存占用和提高性能。尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
- 运用共享技术有效地支持大量细粒度的对象。
- 主要解决
- 在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
- 何时使用
- 系统中有大量对象。
- 这些对象消耗大量内存。
- 这些对象的状态大部分可以外部化。
- 这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
- 系统不依赖于这些对象身份,这些对象是不可分辨的。
- 关键代码
- 类图
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory。
ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。
FlyWeightPatternDemo 类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。
设计模式:享元模式
3.7 代理模式
- 简单介绍
- 一个类代表另一个类的功能,创建具有现有对象的对象,以便向外界提供功能接口。
- 为其他对象提供一种代理以控制对这个对象的访问。
- 主要解决
- 在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
- 何时使用
- 关键代码
- 类图
我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。
ProxyPatternDemo 类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。
设计模式:代理模式(Proxy)
四、行为型
4.1 模版方法模式(Template)
- 简单介绍
- 一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
- 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
- 主要解决
- 何时使用
- 关键代码
- 类图
我们将创建一个定义操作的 Game 抽象类,其中,模板方法设置为 final,这样它就不会被重写。Cricket 和 Football 是扩展了 Game 的实体类,它们重写了抽象类的方法。
TemplatePatternDemo,我们的演示类使用 Game 来演示模板模式的用法。
设计模式:模板方法模式
4.2 命令模式(Command)
- 简单介绍
- 是一种数据驱动的设计模式
- 请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令
- 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化
- 主要解决
- 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
- 何时使用
- 在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
- 关键代码
- 定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
- 类图
Invoker 是调用者角色 Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类 Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作 ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现execute
设计模式:命令模式
4.3 访问者模式(Visitor)
- 简单介绍
- 使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
- 主要解决
- 何时使用
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
- 关键代码
- 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
- 类图
我们将创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。
VisitorPatternDemo,我们的演示类使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。
设计模式:访问者模式
4.4 迭代器模式
- 简单介绍
- 用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
- 提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
- 主要解决
- 何时使用
- 关键代码
- 类图
我们将创建一个叙述导航方法的 Iterator 接口和一个返回迭代器的 Container 接口。实现了 Container 接口的实体类将负责实现 Iterator 接口。
IteratorPatternDemo,我们的演示类使用实体类 NamesRepository 来打印 NamesRepository 中存储为集合的 Names。
设计模式:迭代器模式
4.5 观察者模式(Observer)
- 简单介绍
- 当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。
- 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 主要解决
- 一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
- 何时使用
- 一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
- 关键代码
- 在抽象类里有一个 ArrayList 存放观察者们。
- 类图
观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。
ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式。
设计模式:观察者模式
4.6 中介者模式
- 简单介绍
- 是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。
- 用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- 主要解决
- 对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
- 何时使用
- 关键代码
- 对象 Colleague 之间的通信封装到一个类中单独处理。
- 类图
设计模式:中介者模式
4.7 备忘录模式(Memento)
- 简单介绍
- 保存一个对象的某个状态,以便在适当的时候恢复对象。
- 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
- 主要解决
- 所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
- 何时使用
- 很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
- 关键代码
- 类图
备忘录模式使用三个类 Memento、Originator 和 CareTaker。Memento 包含了要被恢复的对象的状态。Originator 创建并在 Memento 对象中存储状态。Caretaker 对象负责从 Memento 中恢复对象的状态。
MementoPatternDemo,我们的演示类使用 CareTaker 和 Originator 对象来显示对象的状态恢复。
设计模式:备忘录模式
4.8 解释器模式(Interpreter)
- 简单介绍
- 提供了评估语言的语法或表达式的方式,实现了一个表达式接口,该接口解释一个特定的上下文。
- 给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
- 主要解决
- 何时使用
- 如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
- 关键代码
- 构建环境类,包含解释器之外的一些全局信息,一般是 HashMap。
- 类图
Context: 是环境角色,含有解释器之外的全局信息. AbstractExpression: 抽象表达式, 声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享 TerminalExpression: 为终结符表达式, 实现与文法中的终结符相关的解释操作 NonTermialExpression: 为非终结符表达式,为文法中的非终结符实现解释操作. 说明: 输入 Context 和 TerminalExpression 信息通过 Client 输入即可
设计模式:解释器模式
4.9 状态模式(State)
- 简单介绍
- 类的行为是基于它的状态改变的。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
- 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
- 主要解决
- 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
- 何时使用
- 关键代码
- 通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。
- 类图
我们将创建一个 State 接口和实现了 State 接口的实体状态类。Context 是一个带有某个状态(当前状态)的类。
StatePatternDemo,我们的演示类使用 Context 和状态对象来演示 Context 在状态改变时的行为变化。
设计模式:状态模式
4.10 策略模式(Strategy)
- 简单介绍
- 一个类的行为或其算法可以在运行时更改。
- 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
- 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
- 主要解决
- 在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
- 何时使用
- 一个系统有许多许多类,而区分它们的只是他们直接的行为。
- 关键代码
- 同一个算法和行为实现同一个接口(策略)。Context聚合相关策略
- 类图
我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。
StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。
设计模式:策略模式
4.11 职责链模式(责任链模式)
- 简单介绍
- 为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。
- 通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
- 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
- 主要解决
- 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
- 何时使用
- 关键代码
- Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
- 类图
我们创建抽象类 AbstractLogger,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。
设计模式:职责链模式
设计模式之间的关系
小结:
- 设计模式是程序员在编程中,有意或者是无意使用到的(也不是所有的程序员都学习过设计模式),并且同一种设计模式实现方式也不是100%的一样,设计模式主要是提高程序的扩展性,可读性,可维护性、规范性。
- 所以在我们讲某个设计模式在源码框架中使用时,和我们的标准的设计模式写法可能会有些出入,比如组合模式 Component 可以是抽象类,接口,也可以是一个实现类, 我们讲源码时(JDK HashMap源码),Component 就可能不一样? 设计模式在框架或项目中源码分析的说
- 对于框架源码,源码中部分使用了A设计模式,还部分使用了B设计模式,也是有可能的,也就是说设计模式是可以结合使用的
- 因为设计模式主要是一种编程思想,既然是思想,具体实现方式,就不可能100%的一样(当然,程序的设计结构基本是一样的)
- 学习设计模式时,主要是去了解使用这个设计模式到底带了了什么好处? 是扩展性提高了,还是更加规范了,这样我们才能领会设计模式的精妙之处。
参考:菜鸟教程
尚硅谷Java设计模式(图解+框架源码剖析)
|