Object Oriented Analysis and Design Design Pattern
Outline 什么是设计模式 设计模式要素 设计模式的分类 几种设计模式的介绍 创建型模式 结构型模式 行为模式
什么是模式 Christopher Alexander 说过:“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动” 。 尽管A l e x a n d e r所指的是城市和建筑模式,但他的思想也同样适用于面向对象设计模式,只是在面向对象的解决方案里,我们用对象和接口代替了墙壁和门窗。两类模式的核心都在于提供了相关问题的解决方案。 定义: “在一个上下文中对一种问题的解决方案”。 ——这种定义限定模式为单一的问题-解决方案型。
关于设计模式 对已有模式的整理、分类 一套描述模式的词汇,可用于交流和文档化 为软件设计总结了宝贵的经验,这些设计经验可以被重用,但不是简单的代码重用 分类: Creational Patterns Structural Patterns Behavioral Patterns 在软件设计模式领域,起到先驱的作用
Design pattern与framework Patterns支持软件结构和设计的重用 抓住了特定领域中问题的成功解决方案中的静态、动态结构和相互之间的协作关系 patterns与开发语言无关,但是建立在一定的环境基础上 例如:经典的MVC、Factory Method frameworks支持细节设计和代码的重用 framework是一组组件的综合,这些组件相互协作,为一族相关应用提供了一个可重用的框架结构 例如:MMC、MS Script Engine 两者结合起来, design patterns and frameworks有助于提高软件的质量 比如:重用性,扩展性,性能,可维护性
指导模式设计的三个概念 重用(reuse):是目标 接口与实现分离 Decouple 两种重要的重用手段 Inheritance & composition 接口与实现分离 接口保持不变,分离带来灵活性 多态性(polymorphism) Decouple 降低复杂性
设计模式分类
创建型模式 ABSTRACT FACTORY(抽象工厂,kit) BUILDER(生成器) FACTORY METHOD(工厂方法,virtual constructor) PROTOTYPE(原型) SINGLETON(单件)
抽象工厂(一) 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 别名 Kit
抽象工厂(二) 动机 考虑一个支持多种视感( look - and - feel)标准的用户界面工具包,例如Motif和Presentation Manager。不同的视感风格为诸如滚动条、窗口和按钮等用户界面“窗口组件”定义不同的外观和行为。为保证视感风格标准间的可移植性,一个应用不应该为一个特定的视感外观硬编码它的窗口组件。在整个应用中实例化特定视感风格的窗口组件类将使得以后很难改变视感风格。 为解决这一问题我们可以定义一个抽象的WidgetFactory类,这个类声明了一个用来创建每一类基本窗口组件的接口。每一类窗口组件都有一个抽象类,而具体子类则实现了窗口组件的特定视感风格。对于每一个抽象窗口组件类, WidgetFactory接口都有一个返回新窗口组件对象的操作。客户调用这些操作以获得窗口组件实例,但客户并不知道他们正在使用的是哪些具体类。这样客户就不依赖于一般的视感风格,如下页图所示。
抽象工厂(三)
抽象工厂(四) 每一种视感标准都对应于一个具体的WidgetFactory子类。每一子类实现那些用于创建合适视感风格的窗口组件的操作。例如, MotifWidgetFactory的Create ScrollBar操作实例化并返回一个Motif滚动条,而相应的PMWidgetFactory操作返回一个Presentation Manager的滚动条。客户仅通过WidgetFactory接口创建窗口组件,他们并不知道哪些类实现了特定视感风格的窗口组件。换言之,客户仅与抽象类定义的接口交互,而不使用特定的具体类的接口。 WidgetFactory也增强了具体窗口组件类之间依赖关系。一个Motif的滚动条应该与Motif按钮、Motif正文编辑器一起使用,这一约束条件作为使用MotifWidget Factory的结果被自动加上。
抽象工厂(五) 结构: 参与者: Client、AbstractFactory、ConcreteFactory、AbstractProduct、ConcreteProduct 协作:
抽象工厂(六) 评估 与factory method的关系 多个factory method合在一起 factory method一定是virtual的
抽象工厂(七) 评估 优点: factory把product的类型封装起来,分离了具体的类 易于变换product族 保证不同族之间的product相互不会碰撞,即保证products的一致性 缺点: factory对象的方法数目对应product数目,增加新的product种类比较困难,要影响到factory的基类,进而影响到所有的子类
抽象工厂(八) 实现 Factories as singletons, 每个product族往往只需要一个factory对象就可以了 Creating the products, 对于product族比较多的情况,可以使用prototype模式来实现这些factories,而不必对于每一个具有细微差别的product族都使用一个concrete factory class Defining extensible factories,针对Evaluation中提到的缺点,通过参数化技术提高factory的适应能力和扩展性 问题在于,返回给客户什么样的类型?
Builder (一) 意图 动机 适用性,在下列情况适用 Builder 模式: 将复杂对象的构建过程与它的表示相分离,使得相同的构建过程可以创建不同的表示。 动机 在复杂对象的构造过程中,允许同样的构造过程能够加入新的被构造元素 “结构化构造过程” 适用性,在下列情况适用 Builder 模式: the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled. the construction process must allow different representations for the object that's constructed.
Builder (二) 结构 参与者 Director、 Builder、ConcreteBuilder、 Product
Builder (三) 协作
Builder (四) 评估 It lets you vary a product's internal representation It isolates code for construction and representation It gives you finer control over the construction process 实现 Builder interface(Assembly and construction) Why no abstract class for products? Empty methods as default in Builder. 相关模式 Abstract Factory 区别:(1) builder重在构造过程,最后一步返回结果; (2) builder构造许多复杂对象
Builder (五) 实例 readers、parsers、converters the persistence of OLE documents
Factory Method模式(一) intent: problem: Forces : 在一个类层次中,客户在runtime要创建一个对象,对象的子类型未确定,根据客户的需要和环境情况,确定对象的类型 problem: 只知道对象的一般类型,不知道确切类型(需要从环境中获取类型信息) Forces : 隐藏对象的类型层次,只发布基接口 如何确定最合适的派生类 客户必须有办法使用派生类的服务
Factory Method模式(二) solution: 例子: 使用Envelope/Letter或者Handle/Body pattern 由envelope或者handle根据环境信息选择适当的派生类型 例子: 1 根据stream动态创建对象 2 COM对象
Factory Method模式(三) struct Participants Collaborations Product、ConcreteProduct、Creator、ConcreteCreator Collaborations
Factory Method模式(四) Evaluation 多态性:客户代码可以做到与特定应用无关,适用于任何实体类 缺点:需要Creator和相应的子类作为factory method的载体,如果应用模型确实需要creator和子类存在,则很好;否则的话,需要增加一个类层次 优点: (1) Provides hooks for subclasses。基类为factory method提供缺省实现,子类可以重写新的实现,也可以继承父类的实现。 体现了:加一层间接性,增加了灵活性 (2) Connects parallel class hierarchies
Factory Method模式(五) Connects parallel class hierarchies
Factory Method模式(六) Implementation (1) 父类是否提供缺省的实现 (3) Language-specific variants and issues SmallTalk,使用类型 C++,使用lazy initialization技术 (4) Using templates to avoid subclassing
Factory Method模式(七) Related Patterns Examples Abstract factory Prototype Examples
Prototype(一) Intent Motivation Applicability Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype. Motivation 以一个已有的对象作为原型,通过它来创建新的对象。在增加新的对象的时候,新对象的细节创建工作由自己来负责,从而使新对象的创建过程与框架隔离开来 Applicability 当产品的创建过程要独立于系统时 当产品的类型是在runtime时被指定的情况下 避免创建一个与product层次平行的factory层次时
Prototype(二) Structure Participants Collaborations Prototype、ConcretePrototype、Client Collaborations
Prototype(三) Evaluation Implementation Adding and removing products at run-time Specifying new objects by varying values,降低系统中类的数目 Configuring an application with classes dynamically 要求:每一个product类都必须实现Clone操作 Implementation Using a prototype manager Implementing the Clone operation shallow copy versus deep copy Save & Load Initializing clones 两阶段构造
Prototype(四) Related patterns Examples Prototype与Abstract Factory往往是相互竞争的 factory method Examples music editor
Singleton(一) Intent Motivation Ensure a class only has one instance, and provide a global point of access to it. Motivation It's important for some classes to have exactly one instance. Instance-controlled class Applicability, Use the Singleton pattern when there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point. when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code.
Singleton(二) Structure Participants Collaborations Singleton Clients access a Singleton instance solely through Singleton's Instance operation.
Singleton(三) Evaluation Implementation Controlled access to sole instance Reduced name space Permits refinement of operations and representation,允许子类化 Permits a variable number of instances More flexible than class operations (static member functions in C++ ) 这种思想比较适用于Object-Based中的许多情形 Implementation Ensuring a unique instance 考虑使用lazy initialize 使用global/static object的缺点 Subclassing the Singleton class
Singleton(四) Related patterns Examples Singleton与其他创建型模式并不矛盾,可以用singleton来实现其他模式中的对象。包括Abstract Factory、Builder、Prototype等。 多个实例对于构造过程往往并无意义,所以在许多情况下singleton模式比较符合应用背景 Examples MFC中的CWinApp派生类实例theApp ……
结构型模式 Adapter Bridge Composite Decorator Facade Flyweight Proxy
Adapter模式(一) Aliases:Wrapper Intent Motivation Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. Motivation Sometimes a toolkit class that's designed for reuse isn't reusable only because its interface doesn't match the domain-specific interface an application requires.
Adapter模式(二) Applicability:Use the Adapter pattern when you want to use an existing class, and its interface does not match the one you need. you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces. (object adapter only) you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
Adapter模式(三) Struct class adapter object
Adapter模式(四) Participants Collaborations Client、Target、Adaptee、Adapter class adapter —— delegation object adapter —— container
Adapter模式(五) Evaluation 本质上是两种重用模型 class adapter: 无法adapt adaptee的子类,但是可以重载adaptee的行为 object adapter 可以adapt adaptee的所有子类 How much adapting does Adapter do? Pluggable adapters Using two-way adapters to provide transparency 针对class adapter,用多重继承来实现
Adapter模式(六) Implementation 使用C++继承机制实现class adapter 使用内嵌对象技术实现object adapter Pluggable adapters,三种实现方案 使用抽象方法定义 使用代理对象 参数化技术 这三种方法的实质:如何在一个类中定义抽象操作,供客户插入?—— hook 技术
Adapter模式(七) Related Patterns Bridge Decorator Proxy Examples DrawCli:COleDrawObj C++ STL COM中的site
Bridge模式(一) Aliases:Handle/Body Intent Motivation Decouple an abstraction from its implementation so that the two can vary independently Motivation 要做到“抽象(接口)与实现分离”,最常用的办法是定义一个抽象类,然后在子类中提供实现。也就是说,用继承机制达到“抽象(接口)与实现分离” 但是这种方法不够灵活,继承机制把实现与抽象部分永久地绑定起来,要想独立地修改、扩展、重用抽象(接口)与实现都非常困难。
Bridge模式(二) Applicability:Use the Bridge pattern when 编译时刻无法确定抽象(接口)与实现之间的关系 抽象部分与实现部分都可以通过子类化而扩展 对一个实现的修改不影响客户(无须重新编译) 在C++中,对客户完全隐瞒实现细节 因为扩展的原因,需要把一个类分成两部分,(以便灵活组合) 在多个对象之间共享数据,但客户不需要知道
Bridge模式(三) Struct Participants Collaborations Client, Abstraction, RefinedAbstraction, Implementor, ConcreteImplementor Collaborations
Bridge模式(四) Evaluation 抽象部分与实现部分的分离,可以在运行时刻连接起来 提高可扩充性:抽象与实现两部分可以单独扩充 对客户隐藏实现细节
Bridge模式(五) Implementation Only one Implementor Creating the right Implementor object 如何创建?根据客户环境,或者通过factory Sharing implementors 资源管理:引用计数技术 Using multiple inheritance
Bridge模式(六) Related Patterns Examples Abstract Factory可以用来创建和配置Bridge模式 与Adapter模式的区别 Examples handle:文件handle、 窗口handle
Composite模式 Intent Motivation Assemble groups of objects with the same signature(用相同的方法签名来组装对象组 )。 将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性 Motivation 在绘图编辑器和图形捕捉系统这样的图形应用程序中,用户可以使用简单的组件创建复杂的图表。用户可以组合多个简单组件以形成一些较大的组件,这些组件又可以组合成更大的组件。一个简单的实现方法是为Text和Line这样的图元定义一些类,另外定义一些类作为这些图元的容器类( Container )。 然而这种方法存在一个问题:使用这些类的代码必须区别对待图元对象与容器对象。
Composite模式 Motivation 而实际上大多数情况下用户认为它们是一样的。对这些类区别使用,使得程序更加复杂。 Composite模式描述了如何使用递归组合,使得用户不必对这些类进行区别。Composite 模式的关键是一个抽象类,它既可以代表图元,又可以代表图元的容器。
Composite模式 Struct
Decorator模式 Intent Motivation One class takes in another class, both of which extend the same abstract class, and adds functionality.(一个类获取另外一个与其扩展自相同抽象类的类,对其功能进行扩充) 动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。 Motivation 有时我们希望给某个对象而不是整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动。 使用继承机制是添加功能的一种有效途径,从其他类继承过来的边框特性可以被多个子类的实例所使用。但这种方法不够灵活,因为边框的选择是静态的,用户不能控制对组件加边框的方式和时机。
Decorator模式 Motivation 一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画一个边框)。
Decorator模式 Struct
Facade模式 Intent Motivation One class has a method that performs a complex process calling several other classes.(一个类具有一个执行复杂的调用其他数个类的处理过程的方法) 为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 Motivation 将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一是就是引入一个外观(facade)对象,它为子系统中较一般的设施提供了一个单一而简单的界面。
Facade模式 Motivation
Facade模式 Struct
FlyWeight模式 Intent Motivation Use sharing to support large numbers of fine-grained objects efficiently. Motivation 当对象的粒度太小的时候,大量对象将会产生巨大的资源消耗,因此考虑用共享对象(flyweight)来实现逻辑上的大量对象。Flyweight对象可用于不同的context中,本身固有的状态不随context发生变化,而其他的状态随context而变化
FlyWeight模式 Struct
FlyWeight模式 Struct(续)
Proxy模式 Intent Motivation One class controls the creation of and access to objects in another class.(有一个类来控制另一个类的对象的创建和访问) Motivation 为其他对象提供一种代理以控制对这个对象的访问。
Proxy模式 Struct
Structural patterns小结 Adapter 、bridge、facade adapter用于两个不兼容接口之间的转接 bridge用于将一个抽象与多个可能的实现连接起来 facade用于为复杂的子系统定义一个新的简单易用的接口 composite、decorator和proxy composite用于构造对象组合结构 decorator用于为对象增加新的职责 proxy为目标对象提供一个替代者 flyweight 针对细粒度对象的一种全局控制手段
行为模式 Chain of Responsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor
Chain of Responsibility Intent 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 Motivation 这一模式的想法是,给多个对象处理一个请求的机会,从而解耦发送者和接受者。该请求沿对象链传递直至其中一个对象处理它.
Chain of Responsibility Struct
Command模式 Aliases Intent Motivation Action, Transaction functor (function object) Intent Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. Motivation 把请求信息和请求执行过程封装起来 framework往往需要把命令请求与处理请求的对象分开,command模式可以把调用操作的对象与操作的目标对象分开 允许通过多种途径调用同一个请求。——请求的重用
Command模式 Struct
Command模式 Collaborations
Interpreter模式 Intent Motivation 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 Motivation 如果一种特定类型的问题发生的频率足够高, 那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器, 该解释器通过解释这些句子来解决该问题。
Interpreter模式 Struct
Iterator模式(一) Aliases :Cursor Intent Motivation Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。) Motivation An aggregate object such as a list should give you a way to access its elements without exposing its internal structure. Separating the traversal mechanism from the List object lets us define iterators for different traversal policies without enumerating them in the List interface.
Iterator模式(二) Applicability:Use the Iterator pattern when : to access an aggregate object's contents without exposing its internal representation. to support multiple traversals of aggregate objects. to provide a uniform interface for traversing different aggregate structures (that is, to support polymorphic iteration).
Iterator模式(三) Struct Participants Iterator、ConcreteIterator、Aggregate、ConcreteAggregate
Iterator模式(四) Evaluation Implementation It supports variations in the traversal of an aggregate Iterators simplify the Aggregate interface More than one traversal can be pending on an aggregate Implementation 实现可以非常灵活 Who controls the iteration? external iterator versus internal iterator Who defines the traversal algorithm? Aggregate本身定义算法 —— Cursor mode iterator定义算法 —— iterator如何访问数据 How robust is the iterator?
Iterator模式(五) Implementation(续) Additional Iterator operations. 基本操作:First, Next, IsDone, and CurrentItem Using polymorphic iterators —— iterator资源释放 Iterators may have privileged access Iterators for composites —— 适合于internal iterator或者cursor方式的iterator Null iterators
Mediator模式(一) Intent Motivation 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 Motivation 面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。在最坏的情况下,每一个对象都知道其他所有对象。 虽然将一个系统分割成许多对象通常可以增强可复用性, 但是对象间相互连接的激增又会降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作—系统表现为一个不可分割的整体。而且,对系统的行为进行任何较大的改动都十分困难,因为行为被分布在许多对象中。结果是, 你可能不得不定义很多子类以定制系统的行为。
Mediator模式(二) Struct Participants Iterator、ConcreteIterator、Aggregate、ConcreteAggregate
Memento模式(一) Aliases :Token Intent Motivation 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 Motivation 有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制, 而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到它们先前的状态。但是对象通常封装了其部分或所有的状态信息, 使得其状态不能被其他对象访问,也就不可能在该对象之外保存其状态。而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。
Memento模式(二) Struct
Observer模式(一) Aliases :Dependents, Publish-Subscribe Intent Motivation Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.(定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新) Motivation 把系统分成一些相互关联的类或者对象,如何维护这些类的实例一致性? The key objects in this pattern are subject and observer One-to-many relationship A subject may have any number of dependent observers. All observers are notified whenever the subject undergoes a change in state.
Observer模式(二) Struct Participants Subject、ConcreteSubject、Observer、ConcreteObserver
Observer模式(三) Collaborations
Observer模式(四) Related Patterns Examples Mediator:用Mediator模式封装复杂的更新语义 COM property page COM+ Event Model MVC
State模式 Aliases :状态对象( Objects for States) Intent 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
State模式 Struct
Strategy模式 Aliases :Policy Intent Motivation Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. Motivation 有些算法对于某些类是必不可少的,但是不适合于硬编进类中。客户可能需要算法的多种不同实现,允许增加新的算法实现或者改变现有的算法实现 我们可以把这样的算法封装到单独的类中,称为strategy
Strategy模式 Struct
Template Method模式 Intent
Template Method模式 Struct
Visitor模式 Aliases :Policy Intent Motivation Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.(表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作) Motivation 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
Visitor模式 Struct
行为模式小结 Strategy、Iterator、Mediator、State、command Mediator、Observer 用一个对象来封装某些特性,比如变化、交互、状态、行为、命令 Mediator、Observer Observer建立起subject和observer之间的松耦合连接 mediator把约束限制集中起来,-〉中心控制 command、Chain of Responsibility、interpreter command模式侧重于命令的总体管理 Chain of Responsibility侧重于命令被正确处理 interpreter用于复合结构中操作的执行过程