软件构造设计模式及图解

软件构造设计模式及图解

结构型模式

1.1 适配器模式

适配器模式中的有以下的四种角色:

**目标(target):**定义客户端使用的与特定领域相关的接口。

**被适配者(adaptee):**定义了一个已经存在的接口,这个接口需要匹配。

**适配者(adapter)????*对Adaptee的接口与target的接口进行适配。

**客户端(Client):**与符合target接口的对象协同。

适配器模式的意图是将一个类的接口转换成客户希望的另外的一个接口。Adapter
模式使得原来由于几口不兼容而不能一起工作的雷可以一起工作。

**设计方式:**将某个类/接口转换为client期望的其他形式,通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。

设计图解:

软件构造设计模式及图解

1.2 装饰器模式

**装饰(Decorator)模式的定义:**指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

装饰(Decorator)模式的主要优点有:

采用装饰模式扩展对象的功能比采用继承方式更加灵活。

可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

**其主要缺点是:**装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

**设计实现:**通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。下面来分析其基本结构和实现方法。

装饰模式主要包含以下角色。

**抽象构件(Component)角色:**定义一个抽象接口以规范准备接收附加责任的对象。

**具体构件(Concrete
Component)角色:**实现抽象构件,通过装饰角色为其添加一些职责。

**抽象装饰(Decorator)角色:**继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。

**具体装饰(ConcreteDecorator)角色:**实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

设计图解:

软件构造设计模式及图解

1.3 外观模式

**外观(Facade)模式定义:**是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

主要优点:

降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。

对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。

降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程,因为编译一个子系统不会影响其他的子系统,也不会影响外观对象。

主要缺点:

不能很好地限制客户使用子系统类。

增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

**设计实现:**外观(Facade)模式包含以下主要角色:

**外观(Facade)角色:**为多个子系统对外提供一个共同的接口。

**子系统(Sub System)角色:**实现系统的部分功能,客户可以通过外观角色访问它。

**客户(Client)角色:**通过一个外观角色访问各个子系统的功能。

设计图解:

软件构造设计模式及图解

1.4 代理模式

**代理模式的定义:**由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

代理模式的主要优点有:

代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;

代理对象可以扩展目标对象的功能;

代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;

其主要缺点是:

在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;

增加了系统的复杂度;

**设计实现:**代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。

代理模式的主要角色如下:

**抽象主题(Subject)类:**通过接口或抽象类声明真实主题和代理对象实现的业务方法。

**真实主题(Real
Subject)类:**实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。

**代理(Proxy)类:**提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

设计图解:

软件构造设计模式及图解

行为类模式

2.1 策略模式

**策略(Strategy)模式的定义:**该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

策略模式的主要优点如下:

多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。

策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。

策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。

策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。

策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

其主要缺点如下:

客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。

策略模式造成很多的策略类。

**设计实现:**策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性,现在我们来分析其基本结构和实现方法。

策略模式的主要角色如下:

**抽象策略(Strategy)类:**定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。

**具体策略(Concrete
Strategy)类:**实现了抽象策略定义的接口,提供具体的算法实现。

**环境(Context)类:**持有一个策略类的引用,最终给客户端调用。

设计图解:

软件构造设计模式及图解

2.2 模板方法模式

**模板方法(Template
Method)模式的定义如下:**定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

该模式的主要优点如下:

它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。

它在父类中提取了公共的部分代码,便于代码复用。

部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

该模式的主要缺点如下:

对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。

父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。

**设计实现:**模板方法模式需要注意抽象类与具体子类之间的协作。它用到了虚函数的多态性技术以及“不用调用我,让我来调用你”的反向控制技术。现在来介绍它们的基本结构。

模板方法模式包含以下主要角色。

(1) **抽象类(Abstract
Class):**负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。

a)**模板方法:**定义了算法的骨架,按某种顺序调用其包含的基本方法。

b)**基本方法:**是整个算法中的一个步骤,包含以下几种类型。

i)**抽象方法:**在抽象类中申明,由具体子类实现。

ii)**具体方法:**在抽象类中已经实现,在具体子类中可以继承或重写它。

iii)**钩子方法:**在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

(2) **具体子类(Concrete
Class):**实现抽象类中所定义的抽象方法和钩子方法,它们是一个*逻辑的一个组成步骤。

设计图解:

软件构造设计模式及图解

2.3 迭代器模式

**迭代器(Iterator)模式的定义:**提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为型模式,

其主要优点如下:

访问一个聚合对象的内容而无须暴露它的内部表示。

遍历任务交由迭代器完成,这简化了聚合类。

它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。

增加新的聚合类和迭代器类都很方便,无须修改原有代码。

封装性良好,为遍历不同的聚合结构提供一个统一的接口。

**其主要缺点是:**增加了类的个数,这在一定程度上增加了系统的复杂性。

**设计实现:**迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。现在我们来分析其基本结构与实现方法。

迭代器模式主要包含以下角色:

**抽象聚合(Aggregate)角色:**定义存储、添加、删除聚合对象以及创建迭代器对象的接口。

**具体聚合(ConcreteAggregate)角色:**实现抽象聚合类,返回一个具体迭代器的实例。

**抽象迭代器(Iterator)角色:**定义访问和遍历聚合元素的接口,通常包含
hasNext()、first()、next() 等方法。

**具体迭代器(Concretelterator)角色:**实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

设计图解:

软件构造设计模式及图解

2.4 观察者模式

**观察者(Observer)模式的定义:**指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

观察者模式是一种对象行为型模式,其主要优点如下:

降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。

目标与观察者之间建立了一套触发机制。

它的主要缺点如下:

目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。

当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

**设计实现:**实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。

观察者模式的主要角色如下:

**抽象主题(Subject)角色:**也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

**具体主题(Concrete
Subject)角色:**也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。

**抽象观察者(Observer)角色:**它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。

**具体观察者(Concrete
Observer)角色:**实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

设计图解:

软件构造设计模式及图解

2.5 访问者模式

**访问者(Visitor)模式的定义:**将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。

访问者(Visitor)模式是一种对象行为型模式,其主要优点如下:

扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。

复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。

灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对*地演化而不影响系统的数据结构。

符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。

访问者(Visitor)模式的主要缺点如下:

增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。

破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。

违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。

**设计实现:**访问者(Visitor)模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类,其基本结构与实现方法如下。

访问者模式包含以下主要角色。

**抽象访问者(Visitor)角色:**定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作
visit() ,该操作中的参数类型标识了被访问的具体元素。

**具体访问者(ConcreteVisitor)角色:**实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。

**抽象元素(Element)角色:**声明一个包含接受操作 accept()
的接口,被接受的访问者对象作为 accept() 方法的参数。

**具体元素(ConcreteElement)角色:**实现抽象元素角色提供的 accept()
操作,其方法体通常都是 visitor.visit(this)
,另外具体元素中可能还包含本身业务逻辑的相关操作。

**对象结构(Object
Structure)角色:**是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由
List、Set、Map 等聚合类实现。

设计图解:

软件构造设计模式及图解

创建型模式

3.1 工厂方法模式

**工厂方法(FactoryMethod)模式的定义:**定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

工厂方法模式的主要优点有:

用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;

在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

**其缺点是:**每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

**设计实现:**工厂方法模式由抽象工厂、具体工厂、抽象产品和具体产品等4个要素构成。本节来分析其基本结构和实现方法。

工厂方法模式的主要角色如下:

**抽象工厂(Abstract
Factory):**提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法
newProduct() 来创建产品。

**具体工厂(ConcreteFactory):**主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

**抽象产品(Product):**定义了产品的规范,描述了产品的主要特性和功能。

**具体产品(ConcreteProduct):**实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

设计图解:

软件构造设计模式及图解

3.2 抽象工厂方法

**抽象工厂(AbstractFactory)模式的定义:**是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

使用抽象工厂模式一般要满足以下条件:

系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。

系统一次只可能消费其中某一族产品,即同族的产品一起使用。

抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下:

可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。

当增加一个新的产品族时不需要修改原代码,满足开闭原则。

**其缺点是:**当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

**设计实现:**抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等
4
个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。现在我们来分析其基本结构和实现方法。

抽象工厂模式的主要角色如下:

**抽象工厂(Abstract Factory):**提供了创建产品的接口,它包含多个创建产品的方法
newProduct(),可以创建多个不同等级的产品。

**具体工厂(Concrete
Factory):**主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。

**抽象产品(Product):**定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。

**具体产品(ConcreteProduct):**实现了抽象产品角色所定义的接口,由具体工厂来创建,它
同具体工厂之间是多对一的关系。

设计图解:

软件构造设计模式及图解

总结

软件构造的方法模式多种多样,为我们提供了很多选择,了解各种模式的优缺点、使用情况,选择最优模式,是做一个好的程序员的基础。