设计模式实战精讲:创建型模式

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

作者
WildPointer
发布
2024.05.03
专栏
设计模式实战精讲
阅读
约 14 分钟 / 259 次原文浏览
设计模式实战精讲:创建型模式

目录

        1.前言

        2.工厂模式

1.简单工厂模式               

1.工厂模式

        3.原型模式

        4.单例模式

        5.建造者模式

        6.抽象工厂模式

        7.创建型模式总结


前言

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


ea9a2630721146e4a9218929ca5a7527.png

图1.创建型模式区分示意


工厂模式

工厂模式内含简单工厂模式,是简单工厂模式的泛化,而简单工厂模式是工厂方法模式的一个特例。当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对 象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭” 原则,而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好,所以使用工厂模式。这里我将分开讲解工厂模式和简单工厂模式,先由简单工厂模式进行解析,以浅入深

        1.简单工厂模式               

1.简单工厂模式:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类,而使用简单工厂模式能减少客户程序对类创建过程的依赖

2.简单工厂实现步骤:

1.定义一个工厂类:负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。

2.定义一个抽象产品类:负责描述所有实例所共有的公共接口

3.定义一个具体产品类:创建的具体实例对象

3.优点:帮助封装,能实现组件封装,面向接口编程,客户端和具体实现类的解耦合

                4.缺点:可能增加客户端的复杂度,不方便扩展子工厂

                5.简单工厂模式实现代码:

cpp
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.工厂模式实现代码:

cpp
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.原型模式实现代码:

cpp
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.懒汉式:在程序的第一次请求使用对象时,才创建对象并分配内存,优点是避免了不必要的内存占用,缺点是会存在线程安全问题

cpp
//懒汉式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.饿汉式:在程序启动初期就创建对象并分配内存,优点是不会存在线程安全问题,缺点是会导致不必要的内存占用

cpp
//饿汉式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.建造者模式实现代码:

cpp
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.抽象工厂模式实现代码:

cpp
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;}

创建型模式总结

  • 抽象工厂模式:针对多个类型中含有多个类的对象初始化
  • 工厂模式模式:针对单个类型的对象初始化
  • 单例模式:针对类的全局对象初始化
  • 建造者模式:针对复合类的对象初始化
  • 原型模式:针对类的对象的克隆操作
13次原文点赞;这里的喜欢仅保存在本机
WildPointer

专注系统编程、工程实践与底层技术,记录 C++、Qt、OpenCV 与 VTK 的学习和实践。