C++设计模式(总结)

C++设计模式

  1. 单例模式

1.1概念:一种创建型的设计模式。

1.2作用:保证一个类只有一个实例化对象,并提供一个访问它的全局访问点,使得系统中只有唯一的一个对象实例。

1.3应用: (1)需要频繁实例化然后销毁的对象。

  1. 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  2. 有状态的工具类对象。
  3. 频繁访问数据库或文件的对象。

如日志文件、应用配置、线程池

1.4三个关键点:

  1. 单例类只能有一个实例化对象。

为此,单例类只能提供私有的构造函数,即保证不能随意创建该类的实例。

2、单例类必须自己提供一个实例化对象。

  因为构造函数是私有的,其他对象不能创建单例类的实例,只能是单例类自己来创建。

3、单例类必须提供一个可以访问唯一实例化对象的接口。

  外界需要获取并使用这个单例类的实例,但是由于该类的构造函数是私有的,外界无法通过new去获取它的实例,那么就必须提供一个静态的公有方法,该方法创建或者获取它本身的静态私有对象并返回。

1.5两种实现方式:

懒汉式:故名思义,懒汉很懒只有饿了才会去找吃的。也就是,只有在需要使用的时候才会去实例化。

饿汉式:饿了肯定要饥不择食。在单例类定义的时候就进行实例化。

1.5.1非线程安全的懒汉式单例模式:

class Singleton

 {

public:

    //(4)提供一个公有的静态成员函数用于返回实例,如果实例为NULL,则进行实例化。

    static Singleton* getInstance();

private:

    //(1)默认构造函数是私有的,外部不能进行单例类的实例化;

    Singleton(){}  

    //(2)拷贝构造函数和赋值运算符也是私有的,以禁止拷贝和赋值;

    Singleton(const Singleton&){}

    Singleton& operator=(const Singleton&){}

    //(3)具有一个私有的静态成员指针 instance_,指向唯一的实例;

    static Singleton* instance_;

};


Singleton* Singleton::instance_ = NULL;


Singleton* Singleton::getInstance()

{

    if (NULL == instance_)

        instance_ = new Singleton();

    return instance_;

}

1.5.2线程安全的懒汉式单例模式:

如果有两个线程同时获取单例类的实例,都发现实例不存在,因此都会进行实例化,就会产生两个实例都要赋值给instance_,这是严重的错误。为了解决这个问题,就要考虑加锁。

绝大多数情况下,获取实例时都是直接返回实例,这时候不会涉及到上锁、解锁的问题。只有在没有实例的时候,才会涉及上锁、解锁,这种情况是很少的。这个获取实例的方法对性能几乎无影响。

std::mutex mt;

class Singleton

 {

public:

    static Singleton* getInstance();

private:

    Singleton(){}  

    Singleton(const Singleton&){}

    Singleton& operator=(const Singleton&){}

    static Singleton* instance_;

};


Singleton* Singleton::instance_ = NULL;


Singleton* Singleton::getInstance()

{

     mt.lock(); //上锁

     if (NULL == instance_)

     {

        instance_ = new Singleton();

     }

     return instance_;

     mt.unlock(); //解锁


}

1.5.3 饿汉式单例模式:

饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化(不存在上述的线程安全问题)。在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

class Singleton

{

public:

    static Singleton* getInstance();

private:

    Singleton(){}  

    Singleton(const Singleton&){}

    Singleton& operator=(const Singleton&){}

    static Singleton* instance_;

};


Singleton* Singleton::m_pSingleton = new Singleton();

Singleton* Singleton::getInstance()

{

    return m_pSingleton;

}

1.6 对象释放问题:

上边的程序中只有new,却没有delete,也就是说只有内存申请而没有内存释放,会不会有内存泄漏?

答:一般情况下,单例类的实例都是常驻内存的,一直存在于进程的生命周期,因此不需要手动释放。如果的确需要释放实例占用的内存,一定不能在单例类的析构函数中进行delete操作,这样会造成无限循环,可以考虑增加一个destroy方法用于释放内存,或者在单例类中定义一个内嵌的垃圾回收类。

(1)提供一个destroy接口,由这个单例的使用者来释放:

class Singleton

{

public:

    ...

    void destory()   //destroy接口

    {

        if (instance_!= NULL)

        {

              delete instance_;

              instance_= NULL;

         }

    }

    ...

private:

    ...

    static Singleton* instance_;

};

PS:一个容易犯的错误:

// 用户1

Singleton* mySinglePtr = Singleton::getInstance();

delete mySinglePtr;

mySinglePtr = NULL;


// 用户2在用户1delete后,使用instance_

Singleton* mySinglePtr2 = Singleton::getInstance();

mySinglePtr2->getVal();

// ****此时,出现segment default!!!

原因:用户1  delete mySinglePtr后,将Singleton的实例已经释放掉,但是但是!!Singleton中的instance_没有复位为空指针!!!!仍然指向之前new出来的内存(但这块内存已经被delete掉,系统已经回收)。用户2要使用instance_,Singleton::getInstance()判断此时的instance_不为空,就直接返回了instance_指针,instance_指向了已经被系统回收的内存,造成segment default。

  1. 在单例类中定义一个内嵌的垃圾回收类(自动回收);
class Singleton

{

public:

    static Singleton* getInstance();


    // 实现一个内嵌垃圾回收类    

    class CGarbo

    {

    public:

          ~CGarbo()

          {

               if(Singleton::m_instance_)

                   delete Singleton::m_instance_;

          }

    };


    // 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象

    static CGarbo Garbo;


private:

    Singleton(){}  

    Singleton(const Singleton&){}

    Singleton& operator=(const Singleton&){}

    static Singleton* instance_;

};

2、工厂模式

2.1 作用:封装对象的创建,分离对象的创建和操作过程,用于批量管理对象的创建过程,便于程序的维护和扩展。工厂模式作为一种创建模式,一般在创建复杂对象时,考虑使用;在创建简单对象时,建议直接new完成一个实例对象的创建。

2.2 分类:简单工厂模式、工厂方法模式、抽象工厂模式。

2.2.1 简单工厂模式:

主要特点是需要在工厂类中做判断,从而创造相应的产品,当增加新产品时,需要修改工厂类。使用简单工厂模式,我们只需要知道具体的产品型号就可以创建一个产品。

缺点:工厂类集中了所有产品类的创建逻辑,如果产品量较大,会使得工厂类变的非常臃肿。

//定义产品类型信息

typedef enum ProductTypeTag

{

    TypeA,

    TypeB,

    TypeC

}PRODUCTTYPE;


//产品抽象基类

class Product

{

public:

    virtual void Show() = 0;

};


//具体的产品类

class ProductA : public Product

{

public:

    void Show() {  cout<<"I'm ProductA"<<endl;  }

};

class ProductB : public Product

{

public:

    void Show() {  cout<<"I'm ProductB"<<endl;  }

};

class ProductC : public Product

{

public:

    void Show() {  cout<<"I'm ProductC"<<endl;  }
    
};




//工厂类

class Factory

{

public:

    Product* CreateProduct(PRODUCTTYPE type)

    {

        switch (type)

        {

        case TypeA:

            return new ProductA();

        case TypeB:

            return new ProductB();

        case TypeC:

            return new ProductC();

        default:

            return NULL;

        }

    }

};


//主函数

int main()

{

    Factory productCreator;

    Product *productA=productCreator.CreateProduct(TypeA);

    Product *productB=productCreator.CreateProduct(TypeB);

    Product *productC=productCreator.CreateProduct(TypeC);

    productA->Show();

    productB->Show();

    productC->Show();

    if(productA){

        delete productA;

        productA=NULL;

    }

    if(productB){

        delete productB;

        productB=NULL;

    }

    if(productC){

        delete productC;

        productC=NULL;

    }

    return 0;

}

2.2.2 工厂方法模式:

工厂方法模式在简单工厂模式的基础上增加对工厂的基类抽象,不同的产品创建采用不同的工厂创建(从工厂的抽象基类派生),这样创建不同的产品过程就由不同的工厂分工解决:FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。

该模式相对于简单工厂模式的优势在于:便于后期产品种类的扩展。

缺点:产品类数据较多时,需要实现大量的工厂类,这无疑增加了代码量。

//抽象工厂类,提供一个创建接口

class Factory

{

public:

    //提供创建产品实例的接口,返回抽象产品类

    virtual Product *createProduct()=0;

};


//具体的创建工厂类,使用抽象工厂类提供的接口,去创建具体的产品实例

class FactoryA : public Factory

{

public:

    Product *createProduct() {  return new ProductA();  }

};


class FactoryB : public Factory

{

public:

    Product *createProduct() {  return new ProductB();  }

};


class FactoryC : public Factory

{

public:

    Product *createProduct() {  return new ProductC();  }

};


//主函数

int main()

{

    Factory *factoryA=new FactoryA();

    Product *productA = factoryA->createProduct();

    productA->Show();

    Factory *factoryB=new FactoryB();

    Product *productB = factoryB->createProduct();

    productB->Show();

    if (factoryA){

        delete factoryA;

        factoryA = NULL;

    }

    if (factoryB){

        delete factoryB;

        factoryB = NULL;

    }

    if (productA){

        delete productA;

        productA = NULL;

    }

    if (productB){

        delete productB;

        productB = NULL;

    }

    return 0;

}

2.2.3 抽象工厂模式:

抽象工厂模式提供创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。当存在多个产品系列,而客户端只使用一个系列的产品时,可以考虑使用抽象工厂模式。

缺点:当增加一个新系列的产品时,不仅需要现实具体的产品类,还需要增加一个新的创建接口,扩展相对困难。

/* 关键代码:在一个工厂里聚合多个同类产品。

   * 以下代码以低端产品和高端产品为例,低端产品为一个产品系列,高端产品为一个产品系列。ProductA1和ProductB1为低端产品,ProductA2和ProductB2为高端产品。每个系列的衣服由一个对应的工厂创建,这样一个工厂创建的产品能保证产品为同一个系列。

*/


class ProductA

{

public:

    virtual void Show() = 0;

};


//A类低端产品

class ProductA1 : public ProductA

{

public:

    void Show() {  cout<<"I'm ProductA1"<<endl;  }

};


//A类高端产品

class ProductA2 : public ProductA

{

public:

    void Show() {  cout<<"I'm ProductA2"<<endl;  }

};


class ProductB

{

public:

    virtual void Show() = 0;

};


//B类低端产品

class ProductB1 : public ProductB

{

public:

    void Show() {  cout<<"I'm ProductB1"<<endl;  }
    
};


//B类高端产品

class ProductB2 : public ProductB

{

public:

    void Show() {  cout<<"I'm ProductB2"<<endl;  }

};


class Factory

{

public:

    virtual ProductA *CreateProductA() = 0;

    virtual ProductB *CreateProductB() = 0;

};


//1号工厂用于生产低端产品

class Factory1 : public Factory

{

public:

    ProductA *CreateProductA() {  return new ProductA1();  }

    ProductB *CreateProductB() {  return new ProductB1();  }

};



//2号工厂用于生产高端产品

class Factory2 : public Factory

{

public:

    ProductA *CreateProductA() {  return new ProductA2();  }

    ProductB *CreateProductB() {  return new ProductB2();  }

};


int main()

{

    Factory *factory1 = new Factory1();

    ProductA *productA1 = factory1->CreateProductA();

    ProductB *productB1 = factory1->CreateProductB();

    productA1->Show();

    productB1->Show();


    Factory *factory2 = new Factory2();

    ProductA *productA2 = factory2->CreateProductA();

    ProductB *productB2 = factory2->CreateProductB();

    productA2->Show();

    productB2->Show();


    if (factory1){

        delete factory1;

        factory1 = NULL;

    }

    if (productA1){

        delete productA1;

        productA1= NULL;

    }

    if (productB1){

        delete productB1;

        productB1 = NULL;

    }

    if (factory2){

        delete factory2;

        factory2 = NULL;

    }

    if (productA2){

        delete productA2;

        productA2 = NULL;

    }

    if (productB2){

        delete productB2;

        productB2 = NULL;

    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值