设计模式之原型模式(Prototype)摘录
Prototype:
(1)、意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象;
(2)、当一个系统应该独立于它的产品创建、构成和表示时,要使用Prototype模式;以及当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者为了避免创建一个与产品类层次平行的工厂类层次时;或者当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些;
(3)、优点:
A、运行时刻增加和删除产品:Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。它比其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型;
B、改变值以指定新对象:高度动态的系统允许你通过对象复合定义新的行为,例如,通过为一个对象变量指定值----并且不定义新的类。你通过实例化已有类并且将这些实例注册为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现出新的行为。这种设计使得用户无需编程即可定义新“类”。实际上,克隆一个原型类似于实例化一个类。Prototype模式可以极大的减少系统所需要的类的数目;
C、改变结构以指定新对象;
D、减少子类的构造:Factory Method经常产生一个与产品类层次平行的Creator类层次。Prototype模式使得你克隆一个原型而不是请求一个工厂方法去产生一个新的对象。因此你根本不需要Creator类层次。这一优点主要适用于像C++这样不降类作为一级类对象的语言;
E、用类动态配置应用:一些运行时刻环境允许你动态将类装载到应用中。在像C++这样的语言中,Prototype模式是利用这种功能的关键。
一个希望创建动态载入类的实例的应用不能静态引用类的构造器。而应该由运行环境在载入时自动创建每个类的实例,并用原型管理器来注册这个实例。这样应用就可以向原型管理器请求新装载的类的实例,这些类原本并没有和程序相连接。
Prototype的主要缺陷是每一个Prototype的子类都必须实现Clone操作,这可能很困难。例如,当所考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难的。
Prototype和Abstract Factory模式在某种方面是相互竞争的。但是它们也可以一起使用。Abstract
Factory可以存储一个被克隆的原型的集合,并且返回产品对象。大量使用Composite和Decorator模式的设计通常也可从Prototype模式处获益。
Prototype模式提供了自我复制的功能,就是说新对象的创建可以通过已有对象进行创建。Prototype模式提供了一个通过已存在对象进行新对象创建的接口(Clone),Clone()实现和具体的实现语言相关,在C++中将通过拷贝构造函数实现之。
从一个对象再创建一个可定制的对象,而无需知道任何创建的细节,并能提高创建的性能。说白了就copy技术,把一个对象完整的copy出一份。
Prototype模式通过复制原型(Prototype)而获得新对象创建的功能,这里Prototype本身就是“对象工厂”(因为能够产生对象),实际上Prototype模式和Builder模式、Abstract
Factory模式都是通过一个类(对象实例)来专门负责对象的创建工作(工厂对象),它们之间的区别是:Builder模式重在复杂对象的一步步创建(并不直接返回对象),Abstract
Factory模式重在产生多个相互依赖类的对象,而Prototype模式重在从自身复制自己创建新类。
示例代码1:
#include <iostream> #include <vector> #include <string> using namespace std; class Prototype//抽象基类 { private: string m_strName; public: Prototype(string strName) {m_strName = strName;} Prototype() {m_strName = "";} void Show() { cout<<m_strName<<endl; } virtual Prototype* Clone() = 0; }; //class ConcretePrototype1 class ConcretePrototype1 : public Prototype { public: ConcretePrototype1(string strName) : Prototype(strName) {} ConcretePrototype1() {} virtual Prototype* Clone() { ConcretePrototype1* p = new ConcretePrototype1(); *p = *this;//复制对象 return p; } }; //class ConcretePrototype2 class ConcretePrototype2 : public Prototype { public: ConcretePrototype2(string strName) : Prototype(strName) {} ConcretePrototype2() {} virtual Prototype* Clone() { ConcretePrototype2* p = new ConcretePrototype2(); *p = *this;//复制对象 return p; } }; //客户端 int main() { ConcretePrototype1* test1 = new ConcretePrototype1("小王"); ConcretePrototype2* test2 = (ConcretePrototype2*)test1->Clone(); test1->Show(); test2->Show(); /* result: 小王 小王 */ return 0; } |
示例代码2:
prototype.h:
#ifndef _PROTOTYPE_H_ #define _PROTOTYPE_H_ class Prototype { public: virtual ~Prototype(); virtual Prototype* Clone() const = 0; protected: Prototype(); private: }; class ConcretePrototype : public Prototype { public: ConcretePrototype(); ConcretePrototype(const ConcretePrototype& cp); ~ConcretePrototype(); Prototype* Clone() const; protected: private: }; #endif//_PROTOTYPE_H_ |
prototype.cpp:
#include "prototype.h" #include <iostream> using namespace std; Prototype::Prototype() { } Prototype::~Prototype() { } Prototype* Prototype::Clone() const { return 0; } ConcretePrototype::ConcretePrototype() { } ConcretePrototype::~ConcretePrototype() { } ConcretePrototype::ConcretePrototype(const ConcretePrototype& cp) { cout<<"ConcretePrototype copy ..."<<endl; } Prototype* ConcretePrototype::Clone() const { return new ConcretePrototype(*this); } |
main.cpp:
#include "prototype.h" #include <iostream> using namespace std; int main() { Prototype* p = new ConcretePrototype(); Prototype* p1 = p->Clone(); /* result: ConcretePrototype copy ... */ return 0; } |
原型模式结构图:
设计模式之桥接模式(Bridge)摘录
Bridge:(1)、意图:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
(2)、适用性:A、你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换;B、类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充;C、对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译;D、(C++)你想对客户完全隐藏抽象的实现部分。在C++中,类的表示在类接口中是可见的;E、你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
(3)、优点:A、分离接口及其实现部分:一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。另外,接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。B、提高可扩充性:你可以独立地对Abstraction和Implementor层次结构进行扩充。C、实现细节对客户透明:你可以对客户隐藏实现细节,例如共享Implementor对象以及相应的引用计数机制(如果有的话)。
(4)、注意事项:A、仅有一个Implementor:在仅有一个实现的时候,没有必要创建一个抽象的Implementor类。这是Bridge模式的退化情况,在Abstraction和Implementor之间有一种一对一的关系。尽管如此,当你希望改变一个类的实现不会影响已有的客户程序时,模式的分离机制还是非常有用的----也就是说,不必重新编译它们,仅需重新连接即可。B、创建正确的Implementor对象:当存在多个Implementor类的时候,你应该用何种方法,在何时何处确定创建哪一个Implementor类呢?如果Abstraction知道所有的ConcreteImplementor类,它就可以在它的构造器中对其中的一个类进行实例化,它可以通过传递给构造器的参数确定实例化哪一个类。例如,如果一个collection类支持多重实现,就可以根据collection的大小决定实例化哪一个类。链表的实现可以用于较小的collection类,而hash表则可用于较大的collection类。另外一种方法是首先选择一个缺省的实现,然后根据需要改变这个实现。例如,如果一个collection的大小超出了一定的阈值时,它将会切换它的实现,使之更适合用于表目较多的collection.也可以代理给另一个对象,由它一次决定。C、共享Implementor对象。D、采用多重继承机制:在C++中可以使用多重继承机制将抽象接口和它的实现部分结合起来。例如,一个类可以用public方式继承Abstraction而以private方式继承ConcreteImplementor。但是由于这种方式依赖于静态继承,它将实现部分与接口固定不变的绑定在一起。因此不可能使用多重继承的方法实现真正的Bridge模式----至少用C++不行。
(5)、Abstract Factory模式可以用来创建和配置一个特定的Bridge模式。Adapter模式用来帮助无关的类协同工作,它通常在系统设计完成后才会被使用。然而,Bridge模式则是在系统开始时就被使用,它使得抽象接口和实现部分可以独立进行改变。
Bridge将抽象部分与实现部分分离,使它们可以独立变化。这里说的意思不是让抽象基类与具体类分离,而是现实系统可能有多角度分类,每一种分类都有可能变化,那么把这种多角度分离出来让它们独立变化,减少它们之间的耦合性,即如果继承不能实现”开放----封闭原则”的话,就应该考虑用桥接模式。
GoF在说明Bridge模式时,在意图中指出Bridge模式“将抽象部分与它的实现部分分离,使得它们可以独立地变化”。这句话很简单,但是也很复杂。原因就在于GoF的那句话中的“实现”该怎么去理解:“实现”特别是和“抽象”放在一起的时候我们“默认”的理解是“实现”就是“抽象”的具体子类的实现,但是这里GoF所谓的“实现”的含义不是指抽象基类的具体子类对抽象基类中虚函数(接口)的实现,是和继承结合在一起的。而这里的“实现”的含义指的是怎么去实现用户的需求,并且指的是通过组合(委托)的方式实现的,因此这里的实现不是指的继承基类、实现基类接口,而是指的是通过对象组合实现用户的需求。
示例代码1:
#include <iostream> #include <string> #include <vector> using namespace std; //手机软件 class HandsetSoft { public: virtual void Run() = 0; }; //游戏软件 class HandsetGame : public HandsetSoft { public: virtual void Run() { cout<<"运行手机游戏"<<endl; } }; //通讯录软件 class HandSetAddressList : public HandsetSoft { public: virtual void Run() { cout<<"手机通讯录"<<endl; } }; //手机品牌 class HandsetBrand { protected: HandsetSoft* m_soft; public: void SetHandsetSoft(HandsetSoft* temp) { m_soft = temp; } virtual void Run() = 0; }; //M品牌 class HandsetBrandM : public HandsetBrand { public: virtual void Run() { m_soft->Run(); } }; //N品牌 class HandsetBrandN : public HandsetBrand { public: virtual void Run() { m_soft->Run(); } }; //客户端 int main() { HandsetBrand* brand; brand = new HandsetBrandM(); brand->SetHandsetSoft(new HandsetGame()); brand->Run(); brand->SetHandsetSoft(new HandSetAddressList()); brand->Run(); /* result: 运行手机游戏 手机通讯录 */ return 0; } |
示例代码2:
abstraction.h:
#ifndef _ABSTRACTION_H_ #define _ABSTRACTION_H_ class AbstractionImp; class Abstraction { public: virtual ~Abstraction(); virtual void Operation() = 0; protected: Abstraction(); private: }; class RefinedAbstraction : public Abstraction { public: RefinedAbstraction(AbstractionImp* imp); ~RefinedAbstraction(); void Operation(); protected: private: AbstractionImp* _imp; }; #endif//_ABSTRACTION_H_ |
abstraction.cpp:
#include "abstraction.h" #include "abstractionImp.h" #include <iostream> using namespace std; Abstraction::Abstraction() { } Abstraction::~Abstraction() { } RefinedAbstraction::RefinedAbstraction(AbstractionImp* imp) { _imp = imp; } RefinedAbstraction::~RefinedAbstraction() { } void RefinedAbstraction::Operation() { _imp->Operation(); } |
abstractionImp.h:
#ifndef _ABSTRACTIONIMP_H_ #define _ABSTRACTIONIMP_H_ class AbstractionImp { public: virtual ~AbstractionImp(); virtual void Operation() = 0; protected: AbstractionImp(); private: }; class ConcreteAbstractionImpA : public AbstractionImp { public: ConcreteAbstractionImpA(); ~ConcreteAbstractionImpA(); virtual void Operation(); protected: private: }; class ConcreteAbstractionImpB : public AbstractionImp { public: ConcreteAbstractionImpB(); ~ConcreteAbstractionImpB(); virtual void Operation(); protected: private: }; #endif //_ABSTRACTIONIMP_H_ |
abstractionImp.cpp:
#include "abstractionImp.h" #include <iostream> using namespace std; AbstractionImp::AbstractionImp() { } AbstractionImp::~AbstractionImp() { } void AbstractionImp::Operation() { cout<<"AbstractionImp .... imp ..."<<endl; } ConcreteAbstractionImpA::ConcreteAbstractionImpA() { } ConcreteAbstractionImpA::~ConcreteAbstractionImpA() { } void ConcreteAbstractionImpA::Operation() { cout<<"ConcreteAbstractionImpA ...."<<endl; } ConcreteAbstractionImpB::ConcreteAbstractionImpB() { } ConcreteAbstractionImpB::~ConcreteAbstractionImpB() { } void ConcreteAbstractionImpB::Operation() { cout<<"ConcreteAbstractionImpB ...."<<endl; } |
main.cpp:
#include "abstraction.h" #include "abstractionImp.h" #include <iostream> using namespace std; int main() { AbstractionImp* imp = new ConcreteAbstractionImpA(); Abstraction* abs = new RefinedAbstraction(imp); abs->Operation(); /* result: ConcreteAbstractionImpA .... */ return 0; } |
桥接模式结构图:
|