GOF设计模式
GOF模式一览表
范围/目的 | 创建型模式 | 结构型模式 | 行为型模式 |
---|---|---|---|
类模式 | 工厂方法模式 | (类)适配器模式 | 解释器模式 模板方法模式 |
对象模式 | 抽象工厂模式 建造这模式 原型模式 单例模式 |
(对象)适配器模式 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式 |
职责链模式 命令模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 策略模式 访问者模式 |
创建型模式
创建型模式是设计模式的一种类型,主要用于对象的创建过程。它们将对象的创建和分离,使得系统在创建对象时更加灵活和可维护,隐藏了对象创建的复杂细节,并且可以根据不同的条件和需求来创建不同类型的对象。
结构型模式
结构型模式主要关注如何将类或对象组合成更大的结构,以实现新的功能和系统架构。它通过定义对象之间的组合方式,使得这些对象能够协同工作,并且可以在不改变现有对象结构的基础上,增加系统的灵活性和可维护性。
行为型模式
行为型模式主要用于处理对象之间的交互和职责分配。它关注的是系统中对象的行为和它们之间的通信方式,通过合理地安排对象的行为逻辑,使得系统能够更加灵活地应对各种变化。
7个面向对象的设计原则
设计原则名称 | 定义 | 精简解释 |
---|---|---|
单一职责原则 | 一个对象应该只包含单一的职责,并且该职责被完整的封装在一个类中 | 一个类只做一件事。 |
开闭原则 | 对扩展开放,对修改关闭 | |
里氏代换原则 | 所有引用基类的地方必须能透明的使用其子类的对象 | 子类能替代基类(父类)工作。 |
依赖倒转原则 | 高层模块不应该依赖底层模块, 它们应该依赖抽象,抽象不该依赖细节,细节应该依赖抽象 |
|
接口隔离原则 | 不应该依赖不需要的接口 | 类只实现其真正需要的接口避免多余依赖。 |
合成复用原则 | 优先使用对象组合,而不是通过继承来达到复用的目的 | |
迪米特法则 | 每一个软件单位对其他单位都只有最少的知识, 而且局限于哪些于本单位密切相关的软件单位 |
一个对象只与直接的朋友交互,而不与陌生人或间接的对象交互,从而降低对象之间的耦合度。 |
创建型模式
模式名称 | 定义 | 精简解释 |
---|---|---|
简单工厂模式 | 定义一个工厂类,它可以根据参数的不同返回不同类的实例, 被创建的实例通常都有共同的父类 |
|
工厂方法模式 | 定义一个用于创建对象的接口,但是让子类来决定将哪一个类实例化 | |
抽象工厂模式 | 提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类 | 接口创建相关对象系列,不用明确具体类。 |
建造者模式 | 将一个复杂对象的构建与它的表示分离,使得同样得构建过程可以创建不同的表示 | 分离构建和表示,相同构建过程能有不同结果。 |
原型模式 | 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象 | 把已有对象当作原型确定类型,通过复制该原型来快速创建新对象,方便创建相似对象 |
单例模式 | 确保一个类只有一个实例,并且提供一个全局访问点来访问这个唯一的实例 | 保证只有一个实例,有全局方式访问这个实例。 |
工厂模式
- 定义
工厂模式是一种创建对象的设计模式。它提供了一种创建对象的方式,将对象的创建和使用分离。就像是一个工厂,负责生产各种产品(对象),而客户(使用对象的代码)只需要从工厂获取产品,不需要关心产品是如何生产出来的。
- 角色
角色 | 定义 |
---|---|
抽象工厂 | 是抽象类或接口,声明创建系列产品的抽象方法,为具体工厂提供创建模板,规范创建接口,将创建逻辑抽象 |
具体工厂 | 抽象工厂子类,实现其抽象创建方法,负责创建特定产品或产品组,封装创建细节,使客户端与创建过程分离 |
抽象产品 | 抽象类或接口,定义产品公共行为属性,为具体产品提供统一规范与契约,确保客户端代码通用一致。 |
具体产品 | 抽象产品的实现类,继承或实现抽象产品,定义具体行为属性,由具体工厂创建,满足不同业务需求, 如绘图系统中不同形状类。 |
在图片工厂中:
- 抽象工厂(Abstract Factory)
- 在这段代码中,
ImageReaderFactory
是抽象工厂。它定义了一个创建ImageReader
对象的抽象方法createImage
,就像是一个工厂的蓝图,规定了工厂应该具备生产某种产品(这里是ImageReader
类型的对象)的功能,但没有具体说明如何生产。
- 在这段代码中,
- 具体工厂(Concrete Factory)
JpgReaderFactory
是具体工厂。它实现了ImageReaderFactory
接口,具体实现了createImage
方法。这个方法返回一个JpgReader
对象,就好比是一个实际的工厂,按照抽象工厂的要求,通过具体的生产流程(在这里是创建JpgReader
对象)来生产产品。
- 抽象产品(Abstract Product)
ImageReader
是抽象产品。它定义了一个抽象方法readImage
,这是产品的一个抽象功能,类似于产品说明书上的功能描述,但没有具体实现这个功能,只是规定了产品应该具备读取图像的功能。
- 具体产品(Concrete Product)
JpgReader
是具体产品。它实现了ImageReader
接口,具体实现了readImage
方法,提供了读取 Jpg 图像的具体功能。就像实际生产出来的具有特定功能的产品,满足了抽象产品所规定的读取图像的功能要求,并且针对 Jpg 图像有具体的实现。
建造者模式
-
定义
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示形式。该模式将对象的构建步骤封装在一个建造者对象中,通过指挥者对象来控制建造的过程,最终得到完整的复杂对象。
-
角色
角色 | 功能 |
---|---|
产品(Product) | 构建的复杂对象 |
抽象建造者(Builder) | 定义了构建产品的抽象接口,包括构建产品各个部件的方法以及返回最终产品的方法。这些方法一般是抽象的,具体的构建步骤由具体的建造者类来实现。 |
具体建造者(Concrete Builder) | 实现了抽象建造者接口,具体实现了构建产品各个部件的方法。它负责按照特定的顺序和规则构建产品的各个部件,并在构建完成后返回最终的产品。 |
指挥者(Director) | 它负责指挥建造者的构建过程,它知道如何调用建造者的方法来构建产品。指挥者本身不进行产品部件的构建,而是通过调用建造者的方法来完成构建过程。 |
结构型模式
模式名称 | 定义 | 精简解释 |
---|---|---|
适配器模式 | 将一个类的接口转换成客户希望的另一个接口, 适配器模式可以让不兼容的类一起工作 |
转换接口使不兼容类能协同工作。 |
桥接模式 | 将抽象部分与它的实现部分解耦,使得两者都能独立变化 | |
组合模式 | 组合多个对象组成树形结构以表示具有部分-整体关系的层次结构。 组合模式让客户端能统一对待单个对象和组合对象 |
|
装饰模式 | 动态的给一个对象增加一些职责。 | |
外观模式 | 为子系统中的一组接口提供一个统一的入口。 外观模式定义了一个高层接口。 此接口让这一子系统更容易使用 |
|
享元模式 | 运用共享技有效地支持大量细粒度对象的复用 | |
代理模式 | 给某一个对象提供一个代理或占位符,并由代理对象来控制原对象的访问 |
适配器模式
- 适配器模式(Adapter Pattern)是一种结构型设计模式。它将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。就像是一个转接头,把一种类型的插头(接口)转换为另一种类型的插头(接口),让电器(类)能够正常使用。
- 主要角色组成:目标抽象类、适配者类、适配器类
装饰模式
- 装饰模式主要包含以下角色:抽象构件(Component) 角色、 具体构件(Concrete Component) 角色、抽象装饰(Abstract Decorator)角色和具体装饰(Concrete Decorator)角色。
角色 | 定义 | 用例 |
---|---|---|
抽象构件 (Component) |
这是一个抽象类或者接口,它定义了被装饰对象的基本行为和属性。 它是装饰模式的基础,所有的具体构件和具体装饰类都要实现或者继承这个抽象构件。 |
在一个咖啡店饮品销售系统中,抽象构件可以是 Beverage 接口,它定义了计算饮品价格(cost() 方法)和获取饮品描述(getDescription() 方法)等基本行为。所有的咖啡和茶等饮品都要实现这个接口。 |
具体构件 (Concrete Component) |
这个角色实现了抽象构件接口,它是被装饰的具体对象,代表了最基本的功能。 具体构件是装饰的起点,装饰器会在其基础上添加新的功能。 |
在咖啡店饮品系统中,Espresso (浓缩咖啡)类可以是一个具体构件。它实现了 Beverage 接口,提供了浓缩咖啡本身的价格计算和描述功能。 |
抽象装饰 (Abstract Decorator) |
这个角色同样实现了抽象构件接口,它的主要作用是持有一个抽象构件(被装饰对象)的引用, 并且可以定义一些装饰类共有的方法和属性。 |
在咖啡店饮品系统中,BeverageDecorator 可以是一个抽象装饰类,它实现了 Beverage 接口,并且有一个 Beverage 类型的成员变量,用于保存被装饰的饮品对象。 |
具体装饰(Concrete Decorator) | 这个角色继承自抽象装饰类,它在抽象装饰类的基础上实现了具体的装饰功能。 具体装饰类可以通过重写抽象装饰类中的方法,在调用被装饰对象的方法前后添加自己的功能,比如添加新的配料或者服务等。 |
在咖啡店饮品系统中,MilkDecorator (牛奶装饰器)可以是一个具体装饰类。它继承自 BeverageDecorator ,在 cost() 方法中增加了牛奶的价格,在 getDescription() 方法中添加了牛奶的描述。 |
代理模式
-
代理(Proxy)模式的适用场景:
代理模式主要用于控制对对象的访问。它可以在访问对象时代替真实对象来执行一些附加操作,比如权限检查、懒加载(根据需要创建开销很大的对象)等。
当需要用比较通用和复杂的对象指针代替简单的指针的时候,也可以使用代理模式。 -
代理模式的主要角色有:抽象主题类、真实主题类和代理主题类。
角色 | 定义 |
---|---|
抽象主题类 (Subject) |
它是一个抽象类或接口,声明了真实主题类和代理主题类的共同接口,这样在客户端代码中就可以使用抽象主题类来统一地操作真实主题对象和代理主题对象。它定义了客户端所期望的操作方法,为代理模式提供了一个统一的服务访问接口。 |
真实主题类 (Real Subject) |
真实主题类实现了抽象主题类的接口,它包含了实际的业务逻辑,是真正完成操作的对象。 |
代理主题类 (Proxy Subject) |
代理主题类同样实现了抽象主题类的接口,它持有一个真实主题类的对象引用。代理主题类的主要作用是在客户端和真实主题类之间起到一个中介的作用。 它可以在调用真实主题类的方法之前或之后添加一些额外的操作,如权限验证、日志记录等。 |
外观模式
优点:降低耦合度
组合模式
组合模式主要包括以下角色:抽象组件、叶子构件、容器构件
核心概念
- 组件(Component):这是组合模式中的抽象角色,它为组合中的对象声明接口,既可以代表叶子节点对象,也可以代表容器对象(即包含子组件的对象)。它定义了一些操作接口,比如添加、删除子组件以及获取子组件等方法,但对于叶子节点,这些方法的默认实现可能是空操作或者抛出异常,因为叶子节点没有子组件。
- 叶子(Leaf):叶子节点是组合中的基本对象,它实现了组件接口,但不包含子组件。叶子节点代表树形结构中的最底层对象,其主要职责是完成自身特定的任务,并且不能再包含其他子对象。
- 容器(Composite):容器对象也是组件的一种实现,它可以包含多个子组件(叶子节点或其他容器)。容器对象实现了组件接口中与子组件管理相关的方法,如添加、删除和获取子组件等,以便构建和管理树形结构。容器对象的主要职责是协调和管理其子组件,将客户端的请求委派给子组件来处理,并根据需要返回合适的结果。
使用场景
- 树形结构数据表示:如文件系统、组织结构图、XML 或 HTML 文档的解析树等,这些场景中对象之间天然存在着 “部分 - 整体” 的层次关系,使用组合模式可以很好地对其进行建模和操作。
- 菜单和导航栏:在图形用户界面(GUI)开发中,菜单和导航栏通常具有多层次的结构,每个菜单项可以是一个叶子节点(执行具体操作的菜单项),也可以是一个包含子菜单的容器节点(下拉菜单或子导航栏),组合模式可以方便地管理和操作这些菜单结构,实现菜单的显示、隐藏、点击响应等功能。
- 部分与整体操作一致的场景:当需要对部分对象和整体对象进行统一的操作处理,并且希望忽略它们之间的类型差异时,组合模式非常合适。比如对一个公司的部门(包含子部门和员工)进行统计、查询等操作,无论是针对单个员工(叶子节点)还是整个部门(容器节点),都可以使用相同的操作接口。
详细说明(举例)
假设我们有一家公司,公司里有不同的部门,有些部门下面还设有子部门,而每个部门都有员工。这里,部门和员工就可以构成一个树形的层次结构,这就是组合模式可以应用的场景。
- 组件(Component):
- 首先定义一个抽象类或者接口,作为 “组件” 的统一规范,比如 “公司单位(CompanyUnit)”。它规定了一些通用的方法,比如 “展示信息(display)”,不管是部门还是员工,都应该能展示自己的信息。这就像是一个模板,所有具体的部门和员工都要遵循这个模板来实现自己的行为。
- 叶子(Leaf):
- 员工就是 “叶子节点”,他们是公司组织架构中最基础的单元,不能再包含其他子单位。每个员工都有自己的名字、职位等信息,并且实现了 “展示信息(display)” 这个方法,用来显示自己的具体信息,例如 “张三,软件工程师”。
- 容器(Composite):
- 部门就是 “容器节点”,一个部门可以包含多个员工(叶子节点)或者其他子部门(也是容器节点)。部门除了实现 “展示信息(display)” 方法来显示部门名称外,还实现了添加子单位(addUnit)、移除子单位(removeUnit)等方法,用于管理其下的员工和子部门。例如,研发部下面有几个小组,每个小组是一个子部门,同时研发部还有很多员工。研发部这个 “容器” 就可以通过 “addUnit” 方法把这些小组和员工都添加进来,形成一个完整的组织架构。
当公司管理层想要查看整个公司的组织架构和人员信息时,他们不需要分别针对部门和员工编写不同的查看代码。而是通过调用最顶层的公司组织(这也是一个 “容器”,包含了所有的部门)的 “display” 方法,这个方法会递归地调用每个子部门和员工的 “display” 方法,将整个公司的架构和人员信息以统一的方式展示出来。这就是组合模式的优势,它让客户端(这里就是公司管理层的查看操作)能够统一对待单个对象(员工)和组合对象(部门),使得操作更加简单、灵活,也便于对复杂的层次结构进行管理和维护。
行为型模式
模式名称 | 定义 | 精简解释 |
---|---|---|
职责链模式 | 避免将一个请求的发送者和接收者耦合在一起,让多个对象都有机会处理请求。 将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到由一个对象能处理它为止。 |
|
命令模式 | 将一个请求封装成一个对象,从而可用不同的请求将客户端参数化, 对请求排队或者记录请求日志,以及支持可撤销的操作 |
|
解释器模式 | 给定一个语言,定义它的的文法的一种表示,并定义一个解释器, 这个解释器使用该表示来解释语言中的句子 |
|
迭代器模式 | 提供一种顺序访问的聚合对象中的各个元素,而又不用暴露该对象的内部表示。 | |
中介者模式 | 定义一个对象来封装一系列对象的交互。 中介者模式使各个对象之间不需要显式的相互引用,从而使其耦合松散。 而且可用独立的改变他们之间的交互 |
|
备忘录模式 | 在不破坏封装的前提条件下,捕获一个对象的内部状态, 并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态 |
|
观察者模式 | 定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时, 其相关依赖对象皆得到通知并被自动更新 |
|
状态模式 | 允许一个对象在其内部状态改变时改变他的行为。 对象看起来似乎修改了它的类。 |
|
策略模式 | 定义一系列算法,将每个算法封装起来,并让它们可用相互替换, 策略模式让算法可以独立于使用它的客户而变化 |
|
模板方法模式 | 定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得 子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 |
|
访问者模式 | 表示一个作用于某对象结构中的各个元素的操作。 访问者模式可以让用户在不改变各元素的类的前提下定义作用于这些元素的新操作 |
状态模式
-
定义
状态模式(State Pattern)是一种行为设计模式,它允许对象在其内部状态改变时改变它的行为。从外部来看,就好像这个对象修改了它的类一样。这种模式将对象的行为封装在不同的状态类中,使得状态的转换和行为的执行更加清晰、易于维护和扩展。
并不完全符合开闭原则。
-
角色:环境、抽象状态、具体状态
-
实例
实例 | 状态描述 | 行为变化 |
---|---|---|
交通信号灯系统 | 交通信号灯有 红灯(Red) 状态、 绿灯(Green)状态 黄灯(Yellow)状态。 |
红灯时车辆停止、行人通过;绿灯时车辆通行、行人等待;黄灯是过渡状态,车辆视情况通过或停止,之后按交通规则切换状态,相应地改变车辆和行人的行为。 |
员工工作状态系统 | 空闲、忙碌、休息 | 空闲时接受任务进入忙碌状态;忙碌完成任务后可进入空闲或休息状态;休息结束回到空闲状态等待任务。 |
电梯运行状态系统 | 待机、洗涤、漂洗、脱水、完成状态。 | 待机时启动进入洗涤状态,然后依次经过漂洗、脱水状态,最后进入完成状态。出现故障则回到待机状态。 |
模板方法模式
- 定义
模板方法模式就像是一个制作某种产品的总流程说明书。这个说明书规定了大致的步骤框架,比如制作一个三明治,它会告诉你基本的流程是先准备面包,然后放馅料,最后盖上另一片面包。但是对于具体放什么馅料(是火腿、蔬菜还是鸡蛋等),这个说明书没有详细规定,而是让具体制作三明治的人(也就是子类)去决定。
- 方法:抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(Hook Method)等几种类型
观察者模式
- 在观察者模式中,观察者角色的更新确实是被动的。
- 被观察者(主题)在其状态发生改变时,有责任通知所有已注册的观察者进行更新。这是观察者模式的基本机制
评论区