[toc]
软件设计师笔记07_面向对象技术
下面的内容参考自《软件设计师教程(第5版)》 这本书的第7章 面向对象技术。
面向对象基础
客观世界由许多具体的事物、事件、概念和规则组成,这些均可被看成对象。
面向对象是一种非常实用的系统化软件开发方法,它以客观世界中的对象为中心,其分析和设计思想符合人们的思维方式,分析和设计的结果与客观世界的实际比较接近,容易被人们所接受。
面向对象基础的概念
面向对象有4个基础概念组成。
即 面向对象 = 对象 + 类 + 继承 + 消息通信
对象
在面向对象的系统中,对象是基本的运行时的实体,它既包括数据(属性),也包括作用于数据的操作(方法)。所以,一个对象把属性和方法封装为一个整体。
一个对象通常可由对象名、属性和方法3个部分组成。
在现实世界中,每个实体都是对象,如学生、汽车、电视机和空调等都是现实世界中的对象。每个对象都有它的属性和操作,如电视机有颜色、音量、亮度、灰度、频道等属性,可以有切换频道、增大/减低音量等操作。电视机的属性值表示了电视机所处的状态,而这些属性只能通过其提供的操作来改变。电视机的各组成部分,如显像管、电路板和开关等都封装在电视机机箱中,人们不知道也不关心电视机是如何实现这些操作的。
消息
对象之间进行通信的一种构造叫作消息。
当一个消息发送给某个对象时,包含要求接收对象去执行某些活动的信息。接收到信息的对象经过解释,然后予以响应。这种通信机制称为消息传递。发送消息的对象不需要知道接收消息的对象如何对请求予以响应。
类
类是在对象之上的抽象,它定义了一组相似的对象的共同特征。而对象是类的具体化,是类的实例。
一个类所包含的方法和数据描述一组对象的共同行为和属性。
类可以分为三种:实体类、接口类(边界类)和控制类。
- 实体类的对象表示现实世界中真实的实体,如人、物等。
- 接口类(边界类)的对象为用户提供一种与系统合作交互的方式,分为人和系统两大类。
- 其中人的接口可以是显示屏、窗口、Web 窗体、对话框、菜单、列表框、其他显示控制、条形码、二维码或者用户与系统交互的其他方法。
- 系统的接口涉及到把数据发送到其他系统,或者从其他系统接收数据。
- 控制类的对象用来控制活动流,充当协调者。
继承
继承是父类和子类之间共享数据和方法的机制。
这是类之间的一种关系,在定义和实现一个类的时候,可以在一个已经存在的类的基础上进行,并把这个类所定义的内容作为自己的内容,并加入若干新的内容。
如图表示了父类A和它的子类B之间的继承关系。 
一个父类可以有多个子类,这些子类都是父类的特例,父类描述了这些子类的公共属性和方法。一个子类可以继承它的父类中的属性和方法,另外子类中还可以定义自己的属性和方法。
多态
当对象在收到消息时,对象要予以响应。不同的对象收到同一消息可以产生完全不同的结果,这一现象称为多态。
多态的实现受到继承的支持,利用类的继承的层次关系,把具有通用功能的消息存放在高层次,而不同的实现这一功能的行为放在较低层次,在这些低层次上生成的对象能够给通用消息以不同的响应。
多态有如下几种
- 参数多态(不同类型参数多种结构类型)
- 包含多态(父子类型关系)
- 过载多态(类似于重载,一个名字不同含义)
- 强制多态(强制类型转换)
覆盖
覆盖是指子类在原有父类接口的基础上,用适合于自己要求的实现去置换父类中的相应实现。
即在子类中重定义一个与父类同名同参的方法
函数重载
函数重载与覆盖要区分开,函数重载与子类父类无关,且函数是同名不同参数。
即一个类中存在同名不同参数的多个函数。
封装
封装:一种信息隐蔽技术,其目的是使对象的使用者和生产者分离,也就是使其他开发人员无需了解所要使用的软件组件内部的工作机制,只需知道如何使用组件。
静态类型
静态类型是指一个对象的类型在编译时就确定了动态类型:指对象类型在运行时才能确定
静态绑定与动态绑定
绑定是一个把过程调用和响应调用所需要执行的代码加以结合的过程。在一般的程序设计语言中,绑定是在编译时进行的,称为静态绑定。动态绑定则是在运行时进行的,因此,一个给定的过程调用和代码的结合直到调用发生时才进行。
面向对象分析
面向对象分析的目的是为了获得对应用问题的理解。理解的目的是确定系统的功能、性能要求。
面向对象分析包含5个活动:认定对象、组织对象、对象间的相互作用、确定对象的操作、定义对象的内部信息。
认定对象
在应用领域中,按自然存在的实体确立对象。在定义域中,首先将自然存在的“名词”作为一个对象。
组织对象
分析对象间的关系,将相关对象抽象成类,其目的是为了简化关联对象,利用类的继承性建立具有继承性层次的类结构。
对象间的相互作用
描述各对象在应用系统中的关系,如一个对象是另一个对象的一部分,一个对象与其他对象间的通信关系等。这样可以完整地描述每个对象的环境,由一个对象解释另一个对象,以及一个对象如何生成另一个对象,最后得到对象的界面描述。
确定对象的操作
确定对象的操作,即对象的行为。操作包括创建、增加、删除、修改、查询等。
定义对象的内部信息
定义对象的内部信息,即对象的属性。属性包括数据项和操作项。数据是对象的状态信息,操作是对象的行为信息。
面向对象设计
面向对象设计是将面向对象分析所创建的分析模型转化为设计模型,其目标是定义系统构造蓝图。
面向对象设计的原则
(1)单一责任原则。就一个类而言,应该仅有一个引起它变化的原因。即,当需要修改某个类的时候原因有且只有一个,让一个类只做一种类型责任。
(2)开放-封闭原则。软件实体(类、模块、函数等)应该是可以扩展的,即开放的;但是不可修改的,即封闭的。
(3)里氏替换原则。子类型必须能够替换掉他们的基类型。即在任何父类可以出现的地方,都可以用子类的实例来赋值给父类型的引用。当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有是一个(is-a)关系。
(4)依赖倒置原则。抽象不应该依赖于细节,细节应该依赖于抽象。即高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
(5)接口分离原则。不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。即依赖于抽象,不要依赖于具体,同时在抽象级别不应该有对于细节的依赖。这样做的好处就在于可以最大限度地应对可能的变化。
上面是面向对象方法种的五大原则,除此之外,Robert C.Martin 还提出了以下几个原则。
- (6)重用发布等价原则。重用的粒度就是发布的粒度。
- (7)共同封闭原则。包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包产生影响,则将对该包中的所有类产生影响,而对于其他的包不造成任何影响。
- (8)共同重用原则。一个包中的所有类应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类。
- (9)无环依赖原则。在包的依赖关系图中不允许存在环,即包之间的结构必须是一个直接的五环图形。
- (10)稳定依赖原则。朝着稳定的方向进行依赖。
- (11)稳定抽象原则。包的抽象程度应该和其稳定程度一致。
面向对象程序设计
面向对象程序设计的实质是选用一种面向对象程序设计语言,采用对象、类及其相关概念所进行的程序设计。它的关键在于加入了类和继承性,从而进一步提高了抽象程度。
面向对象测试
面向对象测试可以分为四个层次:
- 算法层。用于测试类中定义的每个方法,相当于单元测试。
- 类层。用于测试封装在同一个类中的所有方法与属性之间的相互作用。类似模块测试。
- 模板层。用于测试一组协同工作的类之间的相互作用。相当于集成测试。
- 系统层。把各个子系统组装成完整的面向对象软件系统,在组装过程中同时进行测试。相当于系统测试。
UML(统一建模语言)
UML统一建模语言是面向对象软件的标准化建模语言。由于其简单、统一,又能够表达软件设计中的动态和静态信息,目前已经成为可视化建模语言事实上的工业标准。
从企业信息系统到基于 Web 的分布式应用,甚至严格的实时嵌入式系统都适合用UML来建模。它是一种富有表达力的语言,可以描述开发所需要的各种视图,然后以此为基础装配系统。
UML由3个要素构成: UML的基本构造块、支配这些构造块如何放置在一起的规则和运用与整个语言的一些公共机制。限于篇幅,下面仅对 UM,中的基本构造块进行讨论。UML,的词汇表包含3种构造块:事物、关系和图。事物是对模型中最具有代表性的成分的抽象;关系把事物结合在一起;图聚集了相关的事物。
UML由3个要素构成
- UML的基本构造块
- 支配这些构造块如何放置在一起的规则和运用
- 整个UML语言的一些公共机制
UML的3种基本构造块
- 事物(对模型中最具有代表性的成分的抽象)
- 关系(把事物结合在一起)
- 图(聚集了相关的事物)
UML中的事物
UML 中有4种事物:结构事物、行为事物、分组事物和注释事物。
结构事物
结构事物是指 UML 模型的静态部分,是模型中的名词,用来描述概念。如类、接口、用例、构件等。
如图所示 
行为事物
行为事物是指 UML 模型的动态部分,是模型中的动词,用来描述行为。如交互、活动等。

分组事物
分组事物是指 UML 模型的组织部分。最主要的分组事物是包,包是把元素组织在一起的一种机制。
注释事物
注释事物是指 UML 模型的解释部分,用来描述,说明模型中的元素。
UML中的关系
UML 中有4种关系:依赖、关联、泛化和实现。
依赖
依赖是两个事物间的语义关系,其中一个事物(独立事物)发生变化会影响另一个事物(依赖事物)的语义。在图形上,把一个依赖画成一条可能有方向的虚线
关联
关联是一种结构关系,它描述了一组链,链是对象之间的连接。
聚集是一种特殊类型的关联,它描述了整体和部分间的结构关系。
关联和聚集如图所示。 
泛化
泛化是一种特殊/一般关系,即子元素的对象可替代父元素的对象。用这种方法,子元素共享了父元素的结构和行为。
在图形上,把一个泛化关系画成一条带有空心箭头的实线,它指向父元素。
实现
实现是类元之间的语义关系,其中一个类元指定了由另一个类元保证执行的契约。
在两种情况下会使用实现关系:
- 一种是在接口和实现它们的类或构件之间;
- 另一种是在用例和实现它们的协作之间。
在图形上,把一个实现关系画成一条带有空心箭头的虚线,如图所示
UML中的关系的总结
- 依赖关系:一个事物发生变化影响另一个事物。
- 泛化关系:特殊/一般关系。
- 关联关系:描述了一组链,链是对象之间的连接。
- 聚合关系:整体与部分生命周期不同。
- 组合关系:整体与部分生命周期相同。
- 实现关系:接口与类之间的关系。
UML中的图
图是一组元素的图形表示,大多数情况下把图画成顶点(代表事物)和弧(代表关系)的连通图。
UML提供了 13 种图,分别是类图、对象图、用例图、序列图、通信图、状态图、活动图、构件图、组合结构图、部署图、包图、交互概览图和计时图。序列图、通信图、交互概览图和计时图均被称为交互图。
类图
类图通常展现一组对象、接口、协作和它们之间的关系。是系统的静态设计视图。
最常见的图就是类图。类图用于对系统的静态设计视图建模。
类图通常包含下面的内容:
- 类
- 接口
- 协作
- 依赖,泛化,关联关系

对象图
对象图:展现某一时刻一组对象及它们之间的关系,描述了在类图中所建立的事物的实例的静态快照。对象图一般包括对象和链。
如图所示 
用例图
用例图展现了一组用例、参与者和它们之间的关系。用例图用于对系统的静态用例视图进行建模。
用例图通常包含下面的内容:
- 用例:是指参与者完成的一系列操作。
- 参与者:是指人、硬件或其他系统可以扮演的角色。
- 用例之间的关系:是指参与者和用例之间的关联关系,用例与用例以及参与者与参与者之间的泛化关系。
如图所示 
序列图
序列图描述了以时间顺序组织的对象之间的交互活动。
通常把发起交互的对象放在左边,下级对象依次放在右边。然后,把这些对象发送和接收的消息沿垂直方向按时间顺序从上到下放置。这样,就提供了控制流随时间推移的清晰的可视化轨迹。
如图所示 
- 同步消息:调用者中止执行,等待控制权返回。需要等待返回消息,用实心三角箭头表示。
- 异步消息:发出消息后继续执行,不引起调用者阻塞,也不等待返回消息,由空心箭头表示。
- 返回消息:由从右到左的虚线箭头表示。
通信图
通信图不强调时间顺序,只强调事件之间的通信。

状态图
状态图描述单个对象在多个用例中的行为,包括简单状态和组合状态。

状态图中转换和状态是两个独立的概念,如图中方框代表状态,箭头上的代表触发事件,实心圆点表示起点和终点
活动图
活动图展现了在系统内从一个活动到另一个活动的控制流程。

- 活动图中的分岔和汇合线是一条水平粗线。
- 每个分岔的分支数代表了可同时运行的线程数。活动图中能够并行执行的是在一个分岔粗线下的分支上的活动
构件图
构件图展现了一组构件之间的组织和依赖关系。

部署图
部署图是用来对面向对象系统的物理方面建模的方法。它与构件图相关,通常一个结点包含一个或多个构件。其依赖关系类似于包依赖,因此部署组件之间的依赖是单向的类似于包含关系。

包图
包图是用于把模型本身组织成层次结构的通用机制,不能执行,展现由模型本身分解而成的组织单元以及其间的依赖关系。
包可以拥有其他元素,可以是类、接口、构件、结点、协作、用例和图,甚至是嵌套的其他包,
如图所示 
设计模式
基本概念
设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构。
设计模式的四个基本要素:
- 模式名称
- 问题:问题描述了应该在何时使用模式。
- 解决方案:解决方案描述了设计模式的具体内容
- 效果:描述了设计模式应用的效果以及使用设计模式需要权衡的问题。
简而言之,每一个设计模式都集中于一个特定的面向对象设计问题或设计要点,描述了什么时候使用它,在另一些条件下是否还能使用,以及使用的效果和如何取舍。
设计模式的类别
- 创建型模式:与对象的创建有关。
- 结构型模式:主要处理类和对象的组合
- 行为型模式:主要是描述类或者对象的交互行为


创建型设计模式
创建型设计模式抽象了实例化过程,它们帮助一个系统独立于如何创建、组合和表示它的那些对象。
其中一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象。
创建型设计模式的有:
- ①抽象工厂
- ②生成器
- ③工厂方法
- ④原型
- ⑤单例
Abstract Factory 抽象工厂设计模式
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式 适用于
- 一个系统要独立于它的产品的创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当提供一个产品类库,只想显示它们的接口而不是实现时。
抽象工厂模式的结构图

- AbstractFactory 声明一个创建抽象产品对象的操作接口。
- ConcreteFactory 实现创建具体产品对象的操作。
- AbstractProduct 为一类产品对象声明一个接口。
- ConcreteProduct 定义一个将被相应的具体工厂创建的产品对象,实现AbstractProduct接口。
- Client仅使用由AbstractFactory和AbstractProduct类声明的接口。
Builder 生成器设计模式
生成器模式是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
生成器模式适用于:
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
生成器模式的结构图

- Builder为创建一个Product对象的各个部件指定抽象接口。
- ConcreteBuilder实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口。
- Director构造一个使用Builder接口的对象。
- Product 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。包含定义组成组件的类,包括将这些组件装配成最终产品的接口。
Factory Method 工厂方法设计模式
工厂方法设计模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。从而使一个类的实例化延迟到其子类。
工厂方法设计模式适用于:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
结构图

- Product定义工厂方法所创建的对象的接口。
- ConcreteProduct实现Product接口。
- Creator声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的默认实现,它返回一个默认的ConcreteProduct对象,可以调用工厂方法以创建一个Product对象。
- ConcreteCreator重定义工厂方法以返回一个ConcreteProduct实例。
Prototype 原型设计模式
原型设计模式是一种创建型设计模式,它通过复制一个已经存在的实例来创建新的实例,而不是通过实例化类来创建。
原型设计模式适用于:
- 当一个系统应该独立于它的产品创建、组合和表示时。
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
结构图

- Prototype声明一个克隆自身的接口。
- ConcretePrototype实现一个克隆自身的操作。
- Client让一个原型克隆自身从而创建一个新的对象。
Singleton 单例设计模式
单例设计模式是一种创建型设计模式,它确保一个类仅仅只有一个实例,并提供一个全局访问点来访问该实例。
单例设计模式适用于:
- 当类只能有一个实例,并且客户可以从一个众所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
结构图

- Singleton 声明一个静态方法以返回唯一的实例。
- Client 使用Singleton类的静态方法来获取唯一的实例。
创建型设计模式的对比
创建型设计模式主要解决"对象的创建"问题,它们抽象了实例化过程,帮助系统独立于如何创建、组合和表示它的那些对象。从实现机制上,创建型设计模式可以分为两类核心方法:
第一类:基于继承的类创建型模式
这类模式通过继承机制来改变被实例化的类,典型代表是 工厂方法(Factory Method) 模式。
其主要思想是定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而使一个类的实例化延迟到其子类。这种方式的主要缺点是:仅为了改变产品类就可能需要创建一个新的子类,且这种改变可能产生级联效应(例如,如果产品的创建者本身是由工厂方法创建的,那么也必须重定义它的创建者)。
第二类:基于对象组合的对象创建型模式
这类模式将实例化委托给另一个对象,通过对象组合而非继承来实现系统参数化。 抽象工厂(Abstract Factory)、生成器(Builder)和原型(Prototype) 模式是这类方法的典型代表,它们都涉及创建一个专门负责创建产品对象的"工厂对象"。但它们的实现机制和适用场景各有不同:
- 抽象工厂模式:通过工厂对象产生一系列相关或相互依赖的产品对象,适用于需要创建产品家族且希望产品之间保持一致性的场景。
- 生成器模式:通过工厂对象使用相对复杂的协议,逐步构建一个复杂产品,适用于产品构建过程与其表示分离,且相同构建过程需支持不同表示的场景。
- 原型模式:通过工厂对象复制原型对象来创建新产品,其中工厂对象和原型对象是同一个对象,适用于需要避免创建与产品类层次平行的工厂类层次,或当类的实例只能有几种不同状态组合的场景。
除上述两类外,还有一种特殊的创建型模式——单例模式。它确保一个类仅有一个实例,并提供一个全局访问点来访问该实例。单例模式既可以通过继承实现(如饿汉式),也可以通过对象组合实现(如懒汉式中的双重检查锁定),其核心目的是控制对象的创建数量而非参数化系统。
各类创建型模式的核心区别
- 工厂方法:将对象创建延迟到子类,通过继承实现。
- 抽象工厂:创建相关对象家族,无需指定具体类。
- 生成器:关注复杂对象的构建过程和表示的分离。
- 原型:通过复制现有对象创建新对象。
- 单例:确保对象的唯一性和全局访问。
选择创建型模式时,应根据系统的具体需求、对象创建的复杂度、产品变化的方式等因素综合考虑,以实现高内聚、低耦合、易扩展的设计目标。
结构型设计模式
结构型设计模式涉及如何组合类和对象以获得更大的结构。
类的结构型设计模式通常采用继承机制来组合接口或实现。一个简单的例子是采用多重继承方法将两个以上的类组合成一个类,结果这个类包含了所有父类的性质。这一模式尤其有助于多个独立开发的类库协同工作。
对象的结构型设计模式不是对接口和实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法。因为可以在运行时刻改变对象组合关系,所以对象组合方式具有更大的灵活性,而这种机制用静态类组合是不可能实现的。
结构型设计模式的有
- ①适配器
- ②桥接
- ③组合
- ④装饰
- ⑤外观
- ⑥享元
- ⑦代理
Adapter 适配器设计模式
适配器设计模式是一种结构型设计模式,它允许将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器设计模式适用于:
- 当你想使用一个已经存在的类,而它的接口不符合你的需求时。
- 当你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作时。
- 当你想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口时。对象适配器可以适配它的父类接口。
如图所示是适配器设计模式的结构图。

- Target 定义 Client 使用的与特定领域相关的接口。
- Client 与符合 Target 接口的对象协同。
- Adaptee 定义一个已经存在的接口,这个接口需要适配。
- Adapter 对 Adaptee 的接口与 Target 接口进行适配。
Bridge 桥接设计模式
桥接设计模式可以将抽象部分与其实现部分分离,使它们都可以独立地变化
桥接设计模式适用于以下情况:
- 当你想将一个类的接口与它的实现分离,使它们都可以独立地变化时。
- 当你想在不影响客户端代码的情况下,动态地切换实现时。
- 当你想在多个维度上进行扩展时,例如,一个类有多个变化的维度,每个维度都可以独立地变化。
桥接模式的结构如图所示。

- Abstraction 定义抽象类的接口,维护一个指向Implementor 类型对象的指针。
- RefinedAbstraction 扩充由Abstraction 定义的接。
- Implementor 定义实现类的接口,该接口不一定要与 Abstraction 的接口完全一致:事实上这两个接口可以完全不同。一般来说,Implementor 接口仅提供基本操作,而Abstraction 定义了基于这些基本操作的较高层次的操作。
- ConcreteImplementor 实现 Implementor 接口并定义它的具体实现。
Composite 组合设计模式
组合设计模式是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端可以一致地使用单个对象和组合对象。
组合设计模式适用于以下情况:
- 当你想表示对象的“部分-整体”层次结构时。
- 当你想客户端可以忽略组合对象与单个对象的不同,统一地使用它们时。
组合设计模式的结构如图所示。

- Component为组合中的对象声明接口;在适当情况下实现所有类共有接口的默认行为;声明一个接口用于访问和管理 Component 的子组件;(可选)在递归结构中定义一个接口,用于访问一个父组件,并在合适的情况下实现它。
- Leaf在组合中表示叶结点对象,叶结点没有子结点;在组合中定义图元对象的行为。Composite 定义有子组件的那些组件的行为;存储子组件;在Component 接口中实现与子组件有关的操作。
- Client 通过 Component 接口操纵组合组件的对象。
Decorator 装饰设计模式
装饰设计模式是一种结构型设计模式,它允许你动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
装饰设计模式适用于以下情况:
- 当你想在不改变对象接口的情况下,动态地给一个对象添加一些额外的职责时。
- 当你想给一个对象添加一些基本功能,而又不希望用子类来实现时。
- 当你想在运行时刻动态地添加或删除对象的职责时。
装饰设计模式的结构如图所示。

- Component 定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent 定义一个具体的对象,也可以给这个对象添加一些职责。
- Decorator 装饰抽象类,继承了 Component,从外类来扩展 Component 类的功能,但对于 Component 来说,是无需知道 Decorator 的存在的。
- ConcreteDecorator 具体的装饰对象,给 Component 添加一些职责。
Facade 外观设计模式
外观设计模式是一种结构型设计模式,它提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观设计模式适用于以下情况:
- 当你想为一个复杂的子系统提供一个简单的接口时。
- 当你想将子系统的功能进行分层,每个层都有一个外观类来协调其功能时。
外观设计模式的结构如图所示。

- Facade 知道哪些子系统类负责处理请求;将客户的请求代理给适当的子系统对象。
- Subsystem classes 实现子系统的功能;处理有 Facade 对象指派的任务;没有 Facade 的任何相关信息,即没有指向 Facade 的指针。
Flyweight 享元设计模式
享元设计模式是一种结构型设计模式,它通过共享相同状态的对象来减少内存使用量。可以有效地支持大量细粒度的对象。
享元模式适用于以下情况:
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,所以对于概念上明显有别的对象,标识测试将返回真值。
享元设计模式的结构如图所示。

Proxy 代理设计模式
代理设计模式是一种结构型设计模式,它允许你为其他对象提供一个代理,以控制对这个对象的访问。
代理模式适用于以下情况:
- 当你想在访问一个对象时添加一些额外的操作时。
- 当你想控制对一个对象的访问时。
- 当你想在访问一个对象时延迟加载该对象时。
代理设计模式的结构如图所示。

- Subject 定义 RealSubject 和 Proxy 的共用接口,这样就在任何使用 RealSubiect 的地方都可以使用 Proxy。
- RealSubject 定义 Proxy 所代表的实体。
- Proxy 保存一个引用使得代理可以访问实体;提供一个与 Subiect 的接口相同的接口,使代理可以用来代替实体。
结构型设计模式的对比
Adapter适配器模式 与 Bridge桥接模式 的区别:
- Adapter适配器模式:解决已存在的两个接口不匹配问题,不需要重新设计,用于已有代码。
- Bridge桥接模式:将抽象与实现分离,使两者可独立变化,在设计初期使用。
Composite组合设计模式 与 Decorator装饰设计模式 的区别:
- Composite组合设计模式:将多个对象组合成树形结构,表示"部分-整体"关系,重点在统一处理。
- Decorator装饰设计模式:动态给对象添加功能,避免子类激增,重点在功能扩展。
Decorator 装饰设计模式 与 Proxy代理设计模式 的区别:
- Decorator装饰设计模式:动态添加功能,可递归组合,编译时不确定全部功能。
- Proxy代理设计模式:控制对实体的访问,不能动态添加功能,强调访问关系。
其他结构型模式的核心特点:
- Facade(外观):为复杂子系统提供简单统一的入口,简化使用。
- Flyweight(享元):共享对象减少内存,分离内部/外部状态。
选择依据:
接口不匹配用Adapter模式,抽象与实现分离用Bridge模式,部分-整体结构用Composite模式,动态扩展功能用Decorator模式,简化子系统用Facade模式,共享对象用Flyweight模式,控制访问用Proxy模式。
行为设计模式
行为模式涉及算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。这些模式刻画了在运行时难以跟踪的、复杂的控制流。它们将用户的注意力从控制流转移到对象间的联系方式上来。
其中行为类模式使用继承机制在类间分派行为。行为对象模式使用对象复合而不是继承。
行为设计模式的有
- ①责任链
- ②命令
- ③解释器
- ④迭代器
- ⑤中介者
- ⑥备忘录
- ⑦观察者
- ⑧状态
- ⑨策略
- ⑩模板方法
- ⑪访问者
Chain of Responsibility 责任链设计模式
责任链设计模式是一种行为型设计模式,它可以使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
Chaimn ofResponsibility 模式适用于以下条件:
- 有多个的对象都可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
- 在不明确指定接收者的情况下向多个对象中的一个提交一个请求。
- 可处理一个请求的对象集合应被动态指定。
责任链设计模式的结构如图所示。

- Handler 定义一个处理请求的接口;(可选)实现后继链。
- ConcreteHandler 处理它所负责的请求;可访问它的后继者:如果可处理该请求,就处理它,否则将该请求转发给后继者。
- Client 向链上的具体处理者(ConcreteHandler)对象提交请求。
Command 命令设计模式
命令设计模式是一种行为型设计模式,它将请求封装成一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式适用于以下情况:
- 当你想在不同的时间指定请求、将请求排队或记录请求日志时。
- 当你想支持可撤销的操作时。
命令设计模式的结构如图所示。

- Command 声明一个执行操作的接口。
- ConcreteCommand 定义一个将接收者绑定于动作的绑定;实现 Execute 操作,负责调用接收者的相应操作。
- Client 创建一个 ConcreteCommand 对象并设置其接收者。
- Invoker 要求该命令执行这个请求。
- Receiver 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
Interpreter 解释器设计模式
解释器设计模式是一种行为型设计模式。给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式适用于当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,以下情况效果最好:
- 该文法简单。对于复杂的发文,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无须构建抽象语法树即可解释表达式,这样可以节省空间还可能节省时间。
- 效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。不过,即使在这种情况下,转换器仍然可用该模式实现。
解释器设计模式的结构如图所示。

- AbstractExpression声明了一个程序的解释操作,这个接口为抽象语法树中所有的结点所共享。
- TemmminalExpression 实现与文法中的终结符相关联的解释操作;一个句子中的每个终结符需要该类的一个实例。
- NonterminalExpression 对文法中的每一条规则都需要一个 NonterminalExpression 类;为每个符号都维护一个 AbstractExpression 类型的实例变量;为文法中的非终结符实现解释操作。
- Context 包含解释器之外的一些全局信息。
- Client 创建一个表示该文法的抽象语法树的结构;该树由 TerminalExpression 和 NonterminalExpression 对象组成。
Iterator 迭代器设计模式
迭代器设计模式是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
迭代器模式适用于以下情况:
- 当你需要访问一个聚合对象的内容而无需暴露它的内部表示时。
- 当你需要为聚合对象提供多种遍历方式时。
- 当你需要为遍历不同的聚合结构提供一个统一的接口时。
迭代器设计模式的结构如图所示。

- Iterator 定义访问和遍历聚合元素的接口。
- ConcreteIterator 实现 Iterator 接口;对该聚合遍历并跟踪当前位置。
- Aggregate 定义创建相应迭代器对象的接口。
- ConcreteAggregate 实现创建相应迭代器的操作,该操作返回一个 ConcreteIterator 实例。
- Client 使用迭代器接口来遍历聚合对象。
Mediator 中介者设计模式
中介者设计模式是一种行为型设计模式,它定义了一个中介对象,该中介对象封装了一组对象之间的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
中介者模式适用于以下情况:
- 当一组对象以定义良好但是复杂的方式进行通信时。产生的相互依赖关系结构混乱且难以理解。
- 当想定制一个分布在多个类中的行为,而又不想生成太多的子类时。
中介者设计模式的结构如图所示。

- Mediator 定义一个接口,该接口用于与各同事对象通信。
- ConcreteMediator 实现 Mediator 接口;协调各同事对象的交互。
- Colleague 定义一个接口,该接口用于与中介者通信。
- ConcreteColleague 实现 Colleague 接口;与中介者通信。
Mediator 备忘录设计模式
备忘录设计模式是一种行为型设计模式,它允许在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态。
备忘录模式适用于以下情况:
- 当你需要保存一个对象在某一个时刻的状态,这样以后可以恢复到这个状态时。
- 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
备忘录设计模式的结构如图所示。

- Memento(备忘录)存储原发器对象的内部状态,原发器根据需要决定备忘录存储原发器的哪些内部状态;防止原发器以外的其他对象访问备忘录。
- Origimator(原发器)创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态。
- Caretaker(管理者)负责保存好备忘录;不能对备忘录的内容进行操作或检查。
Observer 观察者设计模式
观察者设计模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象。当这个目标对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式适用于以下情况:
- 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时。
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁时。
观察者设计模式的结构如图所示。

- Subject(日标)知道它的观察者,可以有任意多个观察者观察同个日标;提供注册和删除观察者对象的接口。
- Observer(观察者)为那些在目标发生改变时需获得通知的对象定义一个更新接口。
- ConcreteSubiect(具体目标)将有关状态存入各 ConcreteObserver 对象;当它的状态发生改变时,向它的各个观察者发出通知。
- ConcreteObserver(具体观察者)维护一个指向 ConcreteSubiect对象的引用;存储有关状态,这些状态应与目标的状态保持一致;实现 Observer 的更新接口,以使自身状态与目标的状态保持一致。
State 状态设计模式
观察者设计模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
状态设计模式适用于以下情况:
- 对象的行为决定于它的状态,开且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得开发者可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象独立变化。
状态设计模式的结构如图所示。

- Context(上下文)定义客户感兴趣的接口;维护ConcreteState子类的实例,这个实例定义当前状态。
- State(状态)定义一个接口以封装与 Context 的一个特定状态相关的行为。
- ConcreteState(具体状态子类)每个子类实现与 Context 的一个状态相关的行为。
Strategy 策略设计模式
观察者设计模式是一种行为型设计模式,它定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。
策略设计模式适用于以下情况:
- 需要使用一个算法的不同变体。例如,定义一些反映不同空间的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
- 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条件语句。
结构如图所示。

- Strategy(策略)定义所有支持的算法的公共接口。Context 使用这个接口来调用某 ConcreteStrategy 定义的算法。
- ConcreteStrategy(具体策略)以 Stategy 接口实现某具体算法。
- Context(上下文)用一个 ConcreteStrategy 对象来配置;维护一个对 Strategy 对象的引用;可定义一个接口来让 Strategy 访问它的数据。
Template Method 模板方法设计模式
模板方法设计模式是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法设计模式适用于以下情况:
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
- 控制子类扩展。模板方法只在特定点调用“钩子操作”,这样就只允许在这些点进行扩展。
结构如图所示。

- AbstractClass(抽象类)定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤;实现模板方法,定一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在 AbstractClass 或其他对象中的操作。
- ConcreteClass(具体类)实现原语操作以完成算法中与特定子类相关的步骤。
Visitor 访问者设计模式
访问者设计模式是一种行为型设计模式,表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。
适用于以下情况:
- 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
结构如图所示。

- ConcreteVisitor(具体访问者)实现每个有 Visitor 声明的操作,每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor 为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
- Element(元素)定义以一个访问者为参数的 Accept 操作。
- ConcreteElement(具体元素)实现以一个访问者为参数的Accept 操作。
- ObjectStmucture(对象结构)能枚举它的元素:可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个组合或者一个集合,如一个列表或一个无序集合。
行为设计模式的对比
处理请求的模式:
- 责任链:将请求沿着处理者链传递,直到被处理,解耦请求发送者与接收者。
- 命令:将请求封装为对象,支持参数化、队列化、日志记录和撤销操作。
- 中介者:用一个中介对象封装多对象交互,减少对象间直接依赖,降低耦合。
状态与行为的关系:
- 状态:对象状态改变时行为也改变,将状态封装为独立类,避免复杂条件判断。
- 策略:定义算法族,封装后可互相替换,算法独立于使用它的客户。
- 模板方法:定义算法骨架,将可变步骤延迟到子类,控制子类扩展点。
对象交互模式:
- 观察者:一对多依赖,一个对象改变通知多个观察者,适用于事件处理系统。
- 迭代器:提供访问聚合对象元素的方法,不暴露内部结构,支持多种遍历方式。
- 访问者:在不改变对象结构的前提下,定义作用于元素的新操作,分离数据结构与算法。
特殊功能模式:
- 备忘录:在不破坏封装的前提下保存和恢复对象状态,实现撤销功能。
- 解释器:定义语言文法,解释表达式,适用于简单语言的解释执行。
选择依据
处理请求传递用责任链,请求封装用命令,对象通信解耦用中介者;状态变化影响行为用状态,算法替换用策略,固定流程扩展用模板方法;一对多通知用观察者,遍历聚合用迭代器,结构不变添加新操作用访问者。
各个设计模式的应用场景
创建型设计模式的应用场景 
结构型设计模式应用场景 
行为型设计模式应用场景 

