Builder(生成器)——对象创建型模式 1. 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以器创建不同的表示。
2. 动机 面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成,由于需求变化,这个复杂对象的各个部分经常变化,但它们组合在一起的算法很稳定。
3. 适用性 在以下情况下使用Builder模式:
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时 当构造过程必须允许被构造的对象有不同的表示时 4. 结构
5. 参与者 Builder为创建一个Product对象的各个部件指定抽象接口 ConcreteBuilder实现Builder的接口以构造和装配该产品的各个部件 定义并跟踪它所创建的表示 提供一个检索产品的接口 Director Product表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程 包含定义组成部件的类,包括将这些部件装配成最终产品的接口 6. 协作 下面的交互图说明了Builder和Director是如何与一个客户协作的。
7. 效果 它使你可以改变一个产品的内部表示 。Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变产品的内部表示时所要做的只是定义一个新的生成器。它将构造代码和表示分开 。Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息,这些类是不出现在Builder接口中的。它使你可对构造过程进行更精细的控制 。Builder模式与一下子就生成产品的创建模式不同,它是在导向器的控制下一步一步构造产品的。8. 示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 #include <iostream> #include <string> #ifndef CREATIONPATTERNDESIGN_BUILDER_H #define CREATIONPATTERNDESIGN_BUILDER_H using namespace std;void test_builder () ;struct Computer { string cpu; string memory; string mainboard; void show_info () { cout <<"CPU:" << cpu << " memory:" << memory << " mainboard:" << mainboard << endl; } };class ComputerBuilder {public : virtual void build_computer () { computer = new Computer; } virtual void build_cpu () {} virtual void build_mainboard () {} virtual void build_memory () {} virtual Computer *get_computer () { if (computer != nullptr ) { return computer; } return nullptr ; }protected : Computer *computer; };class ComputerBuilderA : public ComputerBuilder { virtual void build_cpu () { if (computer != nullptr ) { computer->cpu = "Intel" ; } } virtual void build_mainboard () { if (computer != nullptr ) { computer->mainboard = "微星" ; } } virtual void build_memory () { if (computer != nullptr ) { computer->memory = "三星" ; } } };class ComputerBuilderB : public ComputerBuilder { virtual void build_cpu () { if (computer != nullptr ) { computer->cpu = "AMD" ; } } virtual void build_mainboard () { if (computer != nullptr ) { computer->mainboard = "华硕" ; } } virtual void build_memory () { if (computer != nullptr ) { computer->memory = "致钛" ; } } };class Factory {public : Factory (ComputerBuilder* builder) : builder (builder) {} Computer* make_computer () { builder->build_computer (); builder->build_cpu (); builder->build_mainboard (); builder->build_memory (); return builder->get_computer (); }private : ComputerBuilder *builder; };#endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> #include "Builder.h" void test_builder () { cout << "——————————开始测试Builder模式——————————" << endl; ComputerBuilder* cba = new ComputerBuilderA; ComputerBuilder* cbb = new ComputerBuilderB; Factory fa (cba) ; Factory fb (cbb) ; fa.make_computer ()->show_info (); fb.make_computer ()->show_info (); cout << "——————————结束测试Builder模式——————————" << endl; }
9. 相关模式 Abstract Factory与Builder相似,因为它也可以创建复杂对象。主要区别是Builder模式着重于一步步构造一个复杂对象。而Abstract Factory 着重于多个系列的产品对象(简单的或复杂的)。Builder在最后一步返回产品,而对于Abstract Factory 来说,产品是立即返回的。
Composite模式通常是用Builder生成的。
Singleton(单例)——对象创建型模式 1. 意图 保证一个类仅有一个实例,并提供一个访问它的全局访问点
2. 动机 对于一些类来说,只有一个实例是很重要的。例如,虽然系统中可以有许多打印机,但却只应该有一个打印假脱机(printer spooler) ,只应该有一个文件系统和一个窗口管理器。一个会计系统只能专用于一个公司。
怎样才能保证一个类只有一个实例并且这个实例易于被访问呢?全局变量使得一个对象可以被访问,但它不能防止你实例化多个对象。
一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。这就是Singleton模式。
3. 适用性 在下面的情况下可以使用Singleton模式:
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无序更改代码就能使用一个扩展的实例时。 4. 结构
5. 参与者 Singleton定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作(可以是C++中的一个静态成员函数) 可能负责创建它自己的唯一实例 6. 协作 客户只能通过Singleton的Instance操作访问一个Singleton的实例 7. 效果 Singleton模式有许多优点:
对唯一实例的受控访问 。因为Singleton类封装它的唯一实例,所以它可以严格地控制客户怎样以及何时访问它。缩小命名空间 。Singleton模式是对全局变量的一种 改进,它避免了那些存储唯一实例的全局变量污染命名空间允许对操作和表示的精化 。Singleton类可以有子类,而且用这个扩展类的实例来配置一个应用是很容易的。你可以用你所需要的类的实例在运行时配置应用允许可变数目的实例 。这个模式使得你易于改变你的想法,并允许Singleton类的多个实例。8. 实现 下面是使用Singleton模式时需要考虑的实现问题。
保证一个唯一的实例。在C++中可以用Singleton类的静态成员函数Instance来定义这个类操作 Instance可以使用惰性(lazy)初始化,即只有第一次被访问时才创建实例 创建Singleton类的子类。最简单的技术是在Singleton的Instance操作中决定你想使用的是哪一个单例。另一个选择Singleton的子类的方法是将Instance的实现从父类中分离出来并将它放入子类。一个更灵活的方法是使用一个单例注册表(registry of singleton)。可能的Singleton类的集合不是由Instance定义的,Singleton类可以根据名字在一个众所周知的注册表中注册它们的单例实例。这个注册表可以在字符串名字和单例之间建立映射。当Instance需要一个单例时,它参考注册表,根据名字请求单例。 9. 示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include <iostream> #ifndef CREATIONPATTERNDESIGN_SINGLETON_H #define CREATIONPATTERNDESIGN_SINGLETON_H class Singleton {public : static Singleton* get_instance () { static Singleton instance; return &instance; }private : Singleton () {} ~Singleton () {} Singleton (const Singleton& singleton) = delete ; Singleton operator = (const Singleton& singleton) = delete ; };class Singleton2 {public : static Singleton2* get_instance () { if (instance == nullptr ) { std::lock_guard<std::mutex> lock (mutex) ; if (instance == nullptr ) { instance = new Singleton2 (); } } return instance; }private : static Singleton2* instance; static std::mutex mutex; class GC { public : ~GC () { if (Singleton2::instance != nullptr ) { delete Singleton2::instance; Singleton2::instance = nullptr ; } } }; static GC gc; }; Singleton2* Singleton2::instance = nullptr ; Singleton2::GC Singleton2::gc; std::mutex Singleton2::mutex;class Singleton3 {public : static Singleton3* get_instance () { return &instance; }private : Singleton3 () {} ~Singleton3 () {} Singleton3 (const Singleton3& singleton) = delete ; Singleton3 operator = (const Singleton3& singleton) = delete ; static Singleton3 instance; }; Singleton3 Singleton3::instance;#endif
10. 相关模式 很多模式都可以用Singleton模式实现,比如Abstract Factory,Builder,Prototype。