设计模式总结
面向对象设计原则
单一职责原则:提高复用性。高内聚,低耦合。
开闭原则:开放拓展,关闭修改。(灵活性,稳定性,抽象化)
里氏代换原则:父类可替换为子类,反之不成立。(抽象化,代码复用,扩展性)
依赖倒转原则:针对抽象层编程。(抽象化)
接口隔离原则:多个专门的接口取代统一接口,不依赖不需要的接口。
合成复用原则:多组合聚合,少继承。(降耦合)
迪米特法则:一个软件实体尽可能少地与其他实体相互作用。只与直接朋友通信。(松耦合)
名称 | 定义 | 优点 | 缺点 | 适用环境 | 备注 |
简单工厂 (静态工厂) (创建型) |
根据参数的不同返回不同类的实例。 OA系统 |
对象的创建、使用分离。 使用配置文件,提高了系统灵活性。 客户端只需要知道产品类对应参数。 |
工厂类职责过重。 扩展困难。 增加了系统复杂性和理解难度。 |
工厂类负责创建的对象少。 不关心创建细节。 |
单一职责原则 降耦合 开闭原则 |
工厂方法 |
将类的实例化延迟到子类中完成,由子类决定实例化(创建)哪个类。 日志记录器 |
向客户隐藏哪种具体产品类被实例化。 工厂自主确定创建何种产品对象。 加入新产品符合开闭原则。 |
类的个数成对增加,系统复杂度提升。 增加了系统的抽象性和理解难度。 |
客户不知道具体产品类的类名。 抽象工厂类通过其子类指定创建哪个对象。 |
开闭原则 可扩展性 |
抽象工厂 |
提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。 电器工厂,数据库操作工厂 |
隔离了具体类的生成。 保证客户端始终只使用同一产品族对象。 增加新的产品族方便,符合开闭原则。 |
增加新的产品等级结构麻烦,违背开闭原则。 |
系统不依赖产品创建、组合、表达细节。 每次只使用一个产品族且所有产品一起使用。 产品等级结构稳定。 |
+新产品族,符合开闭。 +新产品等级结构,不符合开闭。 |
建造者 Builder |
将复杂对象的构建与表示分离,使同样的构建可以创建不同表示。 KFC套餐,JavaMail |
产品本身与产品创建过程解耦。 替换/新增具体建造者符合开闭原则。 可更精细地控制产品创建过程。 |
产品之间差异大则不适用。 产品内部变化复杂需更多具体建造类,导致系统过于庞大。 |
需要生成的产品有复杂的内部结构,属性相互依赖。 对象创建过程独立于创建对象的类。 |
|
原型模式 Prototype |
给出一个原型对象指明所要创建的对象类型,复制这个原型对象创建更多同类型对象。 浅克隆,深克隆(序列化),邮件复制。 |
简化对象创建过程,提高新实例创建效率。 简化创建结构,扩展性好。 深克隆方式能保存对象状态。(撤销) |
每个类需要配备一个克隆方法。 改造已有类需修改源码,改变开闭原则。 深克隆代码复杂。 |
创建新对象成本较大。 对象的状态变化小。 避免使用分层次工厂类。 |
|
单例模式 Singleton |
确保一个类中只有一个实例,自行实例化并向整个系统提供这个实例。 身份证,打印池 |
提供了对唯一实例的受控访问。 节约系统资源,提高性能。 允许多例类。 |
扩展困难。 单例类职责过重。 垃圾自动回收机制丢失单例对象的状态。 |
只需要/允许创建一个对象。 只允许使用一个公共访问点。 |
|
适配器模式 (结构型) Adaptee |
将一个接口转换成客户希望的另一个接口,使接口不兼容的类可以一起工作。 机器人模仿,加密适配器 |
将目标类和适配器解耦。 增加了类的透明性和复用性。 灵活性和扩展性好。 |
类适配器:一次只适配一个适配者类。 目标抽象类只能为接口,不能为类。 对象适配器:置换适配者类的某些方法麻烦。 |
系统需要使用一些现有的类,而这些类的接口不符合系统需要。 创建一个可以重复使用的类。 |
|
桥接模式 Implementor |
抽象与实现部分分离,使他们可以独立地变化。 大中小彩色毛笔,跨平台视频播放器 |
分离抽象接口及其实现部分。 取代多层继承,减少子类个数。 提高系统的可扩展性。 |
增加系统的理解与设计难度。 难以正确识别系统中两个独立变化的维度。 |
增加抽象化和具体化间的灵活性。 抽象、实现部分独立扩展互不影响。 不希望使用继承。 |
|
组合模式 Leaf |
组合多个对象形成树形结构以表示整体-部分的结构层次,对单个对象和组合对象的使用具有一致性。 水果盘,文件浏览 |
定义分层次复杂对象,忽略层次差异。 增加新容量构件和叶子构件方便。 实现树形结构面向对象。 |
抽象复杂,难度大。 增加新构件时很难对容器中的构件类型进行限制。 |
希望客户一致对待整体,部分层次结构。 面向对象开发系统中处理树形结构。 系统中可分离出叶子和容器对象。 |
|
装饰模式 Decorator |
动态地给一个对象增加一些额外职责。 变形金刚变飞机、机器人,多重加密系统 |
比继承灵活,不会急剧增加类的个数。 动态方式扩展对象功能。 可对一个对象多次装饰。 加新的构件类和装饰类符合开闭原则。 |
一定程度下影响对象性能。 比继承更易出错,难排错。 |
动态透明地给单个对象添加职责。 不能采用继承方式扩展系统。 |
|
外观模式 Facade |
为复杂子系统提供一个统一入口。 电源总开关,文件加密外观类, |
减少了客户端所需处理的对象数目。 实现了子系统与客户端间的松耦合。 子系统修改对其他子系统,外观无影响。 |
不能很好地限制客户端直接使用子系统类。 增加新子系统需修改外观类,违背开闭原则。 |
为复杂子系统提供简单入口。 客户端与多个子系统存在依赖性。 层次性结构通过外观类建立联系。 |
迪米特法则 降耦合 |
代理模式 Proxy |
给对象提供一个代理,并由代理对象控制原对象的引用。 论坛权限控制,图片预览 |
协调调用者、被调用者,降耦合。 增加/更换代理类无须修改代码,符合开闭原则。 |
(保护代理)可能造成请求处理缓慢。 (远程代理)实现过程复杂。 |
远程代理,虚拟代理(预览),缓冲代理(共享访问),保护代理(权限),智能引用代理 | |
命令模式(对象型行为模式) Invoker |
将一个请求封装为一个对象,使请求调用者和接收者解耦。 电视遥控器(开关,exchange),功能键 |
降低系统耦合度。 新命令易加入系统,符合开闭原则。 命令队列,宏命令,请求撤销,恢复。 |
可能会导致某些系统有过多具体命令类。 |
将请求调用者和接收者解耦。 不同时间指定请求,请求排队,执行命令撤销,恢复。 |
|
迭代器模式 Iterator |
提供一种方法访问聚合对象,而不暴露对象的内部表示。 遥控器换台 |
同一聚合对象可定义多种遍历方式。 简化了聚合类。 增加聚合类、迭代器方便,符合开闭原则。 |
增加新聚合类需要新迭代器类,复杂性提升。 设计难度大,很难全面考虑。 |
访问聚合对象内容而不暴露内部。 为一个聚合类提供多种遍历方式。 为遍历不同聚合结构提供统一接口。 |
单一职责原则 |
观察者模式 Observer |
定义了对象间的一种一对多依赖关系,使每当一个对象状态改变时,其依赖对象得到通知并被自动更新。 猫狗鼠,MVC,自定义登录控件 |
可实现表示层与数据逻辑层分离。 支持广播通信,一对多。 在观察目标和观察者间建立了一个抽象耦合。 增加具体观察者和观察目标符合开闭原则。 |
通知所有观察者会花费很多时间。 如有循环依赖可能使系统崩溃。 观察者不知道目标对象是怎么发生变化的。 |
抽象模型一方面依赖于另一方面。 一个对象改变会导致别的对象改变。 需要在系统中创建一个触发链。 |
|
状态模式 State |
允许一个对象在其内部改变时改变它的行为。 论坛用户等级,人开心时笑伤心时哭,银行账户余额为正则绿、欠款则红 |
封装状态转换规则,集中管理代码。 注入不同状态可使环境对象行为不同。 允许状态转换逻辑与状态对象合成一体。 多环境对象共享一个状态对象,可以减少类的个数。 |
增加类和对象的个数,增大开销。 使用不当代码会导致混乱,增加难度。 新增/修改状态类不符合开闭原则。 |
状态改变导致对象行为变化。 代码有大量与对象状态有关的条件语句。 |
|
策略模式 Strategy |
定义一系列算法,并将每个算法封装在一个类中,并让他们可以互相替换。让算法独立于使用它的客户而变化。 旅游出行策略,排序策略 |
支持开闭原则,可管理相关算法族。 可替换继承,提高算法复用。 避免多重条件语句。 |
客户端必须知道所有策略类并进行选择。 可能造成系统产生很多具体策略类。 无法同时使用多个策略类。 |
一个系统需动态地在多种算法中选择一个。 避免使用难以维护的多重条件选择。 不希望客户知道与算法相关的数据结构。 |
算法保密性 安全性 |