一、单件(Singleton)
1、引言
C++中如何创建一个唯一的对象或实例?全局变量是一种,更好的替代方式是单件模式。
当某系统只能有一个**时,应该想到该模式。比如,系统中只有一个文件系统、打印机。
2、思路
图中,_instance用以记录唯一实例;GetInstace()用以返回_instance实例。
3、典型代码
(1)将Singleton类构造函数声明为private(更安全)或protected(当需要被继承时),故Singleton类不可以在外部被实例化。
(2)Singleton*Singleton::_instance = 0; //在.cpp中初始化
(3)在GetInstance()实现中:
if(_instance == 0) _instance = newSingleton(); //惰性Lazy初始化方法
return_instance;
(4)在main客户代码中:
Singleton*sgn = Singleton::GetInstance();
4、应用提示
(1)对于多线程程序,存在一种可能性——重复创建问题:对GetInstance()的调用同时发生,那么C++中将发生内存泄露。这时可以使用单件模式的变种——双重检查锁定Double-Checked Locking模式(该方法对JAVA无效):在“==0”检查之后进行同步,然后再次检查“==0”以确保实例尚未被创建。代码如下:
class Singleton
{
staticSingleton * _instance;
Singleton();
public:
static Singleton*GetInstance();
}
Singleton*Singleton::_instance = 0;
Singleton*Singleton:: GetInstance()
{
if (_instance == 0)
{
//do sync here进行同步操作
if (_instance == 0)
_instance = newSingleton();
}
return _instance;
}
(2)当Singleton存在多个子类时,有两种方式完成运行时决定实例化哪个子类:一是,在Singleton的GetInstance()实现中进行if判断(默认是new Singleton);另一种更灵活的方法是使用一个单件注册表(registry of singleton)——基类必须实现注册表功能。
(3)《Head First》提到:“如果你的程序出现大量单件,那么你可能需要好好检查你的设计。因为通常适用使用单件模式的机会不多。”
二、原型(Prototype)
1、引言
抽象工厂模式中提到过,对于童装和成人装,需要设立不同的具体工厂来生产。若要新上一个老年装系列产品,可以考虑重新设厂,但更经济的做法如下:复制成人装工厂的各条产线,通过微调初始化生产参数,从而完成老年装的生产。
2、思路
原型模式,是在一个既成实例基础上,拷贝创建新的对象。典型思路如下图。当中可能需要应用一个独立的Initialize()函数来重新初始化拷贝过来的对象内部状态。
3、典型代码
(1)在具体类ConcretePrototype1/2中声明:
ConcretePrototype(constConcretePrototype& cp); //拷贝构造函数
Prototype*Clone() const;
(2)在Clone()实现中,return new ConcretePrototype(*this);
(3)在客户main()中,
Prototype*p = new ConcretePrototype();
Prototype*p1 = p->Clone();
4、应用提示
(1)原型模式中,最困难的部分在于如何正确实现Clone()。C++中提供了拷贝构造函数,典型代码中,用了编译器缺省方式(按位拷贝/按成员拷贝),即两个对象共享指针。为了使复制对象和原对象保持相对独立性,需要进行深拷贝。关注“深拷贝”和“浅拷贝”的区别。
(2)该模式的主要缺陷是需要每一个Prototype子类都实现Clone操作。
(3)除了和工厂方法的竞争和协同关系之外,大量使用组成Composite模式和装饰Decorator模式的设计通常会用到原型模式。
三、生成器(Builder)
1、引言
作为一个现代化的成熟汽车厂商,需要向市场推出几款车型以适应不同的消费群体。为了构造某一款车,需要在生产的各个阶段(如发动机生产、车身外观设计、底座设计等等)给定不同的生产参数,当然这个工程会非常庞大复杂。而作为一个成熟的体系,应当将构建的机制隐藏在底层车间,当顾客需要某款车时,只需要跟总体部沟通,由它向各车间传达一些参数即可向顾客呈现所需车型。Builder模式就是为了将复杂对象的构建与展示分离,使得同样的构建过程可以有不同的展现;当中的导向器Director就好比总体部,负责调度构造使用生成器的接口。
2、思路
作为客户,需要创建Director对象,同时配置所需的Builder对象。然后,导向器Director会利用一个函数Construct()通知具体生成器ConcreteBuilder完成各阶段构造工作。最后,客户从ConcreteBuilder中获取产品。
3、典型代码
(1)Director类声明:
Director(Builder*bld); //构造函数
Private: Builder* _bld;
VoidConstruct();
(2)在Director()构造函数实现中: _bld= bld;
(3)在Construct()实现中:
_bld->BuildPartA("user-defined");
_bld->BuildPartB("user-defined");
(4)ConcreteBuilder类声明: BuildPartA/B("user-defined")以及 Product*GetProduct();
(5)在GetProduct()实现中: returnnew Product();
(6)在客户main()中:
Director*d = new Director(new ConcreteBuilder());
d->Construct();
Product*p1 = (*d). _bld->GetProduct();
4、应用提示
(1)一般来说Builder模式中对象不是直接返回的,它强调一步步构建复杂对象,运用相同的构造过程创建不同的对象(可能是通过Construct()函数传入上述参数"user-defined"来实现),由客户来通过调用ConcreteBuilder从而获取Product对象。
(2)Builder模式和Abstract Factory模式都用于复杂对象的创建。但侧重点不同,前者强调一步步的创建过程;后者强调一系列相关对象的创建。
(3)组成Composite模式通常是用Builder生成的。