目录
10.4.3 Abstract Factory 抽象工厂模式
10.6.2 Chain of Responsibility 职责链模式
10.6.11 Template Method 模板方法模式
10.1 基本概念
-
对象
-
对象是基本的运行实体,一个对象把属性、行为封装为一个整体,与其他对象间有清晰的边界,有良好定义的行为、可扩展性。对象位置、数量,由使用的对象或系统确定
-
一个对象通常由对象名/对象ID、属性/数据、方法/操作/行为组成。所有属性(通常是静态的)及属性的当前值(通常是动态的)表示对象所处的状态,而这些属性只能通过对象提供的方法改变
-
对象名/对象ID:为了区分一个对象与其它所有对象,通常会给它起一个“标识”
-
行为:是对象根据它的状态改变、消息传递所采取的行动、所作出的反应,行为代表其外部可见的活动。操作代表一个类提供给它的对象的一种服务
-
对象属性、方法的可访问性:由访问权限修饰关键字指定(C++、Java均支持)
-
private:私有的,对内可见,只有类内部定义的方法才可访问
-
protected:保护的,对外不可见,对继承子类可见,使用继承时具有继承关系的子类可访问
-
public:公有的,对外、对内均可见,所有类使用者均可访问。Java中缺省的访问权限指定默认访问权限,是不采用任何访问权限修饰关键字,指定在同一个package中或子类中访问的成员
-
-
面向对象
-
面向对象 = 对象 + 分类 + 继承 + 通过消息的通信
-
接口:一种特殊的类,只有方法定义,没有实现
-
方法重置/覆盖:继承关系中子类重新定义父类中已定义的方法;在定义和实现一个类的时候,可以在一个已经存在的类的基础上进行,子类可继承其父类中的属性和操作作为自己的内容而不必自己定义,子类中也可以用更具体地方式实现从父类继承来的方法
-
方法重载:同一个类中的两个/两个以上的方法,名字相同而参数个数/参数类型不同,每个方法实现自己的特定行为。方法名字、参数都一样,而仅仅返回值类型不同,这不是重载
-
类型检查:验证操作接收的是否为合适的类型数据以及赋值是否合乎类型要求。强、弱类型是编程语言的特性,指在编译/运行时对变量的类型进行严格检查、松散检查
-
-
消息
-
消息:对象间通信的一种构造,消息是异步通信的,不同类的对象通过消息相互通信
-
消息传递:消息传递是对象间的通信机制,即一个消息发送给某个对象时,包含要求接收对象去执行某些活动的信息。接收到信息的对象经解释后予以响应。发送消息的对象不需要知道接收消息的对象如何对请求予以响应
-
-
绑定
-
绑定:一个把过程调用、响应调用所需要执行的代码加以结合的过程
-
静态绑定:绑定在编译时进行
-
动态绑定:绑定在运行时进行 ,一个给定的过程调用、代码的结合直到调用发生时才进行。动态绑定和类的继承、多态相联系。继承关系中子类是父类的一个特例,父类对象可以出现的地方,子类对象也可以出现。因此在运行过程中,当一个类对象发送通用消息请求服务时,它无需知道所调用方法的特定子类的实现,要根据接收对象的具体情况将请求的操作与实现的方法进行连接, 即动态绑定,以实现在这些低层次上生成的对象给通用消息以不同的响应
-
-
封装
-
隐藏对象属性、实现细节,仅对外公开接口(信息隐藏技术)
-
使对象的使用者和生产者分离,对象的使用者需要使用对象中的属性、方法时,需通过对象进行
-
开发人员无需了解所使用的软件组件内部的工作机制,只需知道如何使用组件,即组件提供的功能及接口
-
-
类
-
理解
-
一个类定义了一组大体上相似的对象,一个类所包含的方法、数据描述一组对象的共同行为、属性,这些对象共享这些行为、属性
-
类是在对象之上的抽象,对象是类的具体化,是类的实例(类写实例)
-
—组对象的抽象定义,把一组对象的共同特征加以抽象并存储在一个类中
-
在类定义时,属性声明private的目的是实现数据隐藏,以免意外更改
-
-
分类
-
实体类:对象表示现实世界中真实的实体,如人、物等,负责数据、业务逻辑,是应用领域中的核心类,一般用于保存系统中的信息,提供针对这些信息的相关处理行为
-
边界类/接口类:其对象为用户提供一种与系统合作交互的方式,是系统内对象和系统外参与者的联系媒介。分为人、系统两大类,人的接口可以是显示屏、窗口、Web窗体、对话框、菜单、列表框、其他显示控制、条形码、二维码或用户与系统交互的其他方法。如,销售系统中客户通过二维码支付,二维码类即属于接口类。系统接口涉及到把数据发送到其他系统,或从其他系统接收数据
-
控制类:控制类的对象用来控制活动流,负责协调实体类和接口类的交互
-
表示控制对象、实体对象、边界对象的图形
-
-
-
继承
-
继承与泛化,复用机制。模仿现实世界中继承关系的一种类之间的关系,是超类/父类和子类之间共享数据、方法的机制,is-like-a表示两个类之间的继承关系
-
在定义和实现一个类的时候,可在一个已存在的类的基础上进行,把这个已经存在的类所定义的内容作为自己的内容,并加入新内容
-
一个父类可有多个子类,这些子类都是父类的特例,父类描述了这些子类的公共属性、操作。一个子类可继承它父类中的属性、操作,这些属性、操作在子类中不必定义。子类中还可定义自己的属性、操作
-
特殊/一般关系:也叫泛化关系。特殊元素/子元素的对象可替代一般元素/父元素的对象,父元素是子元素的泛化(一般表示),子元素是父元素的特殊化。子元素共享父元素的结构、行为。在一般特殊关系中,可理解为特殊元素(子类对象)是一般元素(父类对象)的一种特殊体现
-
多重继承:定义一个类时继承多个类。使用多重继承时,多个超类中可能定义有相同名称而不同含义的成员,就可能会造成子类中存在二义性的成员(钻石问题)
-
-
多态
-
理解
-
不同对象收到同样的消息进行不同的响应可产生不同结果,使用户可以发送一个通用消息,而实现的细节由接收对象自行决定,达到同一消息就可以调用不同方法,即一个对象具有多种形态
-
多态的实现受继承的支持,利用类继承的层次关系,把具有通用功能的消息存放在高层次,而不同的实现这一功能的行为放在较低层次
-
客户类无需知道所调用方法的特定子类的实现
-
-
多态的不同形式
通用多态:对工作的类型不加限制,允许对不同类型的值执行相同的代码
特定多态:只对有限数量的类型有效,对不同类型的值可能执行不同的代码
-
参数多态(通用多态):应用广泛、最纯的多态,采用参数化模板,通过给出不同类型参数,使一个结构有多种类型。类属是一种(参数多态)机制;一个类属类是关于一组类的一个特性抽象,强调这些类的成员特征中与(具体类型无关)的那些部分,用变元表示与(具体类型相关)的那些部分
-
包含多态(通用多态):同样的操作可用于一个类型及其子类型,在许多语言中都存在,最常见例子是子类泛型化,包含多态一般需要进行运行时的类型检查
-
过载多态(特定多态):同一个名字(操作符/函数名)在不同上下文中可代表不同的含义。在继承关系支持下,可实现把具有通用功能的消息存放在高层次,而实现这一功能的不同行为放在较低层次,在这些低层次上生成的对象能给通用消息不同的响应。程序设计语言中基本类型的大多数操作符都是过载多态的(函数重载)
-
强制多态(特定多态):编译程序通过语义操作,强行变换操作对象类型,以符合函数/操作符要求。程序设计语言中基本类型的大多数操作符,在发生不同类型的数据进行混合运算时,编译程序一般都进行强制多态。程序员也可显示进行强制多态的操作。如:int + double,编译系统一般会把int转为double,然后执行double + double运算。强制多态即可是隐式的,也可显式转换
-
-
-
面向对象程序设计语言
-
静态成员:所修饰的成员属于类,而不属于某对象。静态数据成员对该类只有一份,该类的所有对象共享静态数据成员,可被该类的所有方法访问,其值可以修改,但不论是通过对象还是类对静态数据成员值的修改, 都会反应到整个类。类的静态方法只能访问该类的静态数据成员
-
主要用于实现面向对象的程序设计,包括定义和实例化对象、使用继承、多态等面向对象的概念和特性
-
开发人员可以更加方便地实现面向对象的编程方式,可以提高代码的可重用性、可维护性、可扩展性
-
在面向对象程序设计中,实现阶段是将设计转换为实际可运行的代码的阶段,将具体实现细节编写成程序,实现对需求的满足
-
现在的面向对象语言有很多已经不再提供全局变量/函数的定义,实践也证明全局变量/函数并不是一种很好的程序设计风格
-
-
面向对象业务建模
-
业务用例和参与者一起描述组织或企业所支持的业务过程
-
业务用例:确定执行业务时将发生的事情,描述一系列动作的执行,及产生对特定业务主角有价值的结果
-
业务流程:被定义为多个不同的业务用例,每个业务用例都代表业务中某个特定的工作流程
-
业务对象模型:从业务角色内部的观点定义业务用例。该模型确定了业务人员及其处理和使用的对象间应该具有的静态、动态关系,注重业务中承担的角色及当前职责,既描述业务结构,又描述这些结构元素如何完成业务用例
-
-
面向对象的软件开发
-
面向对象分析:
① 主要回答软件系统需要解决什么问题,并不考虑系统实现以及系统的测试问题
② 强调建立独立与系统实现的系统分析模型,关注点仍然侧重于问题域
③ 是为了获得对应用问题的理解,其主要任务是抽取、整理用户需求并建立问题域精确模型
④ 面向对象分析产生分析模型,该分析模型可使用UML表达
⑤ 确定系统的功能、性能要求,在此阶段主要关注系统的行为,明确系统需要提供什么服务
⑥ 定义服务、确定附加的系统约束以及定义类和对象的前提是要确定问题域
定义领域模型:是面向对象分析的关键步骤之一。领域模型是从按对象分类的角度创建对象领域的描述,包括定义概念、属性、重要关联,其结果用一组显示领域概念和对象的图形(类图)来组织,图中还包括多重性、关联关系、泛化/特化关系、聚合关系等。面向对象分析步骤如下:
① 认定对象:在应用领域中,按自然存在的实体确立对象。在定义域中,首先将自然存在的“名词”作为一个对象,这通常是研究问题定义域实体的良好开始。通过实体间的关系寻找对象常常没有问题,而困难在于寻找/选择系统关心的实质性对象。实质性对象是系统稳定性的基础。如:银行应用系统中,实质性对象应包含客户账务、清算等,而门卫值班表不是实质性对象,甚至可不包含在该系统中
② 组织对象:分析对象间关系,将相关对象抽象成类,目的是简化关联对象,利用类的继承性建立具有继承性层次的类结构。抽象类时可从对象间的操作或一个对象是另一个对象的一部分来考虑:如房子由门和窗构成,门和窗是房子类的子类。由对象抽象类,通过相关类的继承构造类层次,所以说系统的行为和信息间的分析过程是一种迭代表征过程
③ 描述对象间的相互作用:描述出各对象在应用系统中的关系。如一个对象是另一个对象的一部分,一个对象与其他对象间的通信关系等。这样可以完整地描述每个对象的环境,由一个对象解释另一个对象,以及一个对象如何生成另一个对象,最后得到对象的界面描述
④ 定义对象的操作
⑤ 定义对象的内部信息
-
面向对象设计
① 主要活动:识别类及对象、定义属性、定义服务、识别关系、识别包
② 设计分析模型、实现相应源代码,是采用协作的对象、对象的属性和方法说明软件解决方案的一种方式,强调定义软件对象和这些软件对象如何协作来满足需求,延续了面向对象分析。以分析模型为基础,继续对分析模型进行精化,得到设计模型,其表达仍可采用UML建模语言。采用面向对象技术将OOA所创建的分析模型转化为设计模型,其目标是定义系统构造蓝图。程序设计范型、选择一种OOPL
-
面向对象实现/面向对象程序设计:强调釆用面向对象程序设计语言实现系统。选择合适的面向对象程序设计语言,将程序组织为相互协作的对象集合,每个对象表示某个类的实例,类通过继承等关系进行组织
-
面向对象测试:根据规范说明验证系统设计的正确性,算法层——类层——模板层——系统层
-
10.2设计原则
-
组合重用原则:尽量使用组合,而不是继承关系达到重用目的
-
共同重用原则:一个包中的所有类应该共同重用。即如果重用了包中的一个类,就要重用包中的所有类
-
共同封闭原则:包中的所有类对同一类性质的变化应该共同封闭。一个变化若对一个包产生影响,则将对该包中的所有类产生影响,而对其他包不造成任何影响
-
单一责任原则:设计目的单一的类。就一个类而言,应该仅有一个引起它变化的原因。当需要修改某个类的时候原因有且只有一个,让一个类只做一种类型责任
-
接口隔离原则:候选类集合进行删除的原则,使用多个专门的接口比使用单一的总接口要好,不应该强迫客户类依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。即依赖于抽象,不依赖于具体,同时在抽象级别不应该有对于具体细节的依赖。好处在于可最大限度地应对可能的变化
-
候选类的选择:运用良性依赖原则(不会在实际中造成危害的依赖关系,都是良性依赖)
-
迪米特原则:最少知识法则,一个对象应当对其他对象有尽可能少的了解
-
无环依赖:包之间的依赖关系图必须是一个直接的无环图形,即在依赖结构中不允许出现环(循环依赖)
-
开放一封闭原则:
-
对扩展开放,对修改封闭,是面向对象的可复用设计的基石
-
软件实体(类、模块、函数等)应该是可以扩展的,即开放的,但不可修改的,即封闭的
-
设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。满足开闭原则的系统可通过扩展已有的软件系统,提供新的能力和行为,以满足对软件的新需求,使软件系统有一定的适应性、灵活性
-
已有的软件模块,特别是最重要的抽象层模块不能再修改,使变化中的软件系统有一定稳定性、延续性;满足开闭原则的系统具备更好的可复用性、可维护性
-
通过抽象类、接口,规定了具体类的特征作为抽象层,相对稳定,满足“对修改关闭”的要求;而从抽象类导出的具体类可改变系统的行为, 满足对扩展开放
-
-
李氏替换原则
-
子类可以替换父类,指一个软件实体如果使用的是—个基类,那么一定适用于其子类,而且软件系统觉察不出基类对象和子类对象的区别。软件系统中把基类都替换成它的子类,程序的行为没有变化
-
里氏代换原则中仅仅指出用子类对象代替基类对象,而反过来的代换是不成立的。如果一个软件模块中使用的是一个子类对象,使用父类对象代换子类对象则可能产生错误。任何基类对象可以出现的地方,子类对象一定可以代替基类对象
-
-
依赖倒置原则:
-
依赖于抽象,而不是具体实现;针对接口编程,不要针对实现编程
-
系统中进行设计、实现的时候应当使用接口、抽象类进行变量类型声明、参数类型声明、方法返回类型说明、数据类型转换等,而不要用具体类进行上述操作。要保证做到这一点,一个具体类应当只实现接口和抽象类中声明过的方法,而不要给出多余的方法
-
传统的过程性系统的设计办法倾向于使高层次模块依赖于低层次模块,抽象层次依赖于具体层次。依赖倒转原则就是把这个不良的依赖关系倒转过来
-
面向对象设计的重要原则是创建抽象层次,从该抽象层次导出具体层次,具体层次给出不同实现。继承关系是一种从抽象化到具体化的导出。抽象层包含应用系统的业务逻辑和宏观的、对整个系统来说重要的战略性决定,而具体层次含有一些次要的与实现有关的算法和逻辑、战术性的决定,带有一定的偶然性选择
-
从复用角度说,高层抽象的模块应当重点复用,因为它含有一个应用系统最重要的宏观业务逻辑,是较为稳定的部分。而在传统过程性设计中,复用则侧重于具体层次模块的复用
-
使用依赖倒转原则时建议不依赖于具体类,即程序中所有的依赖关系都应该终止于抽象类/接口。尽量做到任何变量都不应该持有一个指向具体类的指针/引用; 任何类都不应该从具体类派生;任何方法都不应该覆写它的任何基类中的已实现的方法
-
10.3 设计模式的概念与分类
-
设计模式:主要关注软件系统的设计,与具体的实现语言无关
-
设计模式4个要素
-
模式名称:用一两个词描述模式的问题、解决方案、效果。设计模式允许在较高的抽象层次上进行设计
-
问题:描述应该在何时使用模式。解释了设计问题和问题存在的前因后果,可能描述了特定的设计问题,如怎样用对象表示算法等;也可能描述了导致不灵活设计的类/对象结构
-
解决方案:描述设计的组成成分、它们之间的相互关系及各自的职责和协作方式。模式就像一个模板,提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类/对象组合)来解决这个问题
-
效果:描述模式应用的效果及使用模式应权衡的问题,设计模式能在需求变化情况下,尽可能不更改原有的设计和实现
-
10.4 创建型模式
-
与对象的创建有关,抽象了实例化过程。帮助一个系统独立于如何创建、组合、表示它的那些对象
-
一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象
-
创建型模式两个主旋律
-
它们都将关于该系统使用哪些具体的类的信息封装起来
-
它们隐藏了这些类的实例是如何被创建和放在一起的,整个系统关于这些对象所知道的是由抽象类所定义的接口
-
-
创建型模式在为什么被创建、谁创建它、怎样被创建、何时创建等方面给予了很大灵活性。它们允许用结构和功能差别很大的“产品“对象配置一个系统。配置可以是静态的(编译时指定),也可是动态的(运行时指定)
10.4.1 Singleton 单例模式
-
理解:保证一个类只有一个实例,并提供一个访问它的全局访问点
-
适用场景:
① 当类只能有一个实例且客户可以从一个众所周知的访问点访问它时
② 当这个唯一实例应该是通过子类化可扩展的,且客户应该无须更改代码就能使用一个扩展的实例时
10.4.2 Builder 构建器模式
-
理解:
① 将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示(复杂对象构造)
② 解释
Builder:为创建一个Product对象的各个部件指定抽象接口
ConcreteBuilder:实现Builder接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口。创建该必品的内部表示并定义它的装配过程,包含定义组成组件的类,包括将这些组件装配成最终产品的接口
Director:构造一个使用Builder接口的对象
Product:表示被构造的复杂对象
-
适用场景:
① 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时
② 当构造过程必须允许被构造的对象有不同的表示时
10.4.3 Abstract Factory 抽象工厂模式
-
理解:
① 提供一个创建一系列相关或相互依赖对象的接口,无须指定它们具体的类(生产成系列对象)
② 解释
AbstractFactory:声明一个创建抽象产品对象的操作接口
ConcreteFactory:实现创建具体产品对象的操作
AbstractProduct:为一类产品对象声明一个接口
ConcreteProduct:定义一个将被相应的具体工厂创建的产品对象,实现AbstractProduct接口
Client:使用由 AbstractFactory 和 AbstractProduct 类声明的接口
-
适用场景:
① 一个系统要独立于它的产品的创建、组合、表示时
② 一个系统要由多个产品系列中的一个来配置时
③ 当要强调一系列相关的产品对象的设计以便进行联合使用时
④ 当提供一个产品类库,只想显示它们的接口而不是实现时(如为图形用户界面GUI组件定义不同平台的并行类层次结构)
10.4.4 Prototype原型模式
-
理解:
① 用原型实例指定创建对象的类型,并通过拷贝这个原型创建新对象(克隆对象)
② 解释
Prototype:声明一个复制自身的接口
ConcretePrototype:实现一个复制自身的操作
Client:一个原型复制自身从而创建一个新对象
-
适用场景:
① 当一个系统应该独立于它的产品创建、构成、表示时
② 当实例化的类在运行时刻指定时,如动态装载
③ 为了避免创建一个与产品类层次平行的厂类层次时
④ 当一个类的实例只能有几个不同状态组合中的一种时, 建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些
10.4.5 Factory Method工厂方法模式
-
理解:
① 类行为模式,定义一个创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类(动态生产对象)
② 解释
Product:定义工厂方法所创建的对象的接口
ConcreteProduct:实现Product 接口
Creator:声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的默认实现,它返回一个默认的ConcreteProduct对象,可以调用工厂方法以创建一个Product对象
ConcreteCreator:重定义工厂方法以返回一个ConcreteProduct实例
-
适用场景:
① 当一个类不知道它所必须创建的对象的类时
② 当一个类希望由它的子类来指定它所创建的对象时
③ 当类将创建对象的职责委托给多个帮助子类中的某一个,并希望将哪一个帮助子类是代理者这一信息局部化的时候
10.5 结构型模式
-
涉及如何组合类和对象以获得更大的结构。结构性模式采用继承机制组合接口、实现
-
结构性对象模式不是对接口和实现进行组合,而是描述如何对一些对象进行组合,从而实现新功能的一些方法
10.5.1 Adapter适配器模式
-
理解:
① 将一个类/对象的接口转换成客户希望的另一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作(转换接口)
② 既是类结构模式,又是对象结构模式。类适配器使用多重继承对一个接口与另一个接口进行匹配。对象适配器依赖于对象组合
③ 解释
Target:定义Client使用的与特定领域相关的接口
Client:与符合Target接口的对象协同
Adaptee :定义一个已经存在的接口,这个接口需要适配
Adapter:对Adaptee的接口与Target接口进行适配
-
适用场景:
① 想使用一个已经存在的类,而它的接口不符合要求
② 想创建一个可复用的类,该类可与其他不相关/不可预见的类(即那些接口可能不一定兼容的类)协同工作
③ 想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配他们的接口。对象适配器可以适配它的父类接口。 (仅适用于对象Adapter)
10.5.2 Bridge 桥接模式
-
理解:
① 将抽象部分与其实现部分分离,使它们都可以独立变化(继承树拆分)
② 和适配器模式具有类似特征,都给另一个对象提供了一定程度上的间接性,都涉及自身以外的一个接口向这个对象转发请求
③ 解释
Client:客户程序,使用的主要接口是Abstraction
Abstraction:定义抽象类的接口,维护一个指向Implementor类型对象的指针/引用,这一关系是组成关系,此实现遵循的“优先选用组合而不是继承”原则
RefinedAbstraction:扩充由Abstraction定义的接口
Implementor:定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。通常Implementor接口仅提供基本操作,而Abstraction定义基于这些基本操作的较高层次操作
Concretelmplermentor:实现Implementor接口并定义它的具体实现
-
适用场景:
① 不希望在抽象和它的实现部分间有一个固定的绑定关系
② 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充
③ 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译
④ 想对客户完全隐藏抽象的实现部分
⑤ 有许多类要生成的类层次结构
10.5.3 Decorator装饰模式
-
理解(附加职责):
① 以透明围栏支持修饰的类和对象的关系,动态地给一个对象添加一些额外职责(附加职责)
② 提供了用子类扩展功能的一个灵活的替代,相比生成子类更加灵活
③ 解释
Component:定义一个对象接口,可以给这些对象动态地添加职责
ConcreteComponent:定义一个对象,可以给这个对象添加一些职责
Decorator:维持一个指向Component对象的指针,并定义一个与Component接口一致的接口
ConcreteDecorator: 向组件添加职责
-
适用场景:
① 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
② 处理那些可以撤销的职责
③ 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于类定义被隐藏,或类定义不能用于生成子类
10.5.4 Composite组合模式
-
理解:
① 将对象组合成树型结构表示“整体-部分”的层次结构,使用户对单个对象和组合对象的使用具有一致(树形目录结构)
② 解释
Component:提供给Client操纵组合组件的对象。适当情况下实现所有类共有接口的默认行为,声明一个接口用于访问和管理Component的子组件。为组合的对象声明接口,通常定义父组件引用,用户引用此组件,Leaf和Composite类可以继承这个引用以及管理这个应用的那些操作
Leaf:组合中表示叶结点对象,叶结点没有子结点,在组合中定义图元对象的行为
Composite:定义有子组件的那些组件的行为,存储子组件,在Component接口中实现与子组件有关操作
-
适用场景:
① 想表示对象的“部分-整体”层次结构
② 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象
10.5.5 Facade外观模式
-
理解(对外统一接口):
定义一个高层接口,为子系统中的一组接口提供一个一致的外观,简化该子系统的使用
-
适用场景:
① 要为一个复杂子系统提供一个简单接口时,子系统往往因为不断演化而变得越来越复杂,Facade可以提供一个简单默认视图,这视图对大多数用户已经足够,而那些需要更多的可定制性的用户可以越过Facade层
② 客户程序与抽象类的实现间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性、可移植性
③ 当需要构建一个层次结构子系统时,使用Facade模式定义子系统中每层的入口点。如果子系统之间相互依赖,则可以让它们仅通过Facade通信,从而简化了它们之间的依赖关系
10.5.6 Flyweight享元模式
-
理解:
运用共享技术有效支持大量细粒度对象共享(文章共享文字对象)
-
适用场景:
① 一个应用程序使用了大量的对象
② 完全由于使用大量的对象,造成很大的存储开销
③ 对象的大多数状态都可变为外部状态
④ 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象:应用程序不依赖于对象标识
10.5.7 Proxy代理模式
-
理解:
① 为其他对象提供一种代理以控制这个对象的访问
④ 提供与对象相同的接口来控制对这个对象的访问,以使得在确实需要这个对象时才对它进行创建和初始化
-
适用场景:
在需要比较通用和复杂的对象指针代替简单的指针的时候,常见情况有:
①远程代理:为一个对象在不同地址空间提供据不代表
② 虚代理:根据需要创建开销很大的对象
③ 保护代理:控制对原始对象的访问,用于对象应该有不同访问权限的时候
④ 智能指引:取代了简单的指针,它在访问对象时执行一些附加操作
10.6 行为型模式
-
行为模式:涉及算法和对象间职责分配。行为模式不仅描述对象或类的模式还描述它们之间的通信模式。这些模式刻画了在运行时难以跟踪的复杂的控制流,它们将用户的注意力从控制流转移到对象间的联系方式上来
-
行为类模式使用继承机制在类间分派行为,主要有模板方法Template Method、解释器Interpreter模式
-
行为对象模式使用对象复合而不是继承。一些行为对象模式描述了一组对等的对象怎样相互协作以完成其中任一个对象都无法单独完成的任务。其他的行为对象模式常将行为封装在一个对象中并将请求指派给它
10.6.1 Memento 备忘录模式
-
理解:
在不破坏封装性前提下,捕获一个对象的内部状态,并在对象外保存这个状态。以后就可将对象恢复到原先保存的状态
-
适用场景:
① 必须保存一个对象在某一个时刻的部分状态,以后需要时它才能恢复到先前的状态
② 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象封装性
10.6.2 Chain of Responsibility 职责链模式
-
理解(传递职责):
使多个对象都有机会处理请求,避免请求的发送者、接收者间的耦合关系。将接收对象链接起来,并沿这条链传递该请求,直到有一个对象处理这个请求(传递职责)
-
适用场景:
① 有多个对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定
② 想在不明确指定接收者的情况下向多个对象中的一个提交一个请求
③ 可处理一个请求的对象集合应被动态指定
10.6.3 Strategy 策略模式
-
理解(多方案切换):
① 定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。此模式使得算法可独立于使用它们的客户而变化(多方案切换)
② 适用于需在不同情况下使用不同策略(算法),或策略还可能在未来用其他方式来实现
③ 解释
Strategy (策略):定义所有支持算法的公共接口,Context使用这个接口调用某ConcreteStrategy定义的算法 ConcreteStrategy (具体策略):以Strategy接口实现某具体算法 Context (上下文):用一个ConcreteStrategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口来让Strategy访问它的数据
-
适用场景:
① 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法
② 需要使用一个算法的不同变体。如,定义一些反应不同空间的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式
③ 算法使用客户不该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构
④ 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的Strategy类中,以代替这些条件语旬
10.6.4 mediator 中介者
-
理解(不直接引用):
用一个中介对象封装一系列的对象交互。它使各对象不需要显式地相互调用,从而达到低耦合,还可以独立地改变对象间的交互
-
适用场景:
① 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解
② 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象
③ 想定制一个分布在多个类中的行为,而又不想生成太多的子类
④ 欲使一个后端数据模型能够被多个前端用户界面连接
10.6.5 Visitor 访问者模式
-
理解:
① 表示一个作用于某对象结构中的各元素的操作,使得在不改变各元素的类的前提下,定义作用于这些元素的新操作
② 一个Visitor对象是一个多态的accept操作的参数,这个操作作用于该Visitor对象访问的对象
③ Visitor (访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作
④ Element (元素):定义以一个访问者为参数的Accept操作
-
适用场景:
① 一个对象结构包含很多类对象,它们有不同接口,而用户想对这些对象实施一些依赖于其具体类的操作
② 需要对一个对象结构中的对象进行很多不同且不相关的操作,而又想避免这些操作“污染”这些对象的类
③ 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作
10.6.6 Observer 观察者模式
-
理解( 发布-订阅 Publish-Subscribe模式):
① 定义对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都得到通知并自动更新(联动)
② 通常一个观察者(Observer)观察一个被观察者(Subject),而一个被观察者可以被多个观察者关注
③ 解释
Subject:目标,知道它的观察者,可以有任意多观察者观察同一个目标;提供注册、删除观察者对象的接口
Observer:观察者,为那些在目标发生改变时需获得通知的对象定义一个更新接口
ConcreteSubject:具体目标,将有关状态存入各ConcreteObserver对象;当它的状态发生改变时,向其各个观察者发出通知
ConcreteObserver:具体观察者,维护一个指向ConcreteSubject对象的引用;存储有关状态,这些状态应与目标的状态保持一致;实现Observer的更新接口,以使自身状态与目标的状态保持一致
-
适用场景:
① 当一个抽象模型有两方面,一方面依赖于另一方面,将两者封装在独立对象中以使它们可以各自独立改变和复用
② 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时
③ 当一个对象必须通知其他对象,而它又不能假定其他对象是谁,即不希望这些对象是紧耦合的
④ 最适合用于发布/订阅消息模型,由订阅者订阅消息主题,发布者一旦有此主题消息发布,所有订阅者就会自动收到通知
10.6.7 Iterator 迭代器
-
理解
提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示(数据库、数据集)
-
适用场景:
① 访问一个聚合对象的内容而无须暴露它的内部表示
② 支持对聚合对象的多种遍历
③ 为遍历不同的聚合结构提供一个统一的接口
10.6.8 Command 命令模式
-
理解:
① Command模式中,令牌代表一个请求
② 排队或记录请求日志,以及支持可撤销的操作
③ 解释
Command:抽象命令类,声明执行操作的一个接口
ConcreteCammand:具体命令类将一个接收者对象绑定于一个动作。实现execute方法,以调用接收者的相关操作Action
Invoker:调用者,要求一个命令对象执行一个请求
Receiver:接收者,知道如何执行关联请求的相关操作
Client:客户应用程序,创建一个具体命令类对象,并且设定它的接收者
-
适用场景:
① 抽象出待执行的动作以参数化某对象,此模式是过程语言中的回调机制的一个面向对象的替代方式
② 在不同的时刻指定、排列、执行请求
③ 支持取消操作、支持修改日志
④用构建在原语操作上的高层操作构造一个系统
10.6.9 Interpreter 解释器模式
-
理解:
行为型类模式,给定一个语言,定义其文法的一种表示,并定义一个使用该表示来解释语言中句子的解释器(虚拟机机制)
10.6.10 State状态模式
-
理解(状态变成类):
① 使得一个对象在其内部状态改变时通过调用另一个类中的方法改变其行为,使这个对象看起来如同修改了它的类 (状态变成类)
② Context (上下文):定义客户感兴趣的接口
③ State (状态):定义一个接口以封装与Context的一个特定状态相关的行为
-
适用场景:
① 有多个对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定
② 一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为
③ 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个/多个枚举常量表示。有多个操作包含这相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得开发者可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化
10.6.11 Template Method 模板方法模式
-
理解:
类行为模式,定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义算法的某些特定步骤