设计模式实战精讲:创建型模式
本文章将重点讲解创建型模式,在本人分布的《C++设计模式:前传》中曾简单概述了一下创建型模式细分多少种设计模式,本篇文章将讲解这些设计模式的理论,优缺点和代码实现。

目录
1.前言
2.工厂模式
1.简单工厂模式
1.工厂模式
3.原型模式
4.单例模式
5.建造者模式
6.抽象工厂模式
7.创建型模式总结
前言
本文章将重点讲解创建型模式,在本人分布的《C++设计模式:前传》中曾简单概述了一下创建型模式细分多少种设计模式,本篇文章将讲解这些设计模式的理论,优缺点和代码实现。

图1.创建型模式区分示意
工厂模式
工厂模式内含简单工厂模式,是简单工厂模式的泛化,而简单工厂模式是工厂方法模式的一个特例。当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对 象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭” 原则,而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好,所以使用工厂模式。这里我将分开讲解工厂模式和简单工厂模式,先由简单工厂模式进行解析,以浅入深
1.简单工厂模式
1.简单工厂模式:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类,而使用简单工厂模式能减少客户程序对类创建过程的依赖
2.简单工厂实现步骤:
1.定义一个工厂类:负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
2.定义一个抽象产品类:负责描述所有实例所共有的公共接口
3.定义一个具体产品类:创建的具体实例对象
3.优点:帮助封装,能实现组件封装,面向接口编程,客户端和具体实现类的解耦合
4.缺点:可能增加客户端的复杂度,不方便扩展子工厂
5.简单工厂模式实现代码:
class Operation{ //产品抽象类 public: double m_leftVlaue; double m_rightValue; virtual double GetResult() = 0;}; class AddOperation:public Operation{ //具体产品实现类 double GetResult(){ return m_leftVlaue + m_rightValue; }};class OperatorFactory{ //工厂类 public: //返回一个产品抽象类指针 static Operation* createOperation(char c){ switch (c){ case '+': return new AddOperation; break; } }}; int main(){ //定义一个抽象产品类指针operation,赋初值为AddOperation(具体产品实现类)对象 Operation* operation = OperatorFactory::createOperation('+'); operation->m_leftVlaue = 1; operation->m_rightValue = 2; cout << operation->GetResult() << endl; return 0;} 2.工厂模式
1.工厂模式:通过工厂类封装对象的创建过程,将对象的创建与使用分离
2.工厂模式实现步骤:
1.定义一个抽象工厂类 :所有具体工厂类的父类
2.定义一个抽象产品类:所有产品的父类
3.定义与产品对应的工厂类:负责实例化产品对象
4.定义具体的产品类:对应产品的对象
3.优点:业务需求改变时代码改动最小,具体的创建实例的过程与客户端分离
4.缺点:新增功能时,工程量大
5.工厂模式实现代码:
class AbstractProduct{ //定义抽象的产品类 public: virtual void makeProduct() = 0;};class AbstractFactory{ //定义抽象的工厂类 public: virtual AbstractProduct* createProduct() = 0;};class PlaneProduct : public AbstractProduct{ //定义具体的产品类 public: void makeProduct(){ cout << "产品A" << endl; }};class PlaneFactory : public AbstractFactory{ //定义具体的工厂类 public: AbstractProduct* createProduct(){ AbstractProduct* product = new PlaneProduct; return product; }};int main(){ //定义一个AbstractFactory类(抽象的工厂类)指针,指向PlaneFactory类(具体的工厂类)对象 AbstractFactory* factory = new PlaneFactory(); /*定义一个AbstractProduct类(抽象的产品类)指针 指向具体的工厂类对象调用createProduct()函数所返回的具体的产品类对象 */ AbstractProduct* product = factory->createProduct(); product->makeProduct(); return 0; }原型模式
1.原型模式:克隆指定对象就是原型模式,在对象的创建工作中由于需求的变化,对象的函数内部实现经常会变化,但是对象的接口稳定一致,所以使用原型模式
2.原型模式实现步骤:
1.定义抽象原型类:规定了具体对象必须实现的接口
2.定义多个具体原型类:实现抽象原型类的实例
3.定义访问类:使用具体原型类中的方法来复制新的对象
3.优点:简化对象的创建,无需理会创建过程,提高对象的创建过程的效率,可以在程序运行时获得一个内容相同的对象,但是期间互不干扰(感觉这不算优点)
4.缺点:每一个类都必须实现克隆方法(有些代码规范中会将赋值构造函数和拷贝构造函数定义为私有,防止不必要的拷贝)
5.原型模式实现代码:
class Monkey{ //定义抽象原型类 public: Monkey() {} virtual ~Monkey() {} virtual void Play() = 0; virtual Monkey* Clone() = 0; //克隆函数};class SunWuKong : public Monkey { //定义抽象原型类的实例类 public: SunWuKong(string name) { m_strName = name; } ~SunWuKong() {} SunWuKong(const SunWuKong& other) { //拷贝构造函数 m_strName = other.m_strName; } Monkey* Clone(){ //克隆函数 return new SunWuKong(*this); //调用拷贝构造函数 } void Play(){ cout << m_strName << ":金箍棒" << endl; } private: string m_strName; };int main() { //定义一个原型对象mokey Monkey* monkey = new SunWuKong("齐天大圣孙悟空"); //克隆出多个原型对象 Monkey* m1= monkey->Clone(); Monkey* m2 = m1->Clone(); m1->Play(); m2->Play(); //记得delete防止内存泄漏 delete monkey; delete m1; delete m2; return 0;}单例模式
1.单例模式:保证为一个类只生成唯一的实例对象,在程序中只能调用该对象实现功能,类似于全局变量。当程序需要生成唯一序列的环境需要频繁实例化然后销毁的时候,或者创建对象时耗时过多或者耗资源过多,但又经常用到的对象,此时便需要设计为单例模式
2.单例模式实现步骤:
1.将类的构造函数私有化
2.类中提供一个全局的静态方法,访问唯一对象
3.类中定义一个静态指针,指向唯一对象
3.优点:在内存中只有一个对象,节省内存空间,而且能避免频繁的创建销毁对象,避免对共享资源的多重占用,能为整个程序提供一个全局访问对象
4.缺点:不适用于变化频繁的对象
5.单例模式实现代码:
单例模式实现代码分为懒汉式和饿汉式:
1.懒汉式:在程序的第一次请求使用对象时,才创建对象并分配内存,优点是避免了不必要的内存占用,缺点是会存在线程安全问题
//懒汉式class SingleTon; //前向声明class SingleTon{ //定义单例对象的类 private: SingleTon();//构造函数设为私有 public: static SingleTon* m_singleTon; //定义指针指向具体的类 static SingleTon* GetInstance(); void TestPrint();};//懒汉式中声明的全局指针m_singleTon并没有指向具体的对象SingleTon* SingleTon::m_singleTon = NULL;int main() { SingleTon* p1 = SingleTon::GetInstance(); cout << "p1:"<< hex << p1 << endl; p1->TestPrint(); return 0; } SingleTon::SingleTon(){ //实现类中的构造函数 m_singleTon = NULL;}SingleTon* SingleTon::GetInstance(){ //实现类中的获取对象函数 if(m_singleTon == NULL){ m_singleTon = new SingleTon; return m_singleTon; }void SingleTon::TestPrint(){ //实现类中的接口 cout << "测试调用....." << endl;}2.饿汉式:在程序启动初期就创建对象并分配内存,优点是不会存在线程安全问题,缺点是会导致不必要的内存占用
//饿汉式class SingleTon{ private: SingleTon(); public: static SingleTon* m_singleTon; static SingleTon* GetInstance(); void TestPrint();};//饿汉式创建单例对象时,就已经将指针赋值为具体对象SingleTon* SingleTon::m_singleTon = new SingleTon;int main(){ SingleTon* p1 = SingleTon::GetInstance(); cout << "p1:"<< hex << p1 << endl; p1->TestPrint(); return 0;}SingleTon::SingleTon() { //实现类中的构造函数 m_singleTon = NULL;}SingleTon* SingleTon::GetInstance(){ //实现类中的获取对象函数 return m_singleTon;}void SingleTon::TestPrint(){ //实现类中的接口 cout << "测试调用....." << endl;}建造者模式
1.建造者模式:将一个复合对象的构造与它的函数分离,使同样的初始化过程可以创建不同的复合对象。一个复杂对象的初始化工作,其通常由各个部分的子对象构成;由于需求的变化,这个复杂对象的各个部分经常发生变化,但是这个复杂对象的构造函数却趋于稳定,此时就可以使用建造者模式(复合对象就是指类中定义多个其他类的对象)
2.建造者模式实现步骤:
1.定义抽象建造者类: 定义创建产品的统一抽象接口
2.定义具体建造者类:具体实现抽象建造者创建各个产品的接口
3.定义具体产品类:具体的创建产品
4.定义一个指挥类:负责安排和调度复杂对象的各个建造过程
3.优点:封装性好,扩展性好,各个具体的建造者相互独立,有利于系统的解耦控制细节风险,客户端无需详知细节,建造者细化创建过程
4.缺点:使用范围小,当产品对象内部发生变化,建造者需同步修改,后期维护成本较大
5.建造者模式实现代码:
class AbstractProduct{ //定义抽象的产品类 public: virtual void SetDisplayer(string displayer) = 0; virtual void Show() = 0;};class Computer : public AbstractProduct{ //定义具体的产品类 void SetDisplayer(string displayer){ m_list.push_back(displayer); } void Show(){ cout << "Wild_Pointer" << endl; }};class AbstarctBuilder{ //定义抽象建造者类 public: //抽象建造者类构造函数 AbstarctBuilder() : product(new Computer) {} virtual void BuildDisplayer(string displayer) = 0; AbstractProduct* GetProduct(){ return product; } protected: AbstractProduct* product; };class ConcreteBuilder : public AbstarctBuilder{ //定义具体建造者类 public: virtual void BuildDisplayer(string displayer){ product->SetDisplayer(displayer); } }; class Director{ //定义指挥者类 public: //指挥者类构造函数 Director(AbstarctBuilder* pBuilder) : pBuilder(pBuilder){} AbstractProduct* Construct(string displayer){ pBuilder->BuildDisplayer(displayer); return pBuilder->GetProduct(); } private: AbstarctBuilder* pBuilder; };int main(){ //定义AbstarctBuilder类型(抽象建造者类)指针pB指向ConcreteBuilder类型(具体建造者类)的地址 AbstarctBuilder* pB = new ConcreteBuilder(); //定义Director类型(指挥者类)指针pD Director* pD = new Director(pB); //定义AbstractProduct类型(抽象的产品类)指针指向一个具体的产品类 AbstractProduct* pC = pD->Construct("Wild_Pointer"); pC->Show(); return 0;}抽象工厂模式
1.抽象工厂模式:向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品类型的产品对象。针对的是一个产品类型,使得易于交换产品系列,只需改变具体的工厂就可以使用不同的产品配置,针对同一个类创建多种类型的对象的情况,便可使用抽象工厂模式
2.抽象工厂模式实现步骤:
1.定义抽象工厂类:声明一组创建一种类型的产品的工厂
2.定义具体工厂类:实现了在抽象工厂创建产品的工厂方法
3.定义抽象产品类:声明产品具有的操作方法
4.定义具体产品类:实现抽象产品接口中的操作方法
3.优点:封装了对象创建的具体细节,增加新的产品类型很方便,无须修改已有系统,能针对接口进行编程而不是针对具体类型进行编程
4.缺点:增加新的产品而不是产品类型时,需要对原系统做较大修改(违背开放封闭)
5.抽象工厂模式实现代码:
class Product { //定义抽象的产品类型 public: virtual void show() = 0;};class KeyBoard :public Product{ //定义抽象产品类型};class LogiKeyBoard :public KeyBoard{ //定义抽象产品 public: void show(){ cout << "Wild_Pointer" << endl; }};class Factory{ //定义抽象工厂类 public: virtual KeyBoard* createKeyBoard() = 0; virtual Mouse* createMouse() = 0;};class LogiFactory :public Factory{ //定义具体的工厂类 KeyBoard* createKeyBoard(){ return new LogiKeyBoard; }};int main(){ //定义Factory类型(抽象的工厂类)指针指向LogiFactory类型(具体的工厂类)地址 Factory* factory = new LogiFactory; //定义KeyBoard类型指针(抽象产品类型)指针指向返回的KeyBoard对象 KeyBoard* keyBoard = factory->createKeyBoard(); keyBoard->show(); delete factory; delete keyBoard; return 0;}创建型模式总结
- 抽象工厂模式:针对多个类型中含有多个类的对象初始化
- 工厂模式模式:针对单个类型的对象初始化
- 单例模式:针对类的全局对象初始化
- 建造者模式:针对复合类的对象初始化
- 原型模式:针对类的对象的克隆操作