创建型设计模式总结
(转载请注明来源 http://www.cnblogs.com/jerry19880126/)
创建型设计模式包括简单工厂模式,普通工厂模式,抽象工厂模式,建造者模式,原型模式和最简单的单例模式。
简单工厂模式(Simple Factory)
从UML图中可以看出,工厂是具体的,Product是抽象的,里面的方法Operation是virtual的,它的三个子类是具体的,子类中的Operation覆盖父类的方法Operation,由多态知识可知,运行时将会调用子类的Operation,父类的Operation只是声明的“接口”。
多态有三个条件:一是父类的virtual,二是子类的覆盖(要求函数名、参数、返回值都要一模一样),三是父类的指针或引用指向子类的对象。前两个条件已经满足,下面关键是讨论第三个条件。
第三个条件的关键就是Factory了,Factory能根据客户端的请求,生成不同的具体对象,这可以用flag来标识,假定flag = 1时,生成ConcreteProduct1对象;flag = 2时,生成ConcreteProduct2对象。因此,可以在Factory这样写CreateProduct()。
Product* CreateProduct(flag)
{
Switch(flag)
case 1: return new ConcreateProduct1(); break;
case 2: return new ConcreateProduct2(); break;
case 3:…
}
在客户端只要用
Factory f; // 生成factory对象
f.getProduct(1).Operation();就可以调用ConcreteProduct1的方法了
f.getProduct(2).Operation();就可以调用ConcreteProudct2的方法了。
这样说来,相信读者已经明白,其实工厂方法就是根据客户端不同的“要求”,产生不同的具体对象,再利用多态特性,调用相应具体对象的方法。
下面给出可执行的源代码,与上述例子不尽相同,但思想是一样的,运行结果如下图所示。
1 #include2 using namespace std; 3 4 // 简单工厂模式 5 6 // 抽象产品 7 class AbstractProduct 8 { 9 public: 10 virtual void getProductsName() = 0; 11 }; 12 13 // 具体产品1 14 class ConcreteProduct1: public AbstractProduct 15 { 16 public: 17 void getProductsName() 18 { 19 cout << "ConcreteProduct1" << endl; 20 } 21 }; 22 23 24 // 具体产品2 25 class ConcreteProduct2: public AbstractProduct 26 { 27 public: 28 void getProductsName() 29 { 30 cout << "ConcreteProduct2" << endl; 31 } 32 }; 33 34 35 // 具体的工厂(没有抽象工厂) 36 class ConcreteFactory 37 { 38 public: 39 AbstractProduct* getProductObject(int flag) 40 { 41 if(flag == 1) 42 { 43 return new ConcreteProduct1(); 44 } 45 else if(flag == 2) 46 { 47 return new ConcreteProduct2(); 48 } 49 else 50 { 51 return 0; 52 } 53 } 54 }; 55 56 int main() 57 { 58 ConcreteFactory f; 59 AbstractProduct* p1 = f.getProductObject(1); 60 AbstractProduct* p2 = f.getProductObject(2); 61 p1->getProductsName(); 62 p2->getProductsName(); 63 delete p1; 64 delete p2; 65 return 0; 66 }
运行结果如下:
(普通)工厂模式(Factory)
与简单工厂模式换汤不换药,只是把工厂也“抽象”了,UML图如下所示:
从上图可以看出,只不过多出一块抽象工厂而已。抽象工厂提供CreateProduct的虚接口,在ConcreteFactory中实现,为了便于说明问题,这里假定有两个ConcreteFactory,一个是ConcreteFactory1,只生产ConcreteProduct1产品,另一个是ConcreteFactory2,只生产ConcreteProduct2产品。
以ConcreteFactory1为例,代码框架如下:
class ConcreateFactory1: public Factory
{
Product* CreateProduct()
{
return new ConcreteProduct1();
}
};
在客户端用 Factory *f = new ConcreteFactory1(); f->CreateProduct();就可以得到ConcreteProduct1的对象了。
下面给出可执行的源代码,运行结果的截图放在后面。
1 #include2 using namespace std; 3 4 //普通工厂模式 5 6 //抽象产品 7 class AbstractProduct 8 { 9 public: 10 virtual void getProductName() = 0; 11 }; 12 13 //具体产品1 14 class ConcreteProduct1: public AbstractProduct 15 { 16 public: 17 void getProductName() 18 { 19 cout << "ConcreteProduct1" << endl; 20 } 21 }; 22 23 //具体产品2 24 class ConcreteProduct2: public AbstractProduct 25 { 26 public: 27 void getProductName() 28 { 29 cout << "ConcreteProduct2" << endl; 30 } 31 }; 32 33 34 //抽象工厂 35 class AbstractFactory 36 { 37 public: 38 virtual AbstractProduct* getProduct() = 0; 39 }; 40 41 //具体工厂1 42 class ConcreteFactory1: public AbstractFactory 43 { 44 public: 45 AbstractProduct* getProduct() 46 { 47 return new ConcreteProduct1(); 48 } 49 }; 50 51 52 //具体工厂2 53 class ConcreteFactory2: public AbstractFactory 54 { 55 public: 56 AbstractProduct* getProduct() 57 { 58 return new ConcreteProduct2(); 59 } 60 }; 61 62 int main() 63 { 64 AbstractFactory* f1 = new ConcreteFactory1(); 65 AbstractFactory* f2 = new ConcreteFactory2(); 66 f1->getProduct()->getProductName(); 67 f2->getProduct()->getProductName(); 68 delete f1, f2; 69 return 0; 70 }
运行结果如下:
抽象工厂模式(Abstract Factory)
抽象工厂又是(普通)工厂模式的升级版,但本质是相同的。观察UML图,可以看到不同的地方在于多了一个抽象产品的类。
ConcreateFactory1只生产ProductA1和ProductB1,即下标带“1”的产品。可以预见,在ConcreteFactory1中的两个方法应该如下:
AbstractProductA* CreateProductA()
{
return new ProductA1();
}
AbstractProductB* CreateProductB()
{
return new ProductB1();
}
ConcreateFactory2中的两个方法类似,只是将最后的下标换成2而已。
下面给出可以执行的源代码,运行截图放在代码的后面。
1 #include2 3 using namespace std; 4 5 6 7 // 抽象工厂模式 8 9 10 11 // 抽象产品A 12 13 class AbstractProductA 14 15 { 16 17 public: 18 19 virtual void getProductName() = 0; 20 21 }; 22 23 24 25 // 具体产品A1 26 27 class ConcreteProductA1: public AbstractProductA 28 29 { 30 31 public: 32 33 void getProductName() 34 35 { 36 37 cout << "ConcreteProductA1" << endl; 38 39 } 40 41 }; 42 43 44 45 46 47 // 具体产品A2 48 49 class ConcreteProductA2: public AbstractProductA 50 51 { 52 53 public: 54 55 void getProductName() 56 57 { 58 59 cout << "ConcreteProductA2" << endl; 60 61 } 62 63 }; 64 65 66 67 68 69 // 抽象产品B 70 71 class AbstractProductB 72 73 { 74 75 public: 76 77 virtual void getProductName() = 0; 78 79 }; 80 81 82 83 // 具体产品B1 84 85 class ConcreteProductB1: public AbstractProductB 86 87 { 88 89 public: 90 91 void getProductName() 92 93 { 94 95 cout << "ConcreteProductB1" << endl; 96 97 } 98 99 }; 100 101 102 103 104 105 // 具体产品B2 106 107 class ConcreteProductB2: public AbstractProductB 108 109 { 110 111 public: 112 113 void getProductName() 114 115 { 116 117 cout << "ConcreteProductB2" << endl; 118 119 } 120 121 }; 122 123 124 125 126 127 // 抽象工厂 128 129 class AbstractFactory 130 131 { 132 133 public: 134 135 virtual AbstractProductA* getProductA() = 0; 136 137 virtual AbstractProductB* getProductB() = 0; 138 139 }; 140 141 142 143 144 145 // 具体工厂1 146 147 class ConcreteFactory1: public AbstractFactory 148 149 { 150 151 AbstractProductA* getProductA() 152 153 { 154 155 return new ConcreteProductA1; 156 157 } 158 159 AbstractProductB* getProductB() 160 161 { 162 163 return new ConcreteProductB1; 164 165 } 166 167 }; 168 169 170 171 // 具体工厂2 172 173 class ConcreteFactory2: public AbstractFactory 174 175 { 176 177 AbstractProductA* getProductA() 178 179 { 180 181 return new ConcreteProductA2; 182 183 } 184 185 186 187 AbstractProductB* getProductB() 188 189 { 190 191 return new ConcreteProductB2; 192 193 } 194 195 }; 196 197 198 199 200 201 int main() 202 203 { 204 205 AbstractFactory *f1 = new ConcreteFactory1(); 206 207 AbstractFactory *f2 = new ConcreteFactory2(); 208 209 f1->getProductA()->getProductName(); 210 211 f1->getProductB()->getProductName(); 212 213 f2->getProductA()->getProductName(); 214 215 f2->getProductB()->getProductName(); 216 217 delete f1, f2; 218 219 return 0; 220 221 }
运行结果如下:
“工厂系列”设计模式总结
下面总结一下“工厂系列”设计模式,简单工厂模式只有一份抽象的产品,工厂是具体的;(普通)工厂模式的同样也只有一份抽象的产品,但工厂有抽象的了;抽象工厂模式工厂当然是抽象的,但是它独特的地方在于产品至少有两份是抽象的。
建造者模式(Builder)
建造者模式包含一个抽象的Builder类,还有它的若干子类——ConcreteBuilder,不用理会UML图上的Product,关键是看Director,Director里面的方法Construct()其实包含了Builder指针或引用的形参,由客户端传入某个ConcreateBuilder对象。Construct(Builder* builder)的方法大致如下:
Construct(Builder* builder)
{
Builder->BuildPartA();
Builder->BuildPartB();
…
}
由多态性可知,客户端传进来的ConcreteBuilder是谁,就调用谁的方法。
可执行的源代码如下,运行结果在源代码的后面。
1 #include2 3 using namespace std; 4 5 6 7 // 建造者模式 8 9 10 11 // 抽象建造者 12 13 class AbstractBuilder 14 15 { 16 17 public: 18 19 virtual void buildPart1() = 0; 20 21 virtual void buildPart2() = 0; 22 23 }; 24 25 26 27 28 29 //具体建造者1 30 31 class ConcreteBuilder1: public AbstractBuilder 32 33 { 34 35 public: 36 37 void buildPart1() 38 39 { 40 41 cout << "用A构造第一部分" << endl; 42 43 } 44 45 void buildPart2() 46 47 { 48 49 cout << "用B构造第二部分" << endl; 50 51 } 52 53 }; 54 55 56 57 58 59 //具体建造者2 60 61 class ConcreteBuilder2: public AbstractBuilder 62 63 { 64 65 public: 66 67 void buildPart1() 68 69 { 70 71 cout << "用X构造第一部分" << endl; 72 73 } 74 75 void buildPart2() 76 77 { 78 79 cout << "用Y构造第二部分" << endl; 80 81 } 82 83 }; 84 85 86 87 // 指挥者,注意其方法的参数是抽象建造者的指针 88 89 class Director 90 91 { 92 93 public: 94 95 void build(AbstractBuilder *builder) 96 97 { 98 99 builder->buildPart1(); 100 101 builder->buildPart2(); 102 103 } 104 105 }; 106 107 108 109 int main() 110 111 { 112 113 Director d; 114 115 d.build(new ConcreteBuilder1()); 116 117 d.build(new ConcreteBuilder2()); 118 119 return 0; 120 121 }
运行结果如下:
原型模式(Prototype)
听起来挺玄乎,其实说穿了,就是深拷贝问题。当一个类中包含了指针,那么这个类一定要显示规定三个东西:拷贝构造函数,重载”=”操作符以及析构函数。如果程序员使用编译器默认产生的这三个函数,那么得到的对象是原来对象的“浅拷贝”,即只是简单拷贝了指针的值(只复制了地址),没有复制指针指向空间的内容。“浅拷贝”只会保留最近的修改结果,而且在析构时容易出现重复析构的错误。
“深拷贝”是相对浅拷贝的概念说的,深拷贝不是简单的拷贝指针的值(地址),而是重新生成了一个新的空间,这个空间里存放的内容与传入类内容是完全相同的。
请看下面“浅拷贝”的实例:
1 #include2 3 using namespace std; 4 5 6 7 // 原型模式,本质就是深拷贝 8 9 10 11 // 浅拷贝,这时可以观察到p的地址是一样的,析构的时候因为重复释放同一地址空间,所以 12 13 // 会出错。 14 15 class PrototypeWrong 16 17 { 18 19 private: 20 21 int a; 22 23 int *p; // 有一个指针 24 25 public: 26 27 PrototypeWrong() 28 29 { 30 31 a = 3; 32 33 p = new int(2); 34 35 } 36 37 void outputPointerAddress() 38 39 { 40 41 cout << p << endl; 42 43 } 44 45 46 47 ~PrototypeWrong() 48 49 { 50 51 delete p; 52 53 } 54 55 }; 56 57 58 59 int main() 60 61 { 62 63 // 这一部分是错误的原型模式的测试样例 64 65 PrototypeWrong p1; 66 67 PrototypeWrong p2 = p1; 68 69 p1.outputPointerAddress(); 70 71 p2.outputPointerAddress(); 72 73 }
运行结果为:
可以看到指针值(地址)是相同的,所以是浅拷贝,程序没有出现“请按任意键继续”的提示,说明程序其实是卡死的,原因是重复析构指针p。
再看看“深拷贝”的实例:
1 #include2 3 using namespace std; 4 5 6 7 // 原型模式,本质就是深拷贝 8 9 10 11 // 深拷贝,正确的原型模式 12 13 class PrototypeRight 14 15 { 16 17 private: 18 19 int a; 20 21 int *p; // 有一个指针 22 23 public: 24 25 PrototypeRight() 26 27 { 28 29 a = 3; 30 31 p = new int(2); 32 33 } 34 35 36 37 // 不使用默认的拷贝构造函数! 38 39 PrototypeRight(const PrototypeRight& obj) 40 41 { 42 43 a = obj.a; 44 45 p = new int(*obj.p); 46 47 } 48 49 50 51 void outputPointerAddress() 52 53 { 54 55 cout << p << endl; 56 57 } 58 59 60 61 ~PrototypeRight() 62 63 { 64 65 delete p; 66 67 } 68 69 }; 70 71 72 73 int main() 74 75 { 76 77 // 这一部分是正确的原型模式的测试样例 78 79 80 81 PrototypeRight p1; 82 83 PrototypeRight p2 = p1; 84 85 p1.outputPointerAddress(); 86 87 p2.outputPointerAddress(); 88 89 return 0; 90 91 92 93 }
运行结果如下:
可见指针值不同了,说明指向了不同的空间,而且成功显示了“请按任意键继续”的提示符,说明析构也是正常了。但这里的程序还不完整,按照C++的程序风格,还应该重载“=”运算符,这里的练习便留给读者。
单例模式(Singleton)
顾名思义,就是保证某个类只有一个实例(对象),这个应用还是很广的,假设腾迅想让用户每次只能用一个QQ登陆,就可以用到这个模式。
这个UML图非常简单,可以说也是所有设计模式中最简单的了,所以在面试中,常常被面试官们问起。
要使一个类只能生成一个对象,就是要限制使用它的构造函数,即将构造函数定义为private或protected的,然后另辟一个公有方法Instance,在这个方法里检查instance(instance是指向本类的一个指针或引用,这在C++语法中是可以的)是否为空指针,若为空指针,则说明是第一次生成对象,那么操作是允许的,instance = new Singleton(),若指针非空,说明在之前已经有一个对象(实例)了,单例模式不允许再次生成实例,因此直接返回之前生成的对象的地址。
将instance定义成static变量,就更符合“单例”模式了,因为static变量只有一份,它属于这个类,不属于某个对象。相应的Instance()方法应该也定义成static的,用Singleton::Instance()来调用。注意这里的static方法和变量是必须的,如果函数不是static,则要事先生成对象才能调用Instance,就破坏了“单例”的思想了,如果变量不是static,那么静态函数Instance又不能引用非static变量。
下面给出可以执行的源程序:
1 #include2 3 using namespace std; 4 5 6 7 // 单例模式 8 9 class Singleton 10 11 { 12 13 private: 14 15 Singleton(){}; // 不允许直接构造其对象 16 17 static Singleton *instance; 18 19 20 21 public: 22 23 static Singleton* createInstance() 24 25 { 26 27 if(!instance) 28 29 { 30 31 // 对象第一次被创建,允许 32 33 cout << "创建新对象" << endl; 34 35 instance = new Singleton(); 36 37 } 38 39 else 40 41 { 42 43 // 请求再次创建对象,不允许 44 45 cout << "已经创建过对象了,返回原对象" << endl; 46 47 } 48 49 return instance; 50 51 } 52 53 void getAddress() 54 55 { 56 57 cout << "我的地址是 " << instance << endl; 58 59 } 60 61 }; 62 63 64 65 Singleton* Singleton::instance = 0; //在初始化的时候,不能在前面加static了 66 67 68 69 int main() 70 71 { 72 73 //Singleton s;//报错:无法访问 private 成员(在“Singleton”类中声明) 74 75 Singleton *s1 = Singleton::createInstance(); 76 77 s1->getAddress(); 78 79 80 81 cout << endl << endl; 82 83 84 85 Singleton *s2 = Singleton::createInstance(); 86 87 s2->getAddress(); 88 89 return 0; 90 91 }
运行结果为: