设计模式大集合
设计模式的定义和结构
软件设计模式是:在软件设计中,一个通用的,可重用的解决方案,用于解决给定上下文中的一个常见问题。
设计模式的描述
下面定义了一个标准描述设计模式的结构。
- 模式名称和分类
一个描述性和惟一的名称,有助于识别和引用模式。 - 意图
描述模式背后的目标和使用它的原因。 - 别名
模式的其他名称。 - 动机
由问题和可使用该模式的上下文组成的场景。 - 适用性
这种模式可用的情况;模式的上下文。 - 结构
模式的图形表示。类图和交互图可以用于此目的。 - 参与者
模式中使用的类和对象的列表及其在设计中的角色。 - 协作
描述模式中使用的类和对象如何相互作用。 - 结果
对使用该模式导致的结果、副作用和交易的描述。 - 实施
对模式实施的描述;这个模式的解决方案部分。 - 示例代码
演示如何在编程语言中使用模式的说明。 - 已知用途
模式的实际使用示例。 - 相关模式
与模式有一定关系的其他模式;讨论模式和相似模式之间的差异。
生成模式
名称 | 描述 |
---|---|
抽象工厂 | 提供了一个接口,用于创建相关的一组对象,而无需指定具体的类。 |
构建器 | 将复杂对象的构造与它的表示分开,允许相同的构造过程创建各种各样的表示。 |
依赖注入 | 一个类接受来自注入器的对象,而不是直接创建对象。 |
工厂方法 | 定义了创建单个对象的接口,但是让子类决定实例化哪个类。工厂方法让一个类延迟实例化到子类。 |
延迟创建 | 对象的延迟初始化策略,即在第一次需要时,延迟创建一个对象、计算一个值或其他一些昂贵的过程。 |
Multiton | 确保一个类只有命名的实例,并提供一个全局的访问点。 Key-value 版本,集成多个类的单例模式。 |
对象池 | 通过回收不再使用的对象来避免昂贵的获取和释放资源。可以被认为是连接池和线程池模式的泛化。 |
Prototype | 通过一个原型实例指定要创建的对象种类,并从现有对象的“骨架”中创建新的对象,从而提高性能并将内存占用保持在最小值。 |
资源获取是初始化 | (RAII)确保通过将资源与合适对象的生命周期相关联来适当地释放资源。 |
单例模式 | 确保一个类只有一个实例,并且提供了一个全局的访问点。 |
结构模式
名称 | 描述 |
---|---|
适配器、包装器或转换器 | 将一个类的接口转换成客户期望的另一个接口。一个适配器让类协同工作,否则由于接口不兼容,就不能这样做。 |
桥 | 将抽象与它的实现分离,使两者独立地变化。 |
组合 | 将对象组合成树形结构,以表示部分整体的层次结构。使客户端可以统一的处理单个物体和对象的组合。 |
装饰器 | 将额外的责任附加到一个动态保持相同接口的对象上。装饰器提供了一种灵活的替代方法来扩展功能。 |
扩展对象 | 将功能添加到层次结构中,而不需要改变层次结构。 |
Facade | 为子系统中的一组接口提供统一的接口。门面定义了一个更高级的接口,使子系统更易于使用。 |
Flyweight | 使用共享来有效地支持大量的类似对象。 |
前端控制器 | 模式与Web应用程序的设计有关。它提供了处理请求的集中入口点。 |
标记 | 空接口将元数据与一个类关联起来。 |
模块 | 组几个相关的元素,例如类、单例、方法,以及全局使用的方法,都是一个概念实体。 |
代理 | 为另一个对象提供代理或占位符来控制对它的访问。 |
双胞胎 | 对在不支持该特性的编程语言中,允许对多重继承进行建模。 |
行为模式
名称 | 描述 |
---|---|
黑板 | 人工智能模式,用于组合不同的数据来源(参见黑板系统) |
责任链 | 避免将请求的发送者与它的接收者耦合,因为它给多个对象一个处理请求的机会。将接收对象串起来,并沿着链传递请求,直到一个对象处理它。 |
命令 | 将请求封装为一个对象,从而允许具有不同请求的客户端参数化,以及请求的排队或日志记录。它还允许支持非可行的操作。 |
解释器 | 使用一种语言,为它的语法定义一个表示,以及一个使用该表示来解释语言句子的解释器。 |
迭代器 | 提供了一种方法,可以在不暴露其底层表示的情况下连续访问聚合对象的元素。 |
中介 | 定义了一个对象,它封装了一组对象之间的交互方式。中介通过使对象不显式地相互引用来促进松散耦合,并且允许它们的交互独立地变化。 |
Memento | 不违反封装、捕获和具体化对象的内部状态,允许对象稍后恢复到这个状态。 |
Null对象 | 通过提供一个默认对象来避免空引用。 |
观察者或发布/订阅 | 定义了对象之间的一对多依赖关系,其中一个对象的状态变化会导致被通知和自动更新的所有依赖项。 |
仆人 | 为一组类定义公共功能。 |
规范 | 以布尔式的方式重组业务逻辑。 |
状态 | 允许物体在其内部状态发生变化时改变其行为。这个对象将会出现改变它的类。 |
策略 | 定义了一个算法家族,封装了每一个算法,并使它们可以互换。策略让算法独立于使用它的客户端。 |
模板方法 | 在一个操作中定义一个算法的骨架,将一些步骤推迟到子类。Template method允许子类重新定义算法的某些步骤,而不改变算法的结构。 |
访问者 | 表示要在对象结构的元素上执行的操作。访问者可以在不改变其操作的元素的类的情况下定义新的操作。 |
并发模式
名称 | 描述 |
---|---|
活动对象 | 将方法执行从位于其自身控制线程中的方法调用中分离出来。我们的目标是通过使用异步方法调用和处理请求的调度程序来引入并发性。 |
阻止 | 当对象处于特定状态时,只对对象执行一个动作。 |
属性绑定 | 结合多个观察者来强制不同对象的属性,以某种方式同步或协调。 |
区块链 | 分散存储数据,并就如何在Merkle树中处理数据达成一致,可选地使用数字签名进行任何个人贡献。 |
计算内核 | 在并行计算中,相同计算操作(但数据不同)的计算,使用共享数组将不同计算的数据统一计算,如GPU优化矩阵乘法或卷积神经网络。 |
双重检查锁定 | 通过首先测试锁定标准(“锁定提示”)以不安全的方式来减少获得锁的开销;只有当它成功时,实际的锁定逻辑才会继续。在某些语言/硬件组合中实现时,可能是不 |
基于事件的异步 | 处理在多线程程序中发生的异步模式的问题。 |
被保护的悬挂系统 | 管理操作,需要获得一个锁,并且在执行操作之前必须满足一个先决条件。 |
Join | Join-pattern提供了一种通过消息传递来编写并发、并行和分布式程序的方法。与线程和锁的使用相比,这是一个高级编程模型。 |
锁定 | 一个线程在资源上放置一个“锁”,防止其他线程访问或修改它。 |
消息传递设计模式(MDP) | 允许在组件和应用程序之间交换信息(即消息)。 |
监视对象 | 其方法受到互斥锁的影响,从而防止多个对象在同一时间错误地使用它。 |
反应堆 | 一个反应堆对象为必须同步处理的资源提供了一个异步接口。 |
读写锁 | 允许对一个对象进行并发读访问,但是需要对写操作进行独占访问。 |
调度程序 | 显式地控制线程何时执行单线程代码。 |
线程池 | 是为了执行许多任务而创建的,这些任务通常是在队列中组织的。通常情况下,线程的任务比线程多得多。可以被看作是对象池模式的特殊情况。 |
线程特定的存储 | 静态或“全局”内存局部到线程。 |
.NET Application Architecture
类别 | 设计模式 | 描述 |
---|---|---|
缓存 | 惰性获取 | 延迟了资源的获取,以优化设备资源的使用。 |
缓存 | 缓存依赖项 | 使用外部信息来确定存储在缓存中的数据的状态。 |
缓存 | 页面缓存 | 提高了频繁访问的动态Web页面的响应时间,但更改频率较低,并消耗大量的系统资源来构建。 |
通信 | 活动对象 | 通过封装服务请求和服务完成响应来支持异步处理。 |
通信 | 通信器 | 将通信的内部细节封装在一个单独的组件中,可以通过不同的通道进行通信。 |
通信 | 双向 | 双向消息通信,服务和客户端都可以独立地发送消息,而不考虑使用单向或请求-应答模式。 |
通信 | 发送并忘记 | 当没有响应的时候,通信就会触发,并忘记一个单向消息通信机制。 |
通信 | 网关 | 通过一个通用的抽象接口提供对外部系统的访问,这样使用者就不需要了解外部系统接口。 |
通信 | 拦截过滤器 | 过滤了一个可组合过滤器(独立模块),它在Web页面请求期间实现常见的预处理和后处理任务。 |
通信 | 管道和过滤器 | 通过管道和过滤器路由消息,这些管道和过滤器可以在管道通过管道时修改或检查消息。 |
通信 | 可靠的会话 | 结束了在源和目的地之间传递消息的可靠传输,而不考虑将端点分离的中介体的数量或类型。 |
通信 | 请求响应 | 一个双向消息通信机制,客户端期望收到对发送的每条消息的响应。 |
通信 | 服务代理 | 和代理实现了消费应用程序可以使用的组件,而不知道它没有访问实际的目标组件或服务。组件通过对远程组件或服务的呼叫,并将结果返还给消费应用程序。代理抽象了与其他远程组件通信的细节,通常是在使用ASMX或WCF服务时。 |
通信 | 服务定位器 | 集中分布式服务对象查找,提供一个集中的控制点,并充当一个缓存,消除冗余查找。 |
表示 | 反转控制 | 填充了对象的任何依赖项,这些对象或组件必须在对象被应用程序使用之前完成。 |
表示 | 两步视图 | 将模型数据转换为逻辑表示,而不需要任何特定的格式,然后转换逻辑表示,以添加所需的实际格式。 |
表示 | 模型-视图-控制器 | 将域内的数据、表示和基于用户输入的操作分离到三个单独的类中。该模型管理应用程序域的行为和数据,响应关于其状态(通常来自视图)的信息的请求,并响应指令以改变状态(通常来自控制器)。视图管理信息的显示。控制器从用户那里解释鼠标和键盘输入,通知模型和/或视图在适当的时候进行更改。 |
表示 | 模型-视图-演示者 | 将请求处理分为三个角色,视图负责处理用户输入,负责应用程序数据和业务逻辑的模型,以及负责表示逻辑和协调视图和模型之间交互的演示者。 |
表示 | 模型-视图-viewmodel | 模型-视图-控制器(MVC)的变种,它是为现代UI开发平台量身定做的,视图是设计师的职责,而不是传统的开发人员。 |
表示 | 页面控制器 | 接受来自请求的输入,并在Web站点上处理特定的页面或动作。 |
表示 | 分页 | 将大量的内容分割成单独的页面,以优化系统资源,并最小化对屏幕空间的使用。 |
表示 | 异步回调 | 在后台执行的单独的线程上执行长时间运行的任务,并为线程在任务完成时调用回调函数提供一个函数。 |
同步 | 并行 | 处理允许多个批处理作业并行运行,以最小化总的处理时间。 |
同步 | 分区 | 分区多个大型批处理作业并发运行。 |
GRASP(General responsibility assignment software patterns) - 通用职责分配软件模式
GRASP并不是设计模式,而更像是早期面向对象设计者提出的一些经验。
-
控制器
使用一个非UI的类来处理UI的功能。也可以认为控制器模式是建议一个多层的架构。 -
创建者
这是一个原则,用来确定谁应该负责创建一个类。
类B应该负责创建类A,如果满足下面的条件之一:- B的实例包含A的实例
- B的实例存储了A的实例
- B的实例密切使用A的实例
- B的实例拥有创建实例A的初始信息
-
高内聚
是一个评估模式。是指一个类中,包含的功能之间有密切的相关性。 -
低耦合
是一个评估模式。是指类和类之间,- 在类之间,依赖性低。
- 一个类的改变,对其它类影响小。
- 高重用性。
-
间接性(Indirection)
将两个类之间的协调功能封装到一个中介类中。比如MVC模式中Controller就是View和Model的中介类。 -
信息专家
将职责放到最需要信息的类中。 -
多态性(Polymorphism)
这是面向对象的基本功能。 -
对变化的保护
open for extension, closed for modification.
支持扩展,允许增加属性和方法。
隐藏变化,变化不会影响调用者以前的代码。
现在,基本上使用interface/implementation,来实现这个原则。
定义一个接口类,供外部调用。
实现一个实现类,外部只能通过接口类来调用实现类的功能。 -
纯粹性(Pure fabrication)
使用Service将提供特定的功能。
SOLID
面向对象设计5原则:
-
单一职责原则
一个类应该只有一个单一的责任(例如,只对软件规范的一部分进行更改应该能够影响一个类的定义)。 -
打开/关闭原则
open for extension, but closed for modification.
“软件实体……应该是支持扩展,隐藏变更。” -
Liskov替换原则
“程序中的对象应该可以替换它们的子类型的实例,而不会改变程序的正确性。” -
接口隔离原则
“许多客户端特定的接口比一个通用接口要好。” -
依赖性倒置原则
一个人应该“依赖于抽象,而不是具体的东西。”