十. 面向对象技术
1. 面向对象基本概念
(1)对象与类相关概念
在面向对象的系统中,对象是基本的运行时的实体,它既包括数据(属性),也包括作用于数据的操作(行为)。一个对象把属性和行为封装为一个整体。封装是一种信息隐蔽技术,它的目的是使对象的使用者和生产者分离,使对象的定义和实现分开。一个对象通常由对象名(ID)、属性和行为(方法)三部分组成。
一个类定义了一组大体上相似的对象。一个类所包含的方法和数据描述一组对象的共同行为和属性。类是在对象之上的抽象,对象是类的具体化,是类的实例。接口是一种特殊的类,它只有方法定义没有实现。
类可以分为三种:实体类、接口类(边界类)、控制类。
- 实体类:实体类的对象表示现实世界中真实的实体,如人、物等。
- 接口类(边界类):接口类的对象为用户提供一种与系统合作交互的方式,分为人和系统两大类,其中人的接口可以是显示屏、窗口、Web窗体、对话框、菜单、列表框、其它显示控制、条形码、二维码或者用户与系统交互的其它方法。系统接口涉及到把数据发送到其它系统,或者从其它系统接收数据。
- 控制类:控制类的对象用来控制活动流,充当协调者。
例题1:
在面向对象的系统中,对象是运行时实体,其组成部分不包括();一个类定义了一组大体相似的对象,这些对象共享()。
A.消息 B.行为(操作) C.对象名 D.状态
A.属性和状态 B.对象名和状态 C.行为和多重度 D.属性和行为
解析1:
先看 AD 选项的两个概念。对象之间进行通信的一种构造叫作消息,是动态的。消息是异步通信的,而消息传递是指接收到信息的对象经过解释,然后予以响应。状态是一组属性对应确定值。 BC 选项是对象的组成部分,状态本质上也是属性,因此第一个空选择 A 项。对象共享属性和行为,第二个空选 D。
例题2:
在面向对象方法中,将逻辑上相关的数据以及行为绑定在一起,使信息对使用者隐蔽称为()。当类中的属性或方法被设计为 private 时,()可以对其进行访问。
A.抽象 B.继承 C.封装 D.多态
A.应用程序中所有方法
B.只有此类中定义的方法
C.只有此类中定义的 public 方法
D.同一个包中的类中定义的方法
解析2:
将属性和行为绑定在一起,使用者和生产者分离,这是封装,第一个空选 C。private 代表私有访问控制符号,也就是只允许自己访问,即同一类中定义的方法可以访问。还有 public 代表公有,应用程序中所有方法均可访问,默认 protected 代表受保护的,同一个包中的类中定义的方法可以访问。因此第二个空选 B。
(2)继承与泛化相关概念
继承是父类和子类之间共享(复用)数据和方法的机制。一个父类可以有多个子类,父类描述了这些子类的公共属性和方法。一个子类可以继承它的父类中的属性和方法,这些属性和方法在子类中不必定义,子类也可以定义自己的属性和方法。
例如,父类动物中的方法 call(),也称为抽象方法,没有具体实现。猫类继承了方法 call(),且有具体实现 call(){喵},狗类同样,call(){汪},这称为重置/覆盖,即在子类中重新定义父类中已经定义的方法。另一个概念叫作重载,指同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。
例题:
在面向对象方法中,()是父类和子类之间共享数据和方法的机制。子类在原有父类接口的基础上,用适合于自己要求的实现去置换父类中的相应实现称为()。
A.封装 B.继承 C.覆盖 D.多态
A.封装 B.继承 C.覆盖 D.多态
解析:
继承是父类和子类之间共享数据和方法的机制,子类也可以定义自己的属性和方法,也可以覆盖父类中的相应实现。因此选择 BC。
(3)多态与动态绑定相关概念
在收到消息时,对象要予以响应。不同的对象收到同一消息可以产生不同的结果,这一现象称为多态。如猫对象收到消息 call,产生喵的结果;狗对象收到消息 call,产生汪的结果,这就是多态。
如果消息直接发送给一个类,然后由类在运行时决定由哪个对象响应,这就是动态绑定,或者说根据接收对象的具体情况将请求的操作与实现的方法进行连接。与之对应的,在编译阶段决定,称为静态绑定。
多态有四类:参数多态、包含多态、过载多态、强制多态。
过载多态:同一个名字(操作符、函数名)在不同的上下文中所代表的含义不同。
参数多态:应用广泛,最纯的多态。
包含多态:同样的操作可用于一个类型及其子类型。包含多态一般需要进行运行时的类型检查。
强制多态:编译程序通过语义操作,把操作对象的类型强行加以变换,以符合函数或操作符的要求。
例题1:
在面向对象方法中,不同对象收到同一消息可以产生完全不同的结果,这一现象称为()。在使用时,用户可以发送一个通用的消息,而实现的细节则由接收对象自行决定。
A.接口 B.继承 C.覆盖 D.多态
解析1:
不同的对象收到同一消息可以产生不同的结果,这一现象称为多态。
例题2:
在下列机制中,()是指过程调用和响应调用所需执行的代码在运行时加以结合;而()是过程调用和响应调用所需执行的代码在编译时加以结合。
A.消息传递 B.类型检查 C.静态绑定 D.动态绑定
A.消息传递 B.类型检查 C.静态绑定 D.动态绑定
解析2:
如果消息直接发送给一个类,然后由类在运行时决定由哪个对象响应,这就是动态绑定。与之对应的,在编译阶段决定,称为静态绑定。
(4)概念汇总
例题1:
在某销售系统中,客户采用扫描二维码进行支付。若采用面向对象方法开发该销售系统,则客户类属于()类,二维码类属于()类。
A.接口 B.实体 C.控制 D.状态
A.接口 B.实体 C.控制 D.状态
解析1:
根据三种类的定义可知,客户属于实体类,二维码属于接口类。
例题2:
在面向对象方法中,继承用于()。
A.在已存在的类的基础上创建新类。
B.在已存在的类中添加新的方法。
C.在已存在的类中添加新的属性。
D.在已存在的状态中添加新的状态。
解析2:
继承是父类和子类之间共享(复用)数据和方法的机制,因此是在父类的基础上创建新类。
例题3:
()多态是指操作(方法)具有相同的名称、且在不同的上下文中所代表的含义不同。
A.参数 B.包含 C.过载 D.强制
解析3:
根据四类多态的定义可知,过载多态是操作(方法)具有相同的名称、且在不同的上下文中所代表的含义不同。
2. 面向对象分析
面向对象方法和结构化开发的流程类似,有面向对象分析、面向对象设计、面向对象程序设计、面向对象测试等步骤。
其中,面向对象分析的目的是为了获得对应用问题的理解,确定系统的功能和性能需求。
面向对象分析包含四个活动:
- 认定对象
- 组织对象
- 对象间的相互作用
- 基于对象的操作
例题:
面向对象分析的目的是为了获得对应用问题的理解,其主要活动不包括()。
A.认定并组织对象
B.描述对象间的相互作用
C.面向对象程序设计
D.确定基于对象的操作
解析:
面向对象程序设计是面向对象方法中的一个环节,不属于面向对象分析的活动。
3. 面向对象设计
面向对象设计是将分析阶段所创建的分析模型转化为设计模型,其目标是定义系统构造蓝图。
面向对象设计 7 大原则:
- 单一责任原则:设计目的单一的类。就一个类而言,应该仅有一个引起它变化的原因。
- 开放-封闭原则:对扩展开放,对修改封闭。
- 里氏替换原则:子类可以替换父类。
- 依赖倒置原则:要依赖于抽象,而不是具体实现;针对接口编程,不要针对实现编程。
- 接口分离原则:使用多个专门的接口比使用的单一的总接口要好(设计目的单一的接口)。
- 组合重用原则:要尽量使用组合,而不是继承关系达到重用目的。
- 迪米特原则(最少知识法则):一个对象应当对其它对象有尽可能少的了解。
其它原则:(对包而言)
- 重用发布等价原则:重用的粒度就是发布的粒度。
- 共同封闭原则:包中的所有类对于同一性质的变化应该是共同封闭的。一个变化若对一个包产生影响,则将对该包里的所有类产生影响,而对于其它的包不造成任何影响。
- 共同重用原则:一个包里的所有类应该是共同重用的。如果重用了包里的一个类,那么就要重用包中的所有类。
- 无环依赖原则:在包的依赖关系图中不允许存在环,即包之间的结构必须是一个直接的无环图形。
- 稳定依赖原则:朝着稳定的方向进行依赖。
- 稳定抽象原则:包的抽象程度应该和其稳定程度一致。
例题1:
进行面向对象设计时,就一个类而言,应该仅有一个引起它变化的原因,这属于()设计原则。
A.单一责任 B.开放-封闭 C.接口分离 D.里氏替换
解析1:就一个类而言,应该仅有一个引起它变化的原因,单一责任原则的定义。
例题2:
进行面向对象系统设计时,针对包中的所有类对于同类性质的变化;一个变化若对一个包产生影响,则对该包中的所有类产生影响,而对于其它的包不造成任何影响。这属于()设计原则。
A.共同重用 B.开放-封闭 C.接口分离 D.共同封闭
解析2:
一个变化若对一个包产生影响,则对该包中的所有类产生影响,而对于其它的包不造成任何影响,这是共同封闭原则的定义。
4. UML
(1)UML 概念
UML 是统一建模语言,是目前业界普遍接受的面向对象方法。
UML 分为结构图与行为图两类。
结构图:(静态)
- 类图:一组对象、接口、协作和它们之间的关系。
- 对象图:也叫对象快照。一组对象以及它们之间的关系,描述了在类图中所建立的事物的实例的静态快照。
- 包图:描述类或其它UML如何组织成包,以及包之间的依赖关系。
- 组合结构图
- 构件图:一组构件之间的组织和依赖,专注于系统的静态实现视图。
- 部署图:运行处理结点以及构件的配置,给出体系结构的静态实施视图。软硬件之间的映射。
- 制品图
行为图:(动态)
- 用例图:用例、参与者以及它们之间的关系。
- 顺序图:也叫序列图,场景的图像化表示,以时间顺序组织的对象间的交互活动。
- 通信图:强调收发消息的对象之间的组织结构。
- 定时图
- 状态图:展现了一个状态机,由状态、转换、事件和活动组成。
- 活动图:类似于程序流程图。专注于系统的动态视图,一个活动到另一个活动的流程。并行。
- 交互概览图
例题:
在UML图中,()图用于展示所交付系统中软件组件和硬件之间的物理关系。
A.类 B.组件 C.通信 D.部署
解析:
展示组件和硬件的映射是部署图的特点。
(2)UML 关系
UML 中有 4 种关系:依赖、关联、泛化和实现。(这四种关系常出现于类图中)
依赖:两个事物间的语义关系,一个事物发生变化影响到另一个事物。
关联:一种结构关系,描述了一组链,链是对象之间的连接。在关联上可以标注重复度和角色。
关联关系又包含一个特殊类型:聚集。聚集可以继续细分为:聚合和组合。
聚合:整体与部分生命周期不同。
如,大雁与雁群的关系,学生与班级的关系,均是聚合关系。 雁群散开了,大雁仍然存在;班级毕业了,学生仍然存在。
组合:整体与部分生命周期相同。
如,翅膀与大雁的关系,大雁死去后翅膀也不复存在。
泛化:一种特殊/一般关系。
实现:接口与类之间的关系。
在用例图中,也存在三种常见的关系:包含、扩展、泛化。
包含(必选): 提取出的公共用例称为抽象用例,而把原始用例称为基本用例或基础用例。当可以从两个或两个以上的用例中提取公共行为时,应该使用包含关系表示。
如上述图示,在学习课程和课程测试时都需要检查权限,所有检查权限是它们的公共行为,抽取出来作为公共用例(抽象用例),并且检查权限是一定要进行的,也就是执行完基本用例后要去执行公共用例,因此包含关系是必选的。
扩展(可选):如果一个用例明显地混合了两种或两种以上的不同场景,即根据情况可能发生多种分支,则可以将这个用例分为一个基本用例和一个或多个扩展用例,这样使描述可能更加清晰。
如上图所示,学院进行课程测试时需要花费学习币,如果学员本身就有学习币则无需充值,如果没有的话则需要充值,因此是可选的。常见的描述有:如果....则....; 若....则.... 等。
泛化(必选):当多个用例共同拥有一种类似的结构和行为的时候,可以将它们的共性抽象成为父用例,其它的用例作为泛化关系中的子用例。在用例的泛化关系中,子用例是父用例的一种特殊形式,子用例继承了父用例所有的结构、行为和关系。
如上图所示,泛化关系是将多个用例抽象成一个父用例,当学员进行课程注册时会先经过课程注册父用例,然后去进一步选择是电话注册还是网上注册,去选择其中一个子用例进行注册,课程注册就像一个框架,具体的执行是后续的子用例。因此泛化关系也是必选的。
例题:
UML 中关联是一个结构关系,描述了一组链。两个类之间()关联。
A.不能有多个
B.可以有多个由不同角色标识的
C.可以有任意多个
D.多个关联必须聚合成一个
解析:
根据关联的定义可知,两个类之间可以有多个不同角色标识的关联。
(3)类图与对象图
类图:描述一组类、接口、协作和它们之间的关系。在面向对象(OO)系统的建模中,最常见的图就是类图。类图给出了系统的静态设计视图,活动类的类图给出了系统的静态进程视图。
对象图:描述一组对象及它们之间的关系。对象图描述了在类图中所建立的事物实例的静态快照。和类图一样,这些图给出系统的静态设计视图或静态进程视图,但它们是从真实案例或原型案例的角度建立的。
区分多重度:
- 1:表示一个集合中的一个对象对应另一个集合中 1 个对象。
- 0..*/*:表示一个集合中的一个对象对应另一个集合中的 0 个或多个对象。(可以不对应)
- 1..*/*:表示一个集合中的一个对象对应另一个集合中的 1 个或多个对象。(至少对应一个)
- 0..1:表示一个集合中的一个对象对应另一个集合中的 0 个或 1 个对象。(可以不对应)
例如上图所示,一个书籍列表可以对应 0 本或多本书籍,一本书籍可以对应 0 个或 1 个借阅记录,要么借出去了要么没借出去,一个借阅记录列表可以对应 0 个或多个借阅记录。
例题:
UML 图中,对象图展现了(),()所示对象图与下图所示类图不一致。
A.一组对象、接口、协作和它们之间的关系。
B.一组用例、参与者以及它们之间的关系。
C.某一时刻一组对象以及它们之间的关系。
D.以时间顺序组织的对象之间的交互活动。
解析:
对象图描述一组对象及它们之间的关系,第一个空选 C。其中,A 项是类图的描述,B 项是用例图的描述,D 项是顺序图的描述。图中的多重度为一对多,这个多代表可以是 0 个也可以是 1 个也可以是 n 个,因此第二个空选 D,D 项表示多对一,并且多在对象 A 这边。
(4)用例图
用例图:描述一组用例、参与者及它们之间的关系。
关系包括:包含、扩展、泛化。
用例建模的流程:
- 识别参与者(必须)
- 合并需求获得用例(必须)
- 细化用例描述(必须)
- 调整用例模型(可选)
例题:
在 UML 用例图中,参与者表示()。
A.人、硬件或其它系统可以扮演的角色
B.可以完成多种动作的相同用户
C.不管角色的实际物理用户
D.带接口的物理系统或硬件设计
解析:
参与者表示人、硬件或其它系统可以扮演的角色。用例通常是对功能的描述,一般是名词加动词或动词加名词的形式。
(5)顺序图与通信图
顺序图是一种交互图,交互图展现了一种交互,它由一组对象或参与者以及它们之间可能发送的消息构成。交互图专注于系统的动态视图,顺序图是强调消息的时间次序的交互图。
通信图也是一种交互图,它强调收发消息的对象或参与者的结构组织。顺序图和通信图表达了类似的基本概念,但它们所强调的概念不同,顺序图强调的是时序,通信图强调的是对象之间的组织结构(关系)。通信图中没有对象生命线和控制焦点。
例题:
如下所示的图为 UML 的(),用于展示某汽车导航系统中()。Mapping 对象获取汽车当前位置(GPS Location)的消息为()。
A.类图 B.组件图 C.通信图 D.部署图
A.对象之间的消息流及其顺序
B.完成任务所进行的活动流
C.对象的状态转换及其事件顺序
D.对象之间消息的时间顺序
A.1:getGraphic() B.2:getCarPos() C.1.1:CurrentArea() D.2.1:getCarLoaction()
解析:
图中展示了对象之间的结构关系和顺序,没有生命线,是通信图。Mapping 对象获取汽车当前位置的消息为 2.1:getCarLoaction(),从图中可以直接得到。因此选择 CAD。
(6)活动图
活动图将进程或其它计算结构展示为计算内部一步步的控制流和数据流。活动图专注于系统的动态视图。它对系统的功能建模和业务流程建模特别重要,并强调对象间的控制流程。活动图中具有并发的特点。
(7)状态图
状态图描述一个状态机,它由状态、转移、事件和活动组成。状态图给出了对象的动态视图,它对于接口、类或协作的行为建模尤为重要,而且它强调事件导致的对象行为,这非常有助于对反应式系统建模。
例题1:
如下所示的 UML 状态图中,()时,不一定会离开状态 B。
A.状态 B 中的两个结束状态均达到
B.在当前状态为 B2 时,事件 e2 发生
C.事件 e2 发生
D.事件 e1 发生
解析1:
当且仅当当前状态为 B2,且事件 e2 发生时,才会进入 C3 状态,如果当前不在 B2,即使发生了 e2 也不会进入 C3,所以如果仅发生事件 e2,不一定会离开状态 B,选 C。
例题2:
以下关于 UML 状态图的叙述中,不正确的是()。
A.活动可以在状态内执行,也可以在迁移时执行
B.若事件触发一个没有特定监护条件的迁移,则对象离开当前状态
C.迁移可以包含事件触发器、监护条件和状态
D.事件触发迁移
解析2:
事件触发一个没有特定监护条件的迁移,对象不一定会离开当前状态,正如上述图中的事件 e2,只有当前状态在 B2 时才会离开,否则不会,需要有特定的前置条件。其它三项均正确,选 B。
(8)构件图
构件图描述一个封装的类和它的接口、端口,以及由内嵌的构件和连接件构成的内部结构。构件图用于表示系统的静态设计实现视图。对于由小的部件构建大的系统来说,构件图很重要。构件图是类图的变体。
可以将需接口理解为锁,供接口理解为开锁的钥匙。
(9)部署图
部署图描述对运行时的处理节点及在其中生存的构件(制品)的配置。部署图给出了架构的静态部署视图,通常一个节点包含一个或多个构件。部署图是用来对面向对象系统的物理方面建模的方法。
其中,<<artifact>>表示制品。
5. 设计模式
“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。”设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构。
创建型 | 结构型 | 行为型 | |
类 | 工厂方法模式(Factory Method) | 适配器模式(Adapter) | 模板方法模式(Template Method) 解释器模式(Interpreter) |
对象 | 抽象工厂模式(Abstract Factory) 原型模式(Prototype) 单例模式(Singleton) 生成器模式(Bulider) | 桥接模式(Bridge) 组合模式(Composite) 装饰模式(Decorator) 外观模式(Facade) 享元模式(Flyweight) 代理模式(Proxy) | 职责链模式(Chain of Responsibility) 命令模式(Command) 迭代器模式(Iterator) 中介者模式(Mediator) 备忘录模式(Memento) 观察者模式(Observer) 状态模式(State) 策略模式(Strategy) 访问者模式(Visitor) |
其中,类设计模式即可以是类模式也可以是对象模式。
(1)创建型设计模式
创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建、组合和表示它的那些对象。
抽象工厂模式(Abstract Factory)
意图:提供一个接口,可以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
其中:
- AbstractFactory:抽象工厂,声明创建抽象产品对象的操作接口。
- ConcreteFactory:具体工厂,执行生成抽象产品的方法,生成一个具体的产品。
- AbstractProduct:抽象产品,为一种产品声明接口。
- Product:具体产品,定义具体工厂生成的具体产品的对象,实现产品接口。
- Client:客户,使用 AbstractFactory 和 AbstractProduct 生成对象。
适用性:
- 一个系统要独立于它的产品的创建、组合和表示时。
- 一个系统要由多个产品系统中的一个来配置时。
- 当要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当提供一个产品类库,只想显示它们的接口而不是实现时。
工厂模式(Factory Method)
意图:定义一个创建对象的接口,但由子类决定需要实例化哪一个类。工厂方法使得子类实例化的过程推迟。
其中:
- Product:产品角色定义产品的接口。
- ConcreteProduct:真实的产品,实现接口 Product 的类。
- Creator:工厂角色声明工厂方法(Factory Method),返回一个产品。
- ConcreteCreator:真实的工厂实现 Factory Method 工厂方法,由客户调用,返回一个产品实例。
适用性:
- 当一个类希望由它的子类来指定它所创建的对象时。
- 当一个类不知道它所必须创建的对象的类时。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化时。
原型模式(Prototype)
意图:用原型实例指定创建对象的类型,并且通过拷贝这个原型来创建新的对象。
其中:
- Prototype:抽象原型类,定义具有克隆自己的方法的接口。
- ConcretePrototype:具体原型类,实现具体的克隆方法。
- Client:客户。
适用性:
- 当一个系统应该独立于它的产品创建、构成和表示时。
- 当要实例化的类是在运行时指定时,例如通过动态加载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些。
单例模式(Singleton)
意图:保证一个类只有一个实例,并提供一个访问它的全局访问点。
其中:
- Singleton:单例,提供一个 instance 的方法,让客户可以使用它的唯一实例。内部实现只生成一个实例。
适用性:
- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户无须更改代码就能使用一个扩展的实例时。
生成器模式(Bulider)
意图:将一个复杂类的表示与其构造相分离,使得相同的构建过程能够得出不同的表示。
其中:
- Builder:抽象建造者,为创建一个 Product 对象各个部件指定抽象接口,把产品的生产过程分解为不同的步骤,从而使具体建造者在具体的建造步骤上具有更多弹性,从而创造出不同表示的产品。
- ConcreteBuilder:具体建造者,实现 Builder 接口,构造和装配产品的各个部件定义并明确它所创建的表示,提供一个返回这个产品的接口。
- Director:指挥者,构建一个使用 Builder 接口的对象。
- Product:表示被构建的复杂对象。ConcreteBuilder 创建该产品的内部表示并定义它的装配过程。包含定义组成组件的类,包括将这些组件装配成最终产品的接口。
适用性:
- 当构造过程必须允许被构造的对象有不同的表示时。
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
总结(5 种)
设计模式名称 | 简要说明 | 速记关键字 |
抽象工厂(Abstract Factory) | 提供一个接口,可以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。 | 生产成系列对象 |
工厂模式(Factory Method) | 定义一个创建对象的接口,但由子类决定需要实例化哪一个类。工厂方法使得子类实例化的过程推迟。 | 动态生产对象 |
生成器模式(Builder) | 将一个复杂类的表示与其构造相分离,使得相同的构建过程能够得出不同的表示。 | 复杂对象构造 |
原型模式(Prototype) | 用原型实例指定创建对象的类型,并且通过拷贝这个原型来创建新的对象。 | 克隆对象 |
单例模式(Singleton) | 保证一个类只有一个实例,并提供一个访问它的全局访问点。 | 单实例 |
例题1:
()模式将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。以下()情况适合选用该模式。
① 抽象复杂对象的构建步骤
② 基于构建过程的具体实现构建复杂对象的不同表示
③ 一个类仅有一个实例
④ 一个类的实例只能有几个不同状态组合中的一种
A.生成器(Builder) B.工厂模式(Factory Method) C.原型(Prototype) D.单例(Singleton)
A.①② B.②③ C.③④ D.①④
解析1:
将一个复杂对象的构建与其表示分离是生产者模式的特征,该模式适用于对复杂对象的构建过程以及其不同表示,因此选 AA。
例题2:
某快餐厅主要制作并出售儿童套餐,一般包括主餐(各类披萨)、饮料和玩具,其餐品种类可能不同,但制作过程相同。前台服务员(Waiter)调度厨师制作套餐。欲开放一软件,实现该制作过程,设计如下所示类图。该设计采用()模式将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。其中,()构造一个使用 Builder 接口的对象。该模式属于()模式,该模式适用于()情况。
A.生成器(Builder) B.抽象工厂(Abstract Factory) C.原型(Prototype) D.工厂方法(Factory Method)
A.PizzaBuilder B.SpicyPizzaBuilder C.Pizza D.Waiter
A.创建型对象 B.结构型对象 C.行为型对象 D.结构型类
A.当一个系统应该独立于它的产品创建、构成和表示时。
B.当一个类希望由它的子类来指定它所创建的对象时。
C.当要强调一系列相关的产品对象的设计以便进行联合使用时。
D.当构造过程必须允许被构造的对象有不同的表示时。
解析2:
题干中提到餐品种类不同,但制作过程相同,其实已经可以得出采用的设计模式是生成器模式;指挥者构建一个使用 Builder 接口的对象,该系统中的指挥者是 Waiter;生成器模式是创建型模式,适用于构造过程必须允许被构造的对象有不同的表示时。因此选 ADAD。其中,第四个空中,A 项适用于抽象工厂或原型模式,B 项适用于工厂模式,C 项也适用于抽象工厂模式。
(2)结构型设计模式
结构型模式涉及如何组合类和对象以获得更大的结构。
桥接模式(Bridge)
意图:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
其中:
- Abstraction:定义抽象类的接口,维护一个指向 Implementor 类型对象的指针。
- RefinedAbstraction:扩充的抽象类,扩充由 Abstraction 定义的接口。
- Implementor:定义实现类的接口,该接口不一定要与 Abstraction 的接口完全一致;事实上这两个接口可以完全不同。一般来说,Implementor 接口仅提供基本操作,而 Abstraction 定义了基于这些基本操作的较高层次的操作。
- ConcreteImplementor:实现 Implementor 接口并定义它的具体实现。
适用性:
- 不希望在抽象和它的实现部分之间有一个固定的绑定关系。
- 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。
- 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。
- 想对客户完全隐藏抽象的实现部分。
- 有许多类要生成的类层次结构。
- 想在多个对象间共享实现,但同时要求客户并不知道这一点。
组合模式(Composite)
意图:将对象组合成树型结构以表示 “整体-部分” 的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
其中:
- Component:为组合中的对象声明接口。
- Leaf:叶部件,在组合中表示叶节点对象,叶节点没有子节点。定义组合中原有接口对象的行为。
- Composite:定义有子组件的那些组件的行为。在 Component 接口中实现与子部件相关的操作。
- Client:客户,通过 Component 接口操纵组合组件的对象。
适用性:
- 想表示对象的部分-整体层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
适配器模式(Adapter)
意图:将一个类的接口转换成用户希望得到的另一种接口。它使原本不相容的接口得以协同工作。
其中:
- Target: 定义客户要用的特定领域的接口。
- Adapter:对 Adaptee 的接口与 Target 接口进行适配。
- Adaptee:定义一个已经存在的接口,这个接口需要适配。
适用性:
- 想使用一个已经存在的类,而它的接口不符合要求。
- 想创建一个可以复用的类,该类可以与其它不相关的类或不可预见的类协同工作。
- 想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
装饰模式(Decorator)
意图:动态地给一个对象添加一些额外的职责。它提供了用子类扩展功能的一个灵活的替代,比派生一个子类更加灵活。
其中:
- Component:部件,定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent:具体部件,定义具体的对象,Decorator 可以给这个对象添加一些额外的职责。
- Decorator:装饰抽象类,维护一个指向 Component 对象的指针,并且定义一个与 Component 接口一致的接口。
- ConcreteDecorator:向组件添加职责。
适用性:
- 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责。
- 当不能采用生成子类的方式进行扩充时。
外观模式(Facade)
意图:定义一个高层接口,为子系统中的一组接口提供一个一致的外观,从而简化了该子系统的使用。
其中:
- Facade:外形类,知道哪些子系统类负责处理请求,将客户的请求传递给相应的子系统对象处理。
- Subsystem:子系统类,实现子系统的功能,处理由 Facade 传来的任务。子系统不用知道 Facade,在任何地方也没有引用 Facade。
适用性:
- 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入 Facade 将这个子系统与客户以及其它的子系统分离,可以提高子系统的独立性和可移植性。
- 当需要构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点。
享元模式(Flyweight)
意图:提供支持大量细粒度对象共享的有效方法。
其中:
- Flyweight:抽象轻量级类,声明一个接口,通过它可以接受外来的状态并作出处理。
- ConcreteFlyweight:具体轻量级类,实现 Flyweight 接口。
- UnsharedConcreteFlyweight:不共享的具体轻量级类, UnsharedConcreteFlyweight 对象常常将 ConcreteFlyweight 对象作为子节点。
- FlyweightFactory:轻量级工厂,创建并且管理 Flyweight 对象,确保合理地共享 Flyweight。
- Client:维持一个对 Flyweight 的引用。
适用性:
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于外部标识。
代理模式(Proxy)
意图:为其它对象提供一种代理以控制对这个对象的访问。
其中:
- Proxy:维护一个引用使得代理可以访问实体,提供一个与 Subject 的接口相同的接口,使代理可以用来代替实体。
- Subject:抽象实体接口,为 RealSubject 实体和 Proxy 代理定义相同的接口,使得 RealSubject 在任何地方都可以使用 Proxy 来访问。
- RealSubject:真实对象,定义 Proxy 代理的实体。
适用性:
- 远程代理:负责对请求及其参数编码,向不同地址空间中的实体发送已编码的请求。
- 虚拟代理:可以缓存实体的其它信息,以便延迟对它的访问。
- 保护代理:检查调用者的请求是不是有所需的权限。
总结(7 种)
设计模式名称 | 简要说明 | 速记关键字 |
桥接模式(Bridge) | 将抽象部分与它的实现部分分离,使它们都可以独立地变化。 | 继承树拆分 |
组合模式(Composite) | 将对象组合成树型结构以表示 “整体-部分” 的层次结构,使得用户对单个对象和组合对象的使用具有一致性。 | 树形目录结构 |
适配器模式(Adapter) | 将一个类的接口转换成用户希望得到的另一种接口。它使原本不相容的接口得以协同工作。 | 转换接口 |
装饰模式(Decorator) | 动态地给一个对象添加一些额外的职责。它提供了用子类扩展功能的一个灵活的替代,比派生一个子类更加灵活。 | 附加职责 |
外观模式(Facade) | 定义一个高层接口,为子系统中的一组接口提供一个一致的外观,从而简化了该子系统的使用。 | 对外统一接口 |
享元模式(Flyweight) | 提供支持大量细粒度对象共享的有效方法。 | 文章共享文字对象 |
代理模式(Proxy) | 为其它对象提供一种代理以控制对这个对象的访问。 | 快捷方式 |
例题:
假设现在要创建一个 Web 应用框架,基于此框架能够创建不同的具体 Web 应用,比如博客、新闻网站和网上商店等;并可以为每个 Web 应用创建不同的主题样式,如浅色或深色等。这一业务需求的类图设计适合采用()模式(如下图)。其中()是客户程序使用的主要接口,维护对主题类型的引用。此模式为(),体现的最主要的意图是()。
A.观察者 B.访问者 C.策略 D.桥接
A.WebApplication B.Blog C.Theme D.Light
A.创建型对象模式 B.结构型对象模式 C.行为型类模式 D.行为型对象模式
A.将抽象部分与其实现部分分离,使它们都可以独立地变化。
B.动态地给一个对象添加一些额外的职责。
C.为其它对象提供一种代理以控制对这个对象的访问。
D.将一个类的接口转换成客户希望的另外一个接口。
解析:
根据题干描述可知,该框架分为了两部分,分别是 Web 应用和主题样式,因此适合桥接模式,将抽象部分与它的实现部分分离,使它们都可以独立地变化 。而客户在使用时,应当使用的是 Web 应用,所以 WebApplication 是客户程序使用的主要接口。桥接模式是结构型模式。因此选 DABA。第四个空中,B 项是装饰模式,C 项是代理模式,D 项是适配器模式。
(3)行为型设计模式
行为模式涉及算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。
观察者(Observer)
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
其中:
- Subject:观察目标,可以有任意多个观察者观察同一个目标,提供注册和删除观察者对象的接口。
- Observer:观察者,为那些在目标发生改变时需获得通知的对象定义一个更新接口。
- ConcreteSubject:具体目标,将有关状态存入各 ConcreteObserver 对象,当它的状态发生改变时,向它的各个观察者发出通知。
- ConcreteObserver:具体观察者,维护一个指向 ConcreteSubject 对象的引用,存储有关状态,且与目标状态一致,实现 Observer 的更新接口,以使自身状态与目标保持一致。
适用性:
- 当一个抽象模型有两个方面,一个方面依赖于另一个,将二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变时。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁,即不希望这些对象是紧耦合的。
访问者(Visitor)
意图:表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。
其中:
- Visitor:访问者,为该对象结构中 ConcreteElement 的每一个类声明一个 Visit 操作。
- ConcreteVisitor:具体访问者,实现每个有 Visitor 声明的操作,每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。
- Element:元素,定义以一个访问者为参数的 Accept 操作。
- ConcreteElement:具体元素 ,实现以一个访问者为参数的 Accept 对象。
- ObjectStructure:对象结构,能枚举它的元素,可以提供一个高层的接口以允许该访问者访问它的元素,可以是一个组合或一个集合,如一个列表或无序集合。
适用性:
- 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作污染这些对象类。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
策略(Strategy)
意图:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。
其中:
- Strategy:策略,定义所有支持的算法的公共接口。Context 使用这个接口来调用某 ConcreteStrategy 定义的算法。
- ConcreteStrategy:具体策略,以 Strategy 接口实现某具体算法。
- Context:上下文,用一个 ConcreteStrategy 对象来配置,维护一个对 Strategy 对象的引用,可定义一个接口来让 Strategy 访问它的数据。
适用性:
- 许多相关的类仅仅是行为有异。策略提供了一种用多个行为中的一个行为来配置一个类的方法。
- 需要使用一个算法的不同变体。
- 算法使用客户不应该知道的数据。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条件语句。
状态(State)
意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
其中:
- Context:上下文,定义客户感兴趣的接口,维护一个 ConcreteState 子类的实例,这个实例定义当前状态。
- State:状态,定义一个接口以封装与 Context 的一个特定状态相关的行为。
- ConcreteState:具体状态子类,每个子类实现与 Context 的一个状态相关的行为。
适用性:
- 一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
中介者(Mediator)
意图:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
其中:
- Mediator:中介者,定义一个接口用于各 Colleague 对象通信。
- ConcreteMediator:具体中介者,通过协调各同事对象实现协作行为,了解并维护它的各个同事。
- Colleague:同事(客户)类,每一个同时类对象在需要与其它同事通信的时候与它的中介者通信。
总结(11 种)
设计模式名称 | 简要说明 | 速记关键字 |
职责链模式(Chain of Responsibility) | 通过给多个对象处理请求的机会,减少请求的发送者与接收者之间的耦合。将接收对象链接起来,在链中传递请求,直到有一个对象处理这个请求。 | 传递职责 |
命令模式(Command) | 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,将请求排队或记录请求日志,支持可撤销的操作。 | 日志记录,可撤销。 |
解释器模式(Interpreter) | 给定一种语言,定义它的文法表示,并定义一个解释器,该解释器用来根据文法表示来解释语言中的句子。 | 虚拟机的机制 |
迭代器模式(Iterator) | 提供一种方法来顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。 | 数据库数据集 |
中介者模式(Mediator) | 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 | 不直接引用 |
备忘录模式(Memento) | 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,从而可以在以后将该对象恢复到原先保存的状态。 | 可恢复 |
观察者模式(Observer) | 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 | 联动 |
状态(State) | 允许一个对象在其内部状态改变时改变它的行为。 | 状态变成类 |
策略模式(Strategy) | 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。 | 多方案切换 |
模板方法模式(Template Method) | 定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义算法的某些特定步骤。 | 文档模板填空 |
访问者(Visitor) | 表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。 | 数据与操作分离 |
例题1:
自动售货机根据库存、存放货币量、找零能力、所选项目等不同,在货币存入并进行选择时具有如下行为:交付产品不找零;交付产品并找零;存入货币不足而不提供任何产品;库存不足而不提供任何产品。这一业务需求适合采用()模式设计实现,其类图如下图所示,其中()是客户程序使用的主要接口,可用状态来对其进行配置。此模式为(),体现的最主要的意图是()。
A.观察者 B.状态 C.策略 D.访问者
A.Vending Machine State B.Buy C.Vending Deposit State D.Vending Stock State
A.创建型对象模式 B.结构型对象模式 C.行为型类模式 D.行为型对象模式
A.当一个对象状态改变时所有依赖它的对象得到通知并自动更新。
B.在不破坏封装性的前提下,捕获对象的内部状态并在对象之外保存。
C.一个对象在其内部状态改变时改变其行为。
D.将请求封装为对象从而可用使用不同的请求对客户进行参数化。
解析1:
图示中的类有明显的 State 字样,因此可用推断出是状态图,或者根据题干描述,存入货币时会有不同的行为,而状态图是允许一个对象在其内部状态改变时改变它的行为,也可以推断出是状态模式。Buy 是客户购买时使用的应用程序,而应用程序使用的接口应该是右侧的 Vending Machine State。状态模式是行为型对象模式,意图是一个对象在其内部状态改变时改变其行为。因此选BADC。第四个空中,A 项时观察者模式,B 项是备忘录模式,D 项是命令模式。
例题2:
假设现在要创建一个简单的超市销售系统,顾客将毛巾、饼干、酸奶等物品(Item)加入购物车(Shopping Cart),在收银台(Checkout)人工(Manual)或自动(Auto)地将购物车中每个物品的价格汇总到总价格后结账。这一业务需求的类图设计如下图所示,采用了()设计模式。其中()定义一个 Checkout 对象为参数的 accept 操作,由子类实现此 accept 操作。此模式为(),适用于()。
A.观察者 B.访问者 C.策略 D.桥接
A.Item B.Shopping Cart C.Checkout D.Manual和Auto
A.创建型对象模式 B.结构型对象模式 C.行为型类模式 D.行为型对象模式
A.必须保存一个对象在某一时刻的(部分)状态。
B.想在不明确指定接收者的情况下向多个对象中的一个提交一个请求。
C.需要对一个对象结构中的对象进行很多不同的并且不相关的操作。
D.在不同的时刻指定、排列和执行请求。
解析2:
图中没有明显的标记词汇,因此分析题干,后续提到了定义一个 Checkout 对象为参数的 accept 操作,这是访问者模式的特征,并且 accept 定义在 element 中,应该是图中的 Item。访问者模式是行为型对象模式,适用于需要对一个对象结构中的对象进行很多不同的并且不相关的操作。因此选 BADC。第四个空中,A 项是备忘录模式,B 项是责任链模式,D 项是命令模式。
面向对象技术部分的内容至此结束,后续如果有补充或修改会直接添加。