设计模式:总结

创建型模式

创建型模式抽象了实例化过程。它们帮助一个系统独立于如何创建、组合和表示它的那些对象。一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象。

随着系统演化得越来越依赖于对象复合而不是类继承,创建型模式变得更为重要。当这种情况发生时,重心从对一组固定行为的硬编码(hard-coding)转移为定义一个较小的基本行为集,这些行为可以被组合成任意数目的更复杂的行为。这样创建有特定行为的对象要求的不仅仅是实例化一个类。

在这些模式中有两个不断出现的主旋律。第一,它们都将关于该系统使用哪些具体的类的信息封装起来。第二,它们隐藏了这些类的实例是如何被创建和放在一起的。整个系统关于这些对象所知道的是由抽象类所定义的接口。因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以及何时创建这些方面给予你很大的灵活性。它们允许你用结构和功能差别很大的“产品”对象配置一个系统。配置可以是静态的(即在编译时指定),也可以是动态的(在运行时)。

抽象工厂模式

意图

提供创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

适用性

  • 一个系统要独立于它的产品的创建、组合和表示时。
  • 一个系统要由多个产品系列中的一个来配置时。
  • 当你要强调一系列相关产品对象的设计以便进行联合使用时。
  • 当你提供一个产品类库,而只想显示它们的接口而不是实现时。

结构

在这里插入图片描述

参与者

  • AbstractFactory
    • 声明一个创建抽象产品的操作接口。
  • ConcreteFactory
    • 实现创建具体产品对象的操作。
  • AbstractProduct
    • 为一类产品对象声明一个接口。
  • ConcreteProduct
    • 定义一个将被相应的具体工厂创建的产品对象。
    • 实现 AbstractProduct 接口。
  • Client
    • 仅使用由 AbstractFactory 和 AbstractProduct 类声明的接口。

协作

  • 通常在运行时刻创建一个 ConcreteFactory 类的实例。这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工厂。
  • AbstractFactory 将产品对象的创建延迟到它的 ConcreteFactory 子类。

效果

  1. 分离了具体的类。
  2. 易于交换产品系列。
  3. 有利于产品的一致性。
  4. 难以支持新种类的产品。

References:https://blog.csdn.net/qq_39384184/article/details/80316083

生成器模式

意图

将一个复杂对象的构件与它的表示分离,使得同样的构建过程可以创建不同的表示。

适用性

  • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  • 当构造过程必须允许被构造的对象有不同的表示时。

结构

在这里插入图片描述

参与者

  • Builder
    • 为创建一个 Product 对象的各个部件指定抽象接口。
  • ConcreteBuilder
    • 实现 Builder 的接口以构造和装配该产品的各个部件。
    • 定义并明确它所创建的表示。
    • 提供一个检索产品的接口(GetResult)。
  • Director
    • 构造一个使用 Builder 接口的对象。
  • Product
    • 表示被构造的复杂对象。ConcreteBuilder 创建该产品的内部表示并定义它的装配过程。
    • 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

协作

  • 客户创建 Builder 对象。
  • 客户创建 Director 对象,并用它所想要的 Builder 对象进行配置。
  • 一旦产品部件被生成,导向器就会通知生成器。
  • 生成器处理导向器的请求,并将部件添加到该产品中。
  • 客户从生成器中检索产品。

效果

  1. 使你可以改变一个产品的内部表示。
  2. 将构造代码和表示代码分开。
  3. 使你可以对构造过程进行更精细的控制。

References:https://blog.csdn.net/qq_39384184/article/details/80315826

工厂方法模式

意图

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

适用性

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且希望你将哪一个帮助子类是代理者这一信息局部化的时候。

结构

在这里插入图片描述

参与者

  • Product
    • 定义工厂方法所创建的对象的接口。
  • ConcreteProduct
    • 实现 Product 接口。
  • Creator
    • 声明工厂方法,该方法返回一个 Product 类型的对象。Creator 也可以定义一个工厂方法的缺省实现,它返回一个缺省的 ConcreteProduct 对象。
    • 可以调用工厂方法以创建一个 Product 对象。
  • ConcreteCreator
    • 重定义工厂方法以返回一个 ConcreteProduct 实例。

协作

  • Creator 依赖于它的子类来定义工厂方法,所以它返回一个适当的 ConcreteProduct 实例。

效果

  1. 不再将于特定应用有关的类绑定到代码中。
  2. 仅仅为了创建一个特定的 ConcreteProduct 对象, 就不得不创建 Creator 的子类。
  3. 为子类提供挂钩。
  4. 连接平行的类层次。

References:https://blog.csdn.net/qq_39384184/article/details/80009673

原型模式

意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

适用性

  • 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
  • 为了避免创建一个与产品类层次平行的工厂类层次时。
  • 当一个类的实例只能有几个不同状态组合中的一种时,建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

结构

在这里插入图片描述

参与者

  • Prototype
    • 声明一个克隆自身的接口。
  • ConcretePrototype
    • 实现一个克隆自身的操作。
  • Client
    • 让一个原型克隆自身从而创建一个新的对象。

协作

  • 客户请求一个原型克隆自身。

效果

  • 运行时刻增加和删除产品。
  • 改变值以指定新对象。
  • 改变结构以指定新对象。
  • 减少子类的构造。
  • 用类动态配置应用。
  • 每一个 Prototype 的子类都必须实现 Clone 操作,这可能很困难。

References:https://blog.csdn.net/qq_39384184/article/details/80080420

单件模式

意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性

  • 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
  • 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

结构

在这里插入图片描述

参与者

  • Singleton
    • 定义一个 Instance 操作,允许客户访问它的唯一实例。Instance 是一个类操作。
    • 可能负责创建它自己的唯一实例。

协作

  • 客户只能通过 Singleton 的 Instance 操作访问一个 Singleton 的实例。

效果

  1. 对唯一实例的受控访问。
  2. 缩小名空间。
  3. 允许对操作和表示的精化。
  4. 允许可变数目的实例。
  5. 比类操作更灵活。

References:https://blog.csdn.net/qq_39384184/article/details/80213287

创建型模式的讨论

用一个系统创建的那些对象的类对系统进行参数化有两种常用方法:

  • 一种是生成创建对象的类的子类:
    • 这对应于使用FactoryMethod模式。
    • 这种方法的主要缺点是,仅为了改变产品类,就可能需要创建一个新的子类。这样的改变可能是级联的(cascade)。例如,如果产品的创建者本身是由一个工厂方法创建的,那么你也必须重定义它的创建者。
  • 另一种对系统进行参数化的方法更多的依赖于对象复合:
    • 定义一个对象负责明确产品对象的类,并将它作为该系统的参数。
    • 这是AbstractFactory、Builder和Prototype模式的关键特征。
    • 所有这三个模式都涉及到创建一个新的负责创建产品对象的“工厂对象”。
    • AbstractFactory由这个工厂对象产生多个类的对象。
    • Builder由这个工厂对象使用一个相对复杂的协议,逐步创建一个复杂产品。
    • Prototype由该工厂对象通过拷贝原型对象来创建产品对象。在这种情况下,因为原型负责返回产品对象,所以工厂对象和原型是同一个对象。

考虑在Prototype模式中描述的绘图编辑器框架。可以有多种方法通过产品类来参数化GraphicTool:

  • 使用FactoryMethod模式,将为选择板中的每个Graphic的子类创建一个GraphicTool的子类。GraphicTool将有一个NewGraphic操作,每个GraphicTool的子类都会重定义它。
  • 使用AbstractFactory模式,将有一个GraphicsFactory类层次对应于每个Graphic的子类。在这种情况每个工厂仅创建一个产品:CircleFactory将创建Circle,LineFactory将创建Line,等等。GraphicTool将以创建合适种类Graphic的工厂作为参数。
  • 使用Prototype模式,每个Graphic的子类将实现Clone操作,并且GraphicTool将以它所创建的Graphic的原型作为参数。

究竟哪一种模式最好取决于诸多因素。在我们的绘图编辑器框架中,第一眼看来,Factory Method模式使用是最简单的。它易于定义一个新的GraphicTool的子类,并且仅当选择板被定义了的时候,GraphicToo的实例才被创建。它的主要缺点在于GraphicTool子类数目的激增,并且它们都没有做很多事情。

AbstractFactory并没有很大的改进,因为它需要一个同样庞大的GraphicsFactory类层次。只有当早已存在一个GraphicsFactory类层次时,AbstractFactory才比FactoryMethod更好一点。或是因为编译器自动提供或是因为系统的其他部分需要这个GraphicsFactory类层次。

总的来说,Prototype模式对绘图编辑器框架可能是最好的,因为它仅需要为每个Graphics类实现一个Clone操作。这就减少了类的数目,并且Clone可以用于其他目的而不仅仅是纯粹的实例化。

Factory Method使一个设计可以定制且只略微有一些复杂。其他设计模式需要新的类,而Factory Method只需要一个新的操作。使用AbstractFactory、Prototype或Builder的设计甚至比使用FactoryMethod的那些设计更灵活,但它们也更加复杂。通常,设计以使用FactoryMethod开始,并且当设计者发现需要更大的灵活性时,设计便会向其他创建型模式演化。


结构型模式

结构型模式涉及到如何组合类和对象以获得更大的结构。结构型类模式采用继承机制来组合接口或实现。一个简单的例子是采用多重继承方法将两个以上的类组合成一个类,结果这个类包含了所有父类的性质。这一模式尤其有助于多个独立开发的类库协同工作。另外一个例子是类形式的Adapter模式。一般来说,适配器使得一个接口(adaptee的接口)与其他接口兼容,从而给出了多个不同接口的统一抽象。为此,类适配器对一个adaptee类进行私有继承。这样,适配器就可以用adaptee的接口表示它的接口。

结构型对象模式不是对接口和实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法。因为可以在运行时刻改变对象组合关系,所以对象组合方式具有更大的灵活性,而这种机制用静态类组合是不可能实现的。

适配器模式

意图

将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适用性

  • 你想使用一个已经存在的类,而它的接口不符合你的需求。
  • 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
  • (仅适用于对象 Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。

结构

在这里插入图片描述

参与者

  • Target
    • 定义 Client 使用的与特定领域相关的接口。
  • Client
    • 与符合 Target 接口的对象协同。
  • Adaptee
    • 定义一个已经存在的接口,这个接口需要适配。
  • Adapter
    • 对 Adaptee 的接口与 Target 接口进行适配。

协作

  • Client 在 Adapter 实例上调用一些操作。接着适配器调用 Adaptee 的操作实现这个请求。

效果

  • 类适配器
    1. 用一个具体的Adapter类对Adaptee和Target进行匹配。结果是当我们想要匹配一个类以及所有它的子类时,类Adapter将不能胜任工作。
    2. 使得Adapter可以重定义Adaptee的部分行为,因为Adapter是Adaptee的一个子类。
    3. 仅仅引入了一个对象,并不需要额外的指针以间接得到adaptee。
  • 对象适配器
    1. 允许一个Adapter与多个Adaptee- 即Adaptee本身以及它的所有子类(如果有子类的话)同时工作。Adapter也可以一次给所有的Adaptee添加功能。
    2. 使得重定义Adaptee的行为比较困难。这就需要生成Adaptee的子类并且使得Adapter引用
      这个子类而不是引用Adaptee本身。

References:https://blog.csdn.net/qq_39384184/article/details/79998922

桥接模式

意图

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

适用性

  1. 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。
  2. 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。
  3. 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
  4. (C++)你想对客户完全隐藏抽象的实现部分。
  5. 有许多类要生成,这样一种类层次结构说明你必须将一个对象分解成两个部分。
  6. 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。

结构

在这里插入图片描述

参与者

  • Abstraction
    • 定义抽象类的接口。
    • 维护一个指向Implementor类型对象的指针。
  • RefinedAbstraction
    • 扩充由Abstraction定义的接口。
  • Implementor
    • 定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
  • ConcreteImplementor
    • 实现Implementor接口并定义它的具体实现。

协作

  • Abstraction将client的请求转发给它的Implementor对象。

效果

  1. 分离接口及其实现部分。
  2. 提高可扩充性你可以独立地对Abstraction和Implementor层次结构进行扩充。
  3. 实现细节对客户透明。

References:https://blog.csdn.net/qq_39384184/article/details/80316221

组合模式

意图

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

适用性

  • 你想表示对象的部分-整体层次结构。
  • 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

结构

在这里插入图片描述

参与者

  • Component
    • 为组合中的对象声明接口。
    • 在适当的情况下,实现所有类共有接口的缺省行为。
    • 声明一个接口用于访问和管理Component的子组件。
    • (可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
  • Leaf
    • 在组合中表示叶节点对象,叶节点没有子节点。
    • 在组合中定义图元对象的行为。
  • Composite
    • 定义有子部件的那些部件的行为。
    • 存储子部件。
    • 在Component接口中实现与子部件有关的操作。
  • Client
    • 通过Component接口操纵组合部件的对象。

协作

  • 用户使用Component类接口与组合结构中的对象进行交互。如果接收者是一个叶节点,则直接处理请求。如果接收者是Composite,它通常将请求发送给它的子部件,在转发请求之前与/或之后可能执行一些辅助操作。

效果

  1. 定义了包含基本对象和组合对象的类层次结构。
  2. 简化客户代码。
  3. 使得更容易增加新类型的组件。
  4. 使你的设计变得更加一般化。有时你希望一个组合只能有某些特定的组件。使用Composite时,你不能依赖类型系统施加这些约束,而必须在运行时刻进行检查。

References:https://blog.csdn.net/qq_39384184/article/details/80316407

装饰模式

意图

动态地给一个对象添加一些额外的职责。就增加功能来说,更为灵活。

适用性

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤消的职责。
  • 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

结构

在这里插入图片描述

参与者

  • Component
    • 定义一个对象接口,可以给这些对象动态地添加职责。
  • ConcreteComponent
    • 定义一个对象,可以给这个对象添加一些职责。
  • Decorator
    • 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
  • ConcreteDecorator
    • 向组件添加职责。

协作

  • Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。

效果

  1. 比静态继承更灵活。
  2. 避免在层次结构高层的类有太多的特征。
  3. Decorator与它的Component不一样。
  4. 有许多小对象。

References:https://blog.csdn.net/qq_39384184/article/details/80324493

外观模式

意图

  • 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

适用性

  • 当你要为一个复杂子系统提供一个简单接口时。
  • 客户程序与抽象类的实现部分之间存在着很大的依赖性。
  • 当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。

结构

在这里插入图片描述

参与者

  • Facade
    • 知道哪些子系统类负责处理请求。
    • 将客户的请求代理给适当的子系统对象。
  • SubsystemClasses
    • 实现子系统的功能。
    • 处理由Facade对象指派的任务。
    • 没有facade的任何相关信息,即没有指向facade的指针。

协作

  • 客户程序通过发送请求给Facade的方式与子系统通讯,Facade将这些消息转发给适当的子系统对象。尽管是子系统中的有关对象在做实际工作,但Facade模式本身也必须将它的接口转换成子系统的接口。
  • 使用Facade的客户程序不需要直接访问子系统对象。

效果

  1. 它对客户屏蔽子系统组件。
  2. 它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。
  3. 如果应用需要,它并不限制它们使用子系统类。

References:https://blog.csdn.net/qq_39384184/article/details/80628919

享元模式

意图

运用共享技术有效地支持大量细粒度的对象。

适用性

  • 一个应用程序使用了大量的对象。
  • 完全由于使用大量的对象,造成很大的存储开销。
  • 对象的大多数状态都可变为外部状态。
  • 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
  • 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

结构

在这里插入图片描述

参与者

  • Flyweight
    • 描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
  • ConcreteFlyweight
    • 实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
  • UnsharedConcreteFlyweight
    • 并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点(Row和Column就是这样)。
  • FlyweightFactory
    • 创建并管理flyweight对象。
    • 确保合理地共享flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
  • Client
    • 维持一个对flyweight的引用。
    • 计算或存储一个(多个)flyweight的外部状态。

协作

  • flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部状态则由Client对象存储或计算。当用户调用flyweight对象的操作时,将该状态传递给它。
  • 用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,这可以保证对它们适当地进行共享。

效果

  1. 使用Flyweight模式时,传输、查找和/或计算外部状态都会产生运行时的开销,尤其当flyweight原先被存储为内部状态时。然而,空间上的节省抵消了这些开销。
  2. 共享的Flyweight越多,存储节约也就越多。
  3. Flyweight模式经常和Composite模式结合起来表示一个层次式结构,这一层次式结构是一个共享叶节点的图。共享的结果是,Flyweight的叶节点不能存储指向父节点的指针。而父节点的指针将传给Flyweight作为它的外部状态的一部分。

References:https://blog.csdn.net/qq_39384184/article/details/80753999

代理模式

意图

为其他对象提供一种代理以控制对这个对象的访问。

适用性

  • 远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表。
  • 虚代理(Virtual Proxy)根据需要创建开销很大的对象。
  • 保护代理(Protection Proxy)控制对原始对象的访问。
  • 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:
    • 对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它。
    • 当第一次引用一个持久对象时,将它装入内存。
    • 在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

结构

在这里插入图片描述

参与者

  • Subject
    • 定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
  • Proxy
    • 保存一个引用使得代理可以访问实体。若RealSubject和Subject的接口相同,Proxy会引用Subject。
    • 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
    • 控制对实体的存取,并可能负责创建和删除它。
    • 其他功能依赖于代理的类型:
      • Remote Proxy负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。
      • Virtual Proxy可以缓存实体的附加信息,以便延迟对它的访问。
      • Protection Proxy检查调用者是否具有实现一个请求所必需的访问权限。
  • RealSubject
    • 定义Proxy所代表的实体

协作

  • 代理根据其种类,在适当的时候向RealSubject转发请求。

效果

  1. Proxy模式在访问对象时引入了一定程度的间接性。根据代理的类型,附加的间接性有多种用途:
    • Remote Proxy可以隐藏一个对象存在于不同地址空间的事实。
    • Virtual Proxy可以进行最优化,例如根据要求创建对象。
    • Protection Proxy和Smart Reference都允许在访问一个对象时有一些附加的内务处理。
  2. Proxy模式还可以对用户隐藏另一种称之为copy-on-write的优化方式,该优化与根据需要创建对象有关。在实现Copy-on-write时必须对实体进行引用计数。Copy-on-Write可以大幅度的降低拷贝庞大实体时的开销。

References:https://blog.csdn.net/qq_39384184/article/details/80756939

结构型模式的讨论

Adapter与Bridge

Adapter模式和Bridge模式具有一些共同的特征。它们都给另一对象提供了一定程度上的间接性,因而有利于系统的灵活性。它们都涉及到从自身以外的一个接口向这个对象转发请求。

这些模式的不同之处主要在于它们各自的用途。Adapter模式主要是为了解决两个已有接口之间不匹配的问题。它不考虑这些接口是怎样实现的,也不考虑它们各自可能会如何演化。这种方式不需要对两个独立设计的类中的任一个进行重新设计,就能够使它们协同工作。另一方面,Bridge模式则对抽象接口与它的(可能是多个)实现部分进行桥接。虽然这一模式允许你修改实现它的类,它仍然为用户提供了一个稳定的接口。Bridge模式也会在系统演化时适应新的实现。

由于这些不同点,Adapter和Bridge模式通常被用于软件生命周期的不同阶段。当你发现两个不兼容的类必须同时工作时,就有必要使用Adapter模式,其目的一般是为了避免代码重复。此处耦合不可预见。相反,Bridge的使用者必须事先知道:一个抽象将有多个实现部分,并且抽象和实现两者是独立演化的。Adapter模式在类已经设计好后实施;而Bridge模式在设计类之前实施。这并不意味着Adapter模式不如Bridge模式,只是因为它们针对了不同的问题。

Adapter与Facade

你可能认为facade是另外一组对象的适配器。但这种解释忽视了一个事实:即Facade定义一个新的接口,而Adapter则复用一个原有的接口。记住,适配器使两个已有的接口协同工作,而不是定义一个全新的接口。

Composite与Decorator

Composite模式和Decorator模式具有类似的结构图,这说明它们都基于递归组合来组织可变数目的对象。这一共同点可能会使你认为,decorator对象是一个退化的composite,但这一观点没有领会Decorator模式要点。相似点仅止于递归组合,同样,这是因为这两个模式的目的不同。

Decorator旨在使你能够不需要生成子类即可给对象添加职责。这就避免了静态实现所有功能组合,从而导致子类急剧增加。Composite则有不同的目的,它旨在构造类,使多个相关的对象能够以统一的方式处理,而多重对象可以被当作一个对象来处理。它重点不在于修饰,而在于表示。

尽管它们的目的截然不同,但却具有互补性。因此Composite和Decorator模式通常协同使用。在使用这两种模式进行设计时,我们无需定义新的类,仅需将一些对象插接在一起即可构建应用。这时系统中将会有一个抽象类,它有一些composite子类和decorator子类,还有一些实现系统的基本构建模块。此时,composites和decorator将拥有共同的接口。从Decorator模式的角度看,composite是一个ConcreteComponent。而从composite模式的角度看,decorator则是一个Leaf。当然,他们不一定要同时使用,正如我们所见,它们的目的有很大的差别。

Decorator与Proxy

另一种与Decorator模式结构相似的模式是Proxy。这两种模式都描述了怎样为对象提供一定程度上的间接引用,proxy和decorator对象的实现部分都保留了指向另一个对象的指针,它们向这个对象发送请求。然而同样,它们具有不同的设计目的。

像Decorator模式一样,Proxy模式构成一个对象并为用户提供一致的接口。但与Decorator模式不同的是,Proxy模式不能动态地添加或分离性质,它也不是为递归组合而设计的。它的目的是,当直接访问一个实体不方便或不符合需要时,为这个实体提供一个替代者,例如,实体在远程设备上,访问受到限制或者实体是持久存储的。

在Proxy模式中,实体定义了关键功能,而Proxy提供(或拒绝)对它的访问。在Decorator模式中,组件仅提供了部分功能,而一个或多个Decorator负责完成其他功能。Decorator模式适用于编译时不能(至少不方便)确定对象的全部功能的情况。这种开放性使递归组合成为Decorator模式中一个必不可少的部分。而在Proxy模式中则不是这样,因为Proxy模式强调一种关系(Proxy与它的实体之间的关系),这种关系可以静态的表达。


行为模式

行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。这些模式刻划了在运行时难以跟踪的复杂的控制流。它们将你的注意力从控制流转移到对象间的联系方式上来。

  • 行为类模式使用继承机制在类间分派行为。(模板方法模式,解释器模式)
  • 行为对象模式使用对象复合而不是继承。

职责链模式

意图

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这 些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

适用性

  • 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
  • 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 可处理一个请求的对象集合应被动态指定。

结构

在这里插入图片描述

参与者

  • Handler
    • 定义一个处理请求的接口。
    • (可选)实现后继链。
  • ConcreteHandler
    • 处理它所负责的请求。
    • 可访问它的后继者。
    • 如果可处理该请求,就处理之;否则将该请求转发给它的后继者。
  • Client
    • 向链上的具体处理者(ConcreteHandler)对象提交请求。

协作

  • 当客户提交一个请求时,请求沿链传递直至有一个 ConcreteHandler 对象负责处理它。

效果

  1. 降低耦合度。
  2. 增强了给对象指派职责(Responsibility)的灵活性。
  3. 不保证被接受。

References:https://blog.csdn.net/qq_39384184/article/details/80329843

命令模式

意图

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

适用性

  • 抽象出待执行的动作以参数化某对象。
  • 在不同的时刻指定、排列和执行请求。
  • 支持取消操作。
  • 支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。
  • 用构建在原语操作上的高层操作构造一个系统。

结构

在这里插入图片描述

参与者

  • Command
    • 声明执行操作的接口。
  • ConcreteCommand
    • 将一个接收者对象绑定于一个动作。
    • 调用接收者相应的操作,以实现Execute。
  • Client
    • 创建一个具体命令对象并设定它的接收者。
  • Invoker
    • 要求该命令执行这个请求。
  • Receiver
    • 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

协作

  • Client创建一个ConcreteCommand对象并指定它的Receiver对象。
  • 某Invoker对象存储该ConcreteCommand对象。
  • 该Invoker通过调用Command对象的Execute操作来提交一个请求。若该命令是可撤消的,ConcreteCommand就在执行Execute操作之前存储当前状态以用于取消该命令。
  • ConcreteCommand对象对调用它的Receiver的一些操作以执行该请求。

效果

  1. Command模式将调用操作的对象与知道如何实现该操作的对象解耦。
  2. Command是头等的对象。它们可像其他的对象一样被操纵和扩展。
  3. 你可将多个命令装配成一个复合命令。
  4. 增加新的Command很容易,因为这无需改变已有的类。

References:https://blog.csdn.net/qq_39384184/article/details/80760931

解释器模式

意图

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示 来解释语言中的句子。

适用性

  • 文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。
  • 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。

结构

在这里插入图片描述

参与者

  • AbstractExpression
    • 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
  • TerminalExpression
    • 实现与文法中的终结符相关联的解释操作。
    • 一个句子中的每个终结符需要该类的一个实例。
  • NonterminalExpression
    • 对文法中的每一条规则都需要一个NonterminalExpression类。
    • 为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量。
    • 为文法中的非终结符实现解释(Interpret)操作。解释(Interpret)一般要递归地调用表示R1到Rn的那些对象的解释操作。
  • Context
    • 包含解释器之外的一些全局信息。
  • Client
    • 构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
    • 调用解释操作。

协作

  • Client构建(或被给定)一个句子,它是NonterminalExpression和TerminalExpression的实例的一个抽象语法树,然后初始化上下文并调用解释操作。
  • 每一非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。
  • 每一节点的解释操作用上下文来存储和访问解释器的状态。

效果

  1. 易于改变和扩展文法。
  2. 也易于实现文法。
  3. 复杂的文法难以维护。
  4. 增加了新的解释表达式的方式,解释器模式使得实现新表达式“计算”变得容易。

References:https://blog.csdn.net/qq_39384184/article/details/80777956

迭代器模式

意图

提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

适用性

  • 访问一个聚合对象的内容而无需暴露它的内部表示。
  • 支持对聚合对象的多种遍历。
  • 为遍历不同的聚合结构提供一个统一的接口(即,支持多态迭代)。

结构

在这里插入图片描述

参与者

  • Iterator
    • 迭代器定义访问和遍历元素的接口。
  • ConcreteIterator
    • 具体迭代器实现迭代器接口。
    • 对该聚合遍历时跟踪当前位置。
  • Aggregate
    • 聚合定义创建相应迭代器对象的接口。
  • ConcreteAggregate
    • 具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。

协作

  • ConcreteIterator跟踪聚合中的当前对象,并能够计算出待遍历的后继对象。

效果

  1. 它支持以不同的方式遍历一个聚合复杂的聚合可用多种方式进行遍历。
  2. 迭代器简化了聚合的接口有了迭代器的遍历接口,聚合本身就不再需要类似的遍历接口了。
  3. 在同一个聚合上可以有多个遍历,每个迭代器保持它自己的遍历状态。

References:https://blog.csdn.net/qq_39384184/article/details/79998855

中介者模式

意图

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

适用性

  • 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  • 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

结构

在这里插入图片描述

参与者

  • Mediator
    • 中介者定义一个接口用于与各同事(Colleague)对象通信。
  • ConcreteMediator
    • 具体中介者通过协调各同事对象实现协作行为。
    • 了解并维护它的各个同事。
  • Colleague class
    • 每一个同事类都知道它的中介者对象。
    • 每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。

协作

  • 同事向一个中介者对象发送和接收请求。中介者在各同事间适当地转发请求以实现协作行为。

效果

  1. 减少了子类生成,Mediator将原本分布于多个对象间的行为集中在一起。
  2. 它将各Colleague解耦,Mediator有利于各Colleague间的松耦合。
  3. 它简化了对象协议,用Mediator和各Colleague间的一对多的交互来代替多对多的交互。
  4. 它对对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,使你将注意力从对象各自本身的行为转移到它们之间的交互上来。
  5. 它使控制集中化,中介者模式将交互的复杂性变为中介者的复杂性。

References:https://blog.csdn.net/qq_39384184/article/details/80631275

备忘录模式

意图

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。 这样以后就可将该对象恢复到原先保存的状态。

适用性

  • 必须保存一个对象在某一个时刻的(部分)状态,样以后需要时它才能恢复到先前的状态。
  • 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

结构

在这里插入图片描述

参与者

  • Memento
    • 备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
    • 防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者(caretaker)只能看到备忘录的窄接口(public)
    • 它只能将备忘录传递给其他对象。相反,原发器能够看到一个宽接口(包),允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生成本备忘录的那个原发器访问本备忘录的内部状态。
  • Originator
    • 原发器创建一个备忘录,用以记录当前时刻它的内部状态。
    • 使用备忘录恢复内部状态。
  • Caretaker
    • 负责保存好备忘录。
    • 不能对备忘录的内容进行操作或检查。

协作

  • 管理器向原发器请求一个备忘录,保留一段时间后,将其送回给原发器。有时管理者不会将备忘录返回给原发器,因为原发器可能根本不需要退到先前的状态。
  • 备忘录是被动的。只有创建备忘录的原发器会对它的状态进行赋值和检索。

效果

  1. 保持封装边界。
  2. 它简化了原发器。
  3. 使用备忘录可能代价很高。
  4. 定义窄接口和宽接口。
  5. 维护备忘录的潜在代价。

References:https://blog.csdn.net/qq_39384184/article/details/80637654

观察者模式

意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

适用性

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。

结构

在这里插入图片描述

参与者

  • Subject
    • 目标知道它的观察者。可以有任意多个观察者观察同一个目标。
    • 提供注册和删除观察者对象的接口。
  • Observer
    • 为那些在目标发生改变时需获得通知的对象定义一个更新接口。
  • ConcreteSubject
    • 将有关状态存入各ConcreteObserver对象。
    • 当它的状态发生改变时,向它的各个观察者发出通知。
  • ConcreteObserver
    • 维护一个指向ConcreteSubject对象的引用。
    • 存储有关状态,这些状态应与目标的状态保持一致。
    • 实现Observer的更新接口以使自身状态与目标的状态保持一致。

协作

  • 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
  • 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。

效果

  1. 目标和观察者间的抽象耦合。
  2. 支持广播通信。
  3. 意外的更新。

References:https://blog.csdn.net/qq_39384184/article/details/80637643

状态模式

意图

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

适用性

  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对 象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

结构

在这里插入图片描述

参与者

  • Context
    • 定义客户感兴趣的接口。
    • 维护一个ConcreteState子类的实例,这个实例定义当前状态。
  • State
    • 定义一个接口以封装与Context的一个特定状态相关的行为。
  • ConcreteState subclasses
    • 每一子类实现一个与Context的一个状态相关的行为。

协作

  • Context将与状态相关的请求委托给当前的ConcreteState对象处理。
  • Context可将自身作为一个参数传递给处理该请求的状态对象。这使得状态对象在必要时可访问Context。
  • Context是客户使用的主要接口。客户可用状态对象来配置一个Context,一旦一个Context配置完毕,它的客户不再需要直接与状态对象打交道。
  • Context或ConcreteState子类都可决定哪个状态是另外哪一个的后继者,以及是在何种条件下进行状态转换。

效果

  1. 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
  2. 它使得状态转换显式化。
  3. State对象可被共享。

References:https://blog.csdn.net/qq_39384184/article/details/80753453

策略模式

意图

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

适用性

  • 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
  • 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
  • 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。

结构

在这里插入图片描述

参与者

  • Strategy
    • 定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
  • ConcreteStrategy
    • 以Strategy接口实现某具体算法。
  • Context
    • 用一个ConcreteStrategy对象来配置。
    • 维护一个对Strategy对象的引用。
    • 可定义一个接口来让Strategy访问它的数据。

协作

  • Strategy和Context相互作用以实现选定的算法。当算法被调用时,Context可以将该算法所需要的所有数据都传递给该Strategy。或者,Context可以将自身作为一个参数传递给Strategy操作。这就让Strategy在需要时可以回调Context。
  • Context将它的客户的请求转发给它的Strategy。客户通常创建并传递一个ConcreteStrategy对象给该Context;这样,客户仅与Context交互。通常有一系列的ConcreteStrategy类可供客户从中选择。

效果

  1. 相关算法系列,Strategy类层次为Context定义了一系列的可供重用的算法或行为。
  2. 一个替代继承的方法,继承提供了另一种支持多种算法或行为的方法。
  3. 消除了一些条件语句Strategy模式提供了用条件语句选择所需的行为以外的另一种选择。

References:https://blog.csdn.net/qq_39384184/article/details/80316343

模板方法模式

意图

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适用性

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
  • 控制子类扩展。模板方法只在特定点调用“hook”操作

结构

在这里插入图片描述

参与者

  • AbstractClass
    • 定义抽象的原语操作(primitive operation),具体的子类将重定义它们以实现一个算法的各步骤。
    • 实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。
  • ConcreteClass
    • 实现原语操作以完成算法中与特定子类相关的步骤。

协作

  • ConcreteClass靠AbstractClass来实现算法中不变的步骤。

效果

  1. 模板方法是一种代码复用的基本技术。
  2. 模板方法导致一种反向的控制结构。

References:https://blog.csdn.net/qq_39384184/article/details/79999032

访问者模式

意图

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

适用性

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。

结构

在这里插入图片描述

参与者

  • Visitor
    • 为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
  • ConcreteVisitor
    • 实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
  • Element
    • 定义一个Accept操作,它以一个访问者为参数。
  • ConcreteElement
    • 实现Accept操作,该操作以一个访问者为参数。
  • ObjectStructure
    • 能枚举它的元素。
    • 可以提供一个高层的接口以允许该访问者访问它的元素。
    • 可以是一个复合或是一个集合,如一个列表或一个无序集合。

协作

  • 一个使用Visitor模式的客户必须创建一个ConcreteVisitor对象,然后遍历该对象结构,并用该访问者访问每一个元素。
  • 当一个元素被访问时,它调用对应于它的类的Visitor操作。如果必要,该元素将自身作为这个操作的一个参数以便该访问者访问它的状态。

效果

  1. 访问者模式使得易于增加新的操作,访问者使得增加依赖于复杂对象结构的构件的操作变得容易了。
  2. 访问者集中相关的操作而分离无关的操作,相关的行为不是分布在定义该对象结构的各个类上,而是集中在一个访问者中。
  3. 增加新的ConcreteElement类很困难,Visitor模式使得难以增加新的Element的子类。
  4. 通过类层次进行访问。
  5. 累积状态。
  6. 破坏封装。

References:https://blog.csdn.net/qq_39384184/article/details/80327860

行为模式的讨论

封装变化

  • 一个Strategy对象封装一个算法。
  • 一个State对象封装一个与状态相关的行为。
  • 一个Mediator对象封装对象间的协议。
  • 一个Iterator对象封装访问和遍历一个聚集对象中的各个构件的方法。

这些模式描述了程序中很可能会改变的方面。大多数模式有两种对象:封装该方面特征的新对象,和使用这些新的对象的已有对象。如果不使用这些模式的话,通常这些新对象的功能就会变成这些已有对象的难以分割的一部分。例如,一个Strategy的代码可能会被嵌入到其Context类中,而一个State的代码可能会在该状态的Context类中直接实现。

但不是所有的对象行为模式都象这样分割功能。例如,Chain of Responsibility可以处理任意数目的对象(即一个链),而所有这些对象可能已经存在于系统中了。职责链说明了行为模式间的另一个不同点:并非所有的行为模式都定义类之间的静态通信关系。职责链提供在数目可变的对象间进行通信的机制。其他模式涉及到一些作为参数传递的对象。

对象作为参数

一些模式引入总是被用作参数的对象。例如Visitor。一个Visitor对象是一个多态的Accept操作的参数,这个操作作用于该Visitor对象访问的对象。虽然以前通常代替Visitor模式的方法是将Visitor代码分布在一些对象结构的类中,但visitor从来都不是它所访问的对象的一部分。

**Command和Memento定义一些可作为令牌到处传递的对象,这些对象将在稍后被调用。在Command中,令牌代表一个请求;而在Memento中,它代表在一个对象在某个特定时刻的内部状态。**在这两种情况下,令牌都可以有一个复杂的内部表示,但客户并不会意识到这一点。但这里还有一些区别:在Command模式中多态很重要,因为执行Command对象是一个多态的操作。相反,Memento接口非常小,以至于备忘录只能作为一个值传递。因此它很可能根本不给它的客户提供任何多态操作。

通信应该被封装还是分布

Mediator和Observer是相互竞争的模式。它们之间的差别是,Observer通过引入Observer和Subject对象来分布通信,而Mediator对象则封装了其他对象间的通信。

在Observer模式中,不存在封装一个约束的单个对象,而必须是由Observer和Subject对象相互协作来维护这个约束。通信模式由观察者和目标连接的方式决定:一个目标通常有多个观察者,并且有时一个目标的观察者也是另一个观察者的目标。Mediator模式的目的是集中而不是分布。它将维护一个约束的职责直接放在一个中介者中。

我们发现生成可复用的Observer和Subject比生成可复用的Mediator容易一些。Observer模式有利于Observer和Subject间的分割和松耦合,同时这将产生粒度更细,从而更易于复用的类。

另一方面,相对于Observer,Mediator中的通信流更容易理解。观察者和目标通常在它们被创建后很快即被连接起来,并且很难看出此后它们在程序中是如何连接的。如果你了解Observer模式,你将知道观察者和目标间连接的方式是很重要的,并且你也知道寻找哪些连接。然而,Observer模式引入的间接性仍然会使得一个系统难以理解。

对发送者和接受者解耦

当合作的对象直接互相引用时,它们变得互相依赖,这可能会对一个系统的分层和重用性产生负面影响。命令、观察者、中介者,和职责链等模式都涉及如何对发送者和接收者解耦,但它们又各有不同的权衡考虑。

命令模式使用一个Command对象来定义一个发送者和一个接收者之间的绑定关系,从而支持解耦。Command对象提供了一个提交请求的简单接口(即Execute操作)。将发送者和接收者之间的连接定义在一个单独的对象使得该发送者可以与不同的接收者一起工作。这就将发送者与接收者解耦,使发送者更易于复用。此外,可以复用Command对象,用不同的发送者参数化一个接收者。虽然Command模式描述了避免使用生成子类的实现技术,名义上每一个发送者-接收者连接都需要一个子类。

在这里插入图片描述

观察者模式通过定义一个接口来通知目标中发生的改变,从而将发送者(目标)与接收者(观察者)解耦。Observer定义了一个比Command更松的发送者-接收者绑定,因为一个目标可能有多个观察者,并且其数目可以在运行时变化。

在这里插入图片描述

中介者模式让对象通过一个Mediator对象间接的互相引用,从而对它们解耦。一个Mediator对象为各Colleague对象间的请求提供路由并集中它们的通信。因此各Colleague对象仅能通过Mediator接口相互交谈。因为这个接口是固定的,为增加灵活性Mediator可能不得不实现它自己的分发策略。可以用一定方式对请求编码并打包参数,使得Colleague对象可以请求的操作数目不限。中介者模式可以减少一个系统中的子类生成,因为它将通信行为集中到一个类中而不是将其分布在各个子类中。然而,特别的分发策略通常会降低类型安全性。

在这里插入图片描述

职责链模式通过沿一个潜在接收者链传递请求而将发送者与接收者解耦。因为发送者和接收者之间的接口是固定的,职责链可能也需要一个定制的分发策略。因此它与Mediator一样存在类型安全的问题。如果职责链已经是系统结构的一部分,同时在链上的多个对象中总有一个可以处理请求,那么职责链将是一个很好的将发送者和接收者解耦的方法。此外,因为链可以被简单的改变和扩展,从而该模式提供了更大的灵活性。

在这里插入图片描述


想了解更多关于设计模式:设计模式专栏

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值