C++设计模式一览

来源:互联网 发布:ios 数组替换指定位置 编辑:程序博客网 时间:2024/05/05 22:33

单例模式

单例模式的使用场景:

        单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。

最原始的懒汉单例模式:

class CSingleton {private:    CSingleton() { }private:    static CSingleton* m_sl;public:    static CSingleton* GetInstance()    {        if (m_sl == NULL) {            m_sl = new CSingleton();        }        return m_sl;    }};CSingleton *CSingleton::m_sl = NULL;
该实现中很明显有 new 操作,一般用户new,那么就需要用户来手动delete,防止内存泄露。 因为将构造函数定义为了private,所以至始至终不能生成一个对象,系统也就没有机会来调用析构函数,因此在析构函数中来delete就行不通了。当然,可以定义一个与GetInstance()相对应的方法ReleaseInstance(),在该方法中调用 delete 是可行。但这也需要手动来调用 ReleaseInstance() ,粗心的用户可能会忘记调用。

所以,采用 static 成员对象的方法来绕开 new-delete 方式,将内存的释放交还给操作系统

class CSingleton {private:    CSingleton(){}    CSingleton(const CSingleton &s);    CSingleton &operator=(CSingleton &s);public:    static CSingleton * GetInstance()    {        static CSingleton m_s; //程序结束时,会自动回收1&        return &m_s;    }    ~CSingleton(){} };
将拷贝构造跟赋值重载声明为private,防止用户生成对象
由于static的生命周期为:产生于第一次调用,结束于程序结束,结束时自动调用析构函数来释放对象,并且保证了整个程序运行中只有一个对象

这样,就可以在该类的析构函数中处理释放资源的操作,比如释放文件,设备等资源。

关于内存释放的描述,参考于网上的解释,个人觉得在使用单例模式的时候,不存在内存泄露的问题,上面使用static对象来完成自动释放也没有什么作用,因为既然使用单例,那么程序始终只有该类的一份实例,程序结束时,回收了所有的资源,堆/栈/文件 等,也就没有必要自己显示的来释放内存了!(欢迎网友对此观点的批评指正)

线程安全的单例模式

在多线程程序中,有可能几个线程同时调用了 GetInstance() 函数,几个线程同时判定 m_sl 为空,后果就是,这几个线程都会调用 new 操作,产生了过个类的实例,违背了单例模式设计的初衷。因此需要一种线程安全的实现方法。

class Lock {private:    pthread_mutex_t m_mutex;public:    Lock(const pthread_mutex_t &mutex) : m_mutex(mutex)    {        pthread_mutex_lock(&m_mutex); //lock    }    ~Lock()    {        pthread_mutex_unlock(&m_mutex);        }};class CSingleton {private:    CSingleton()     {        cout << "CSingleton::CSingleton()" << endl;    }public:    static CSingleton * GetInstance()    {        //判断两次是为了将锁操作放在内部,避免每次GetInstance的时候都加锁,提升效率        if (instance == NULL) {            pthread_mutex_init(&mutex, NULL);            Lock lock(mutex);            if (instance == NULL) {                instance = new CSingleton();            }        }        return instance;    }public:    static pthread_mutex_t mutex;private:    static CSingleton *instance;};CSingleton *CSingleton::instance = NULL;pthread_mutex_t CSingleton::mutex;
在上面的代码中使用了互斥锁来保证只有一个线程可以申请到资源,从而实例化一个类。Lock类用户提供锁操作

原文参考

http://blog.csdn.net/hackbuteer1/article/details/7460019

工厂模式

工厂模式使用背景

        工厂模式是创建型模式中最典型的模式,主要是用来创建对象,减少我们在使用某个对象时的new() 操作。通过工厂来完成对象的创建,这样不但提供了统一创建对象的入口,而且对于程序的可维护和可测试性都有很大的提高,有利于程序扩展。常见的三种工厂模式有:简单工厂、工厂方法、抽象工厂。

简单工厂模式

        简单工厂模式在工厂中根据传入的类型判断,来生产不同的产品

//定义产品类class BaseCar {public:    virtual void show() = 0;};class BMWCarr : public BaseCar{public:    void show()    {        cout << "宝马汽车" << endl;    }};class BenzCar : public BaseCar{public:    void show()    {        cout << "奔驰汽车" << endl;    }};//定义一个简单工厂class SimpleFactory{public:    BaseCar* CreateCar(const char* type)    {        if (strcasecmp(type, "BMW") == 0) {            return new BMWCar();        } else if (strcasecmp(type, "Benz") == 0) {            return new BenzCar();        } else {            return NULL;        }    }};
简单工厂的缺点:增加新的产品类型时,就需要修改工厂类。 这就违反了开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改。

工厂方法模式

         工厂方法模式是将工厂做一次抽象,将产品的生产延迟到工厂子类中去完成,当有新的产品需要生产时,只需要派生一个子工厂来完成生产,扩展极其方便。

class IFactory{public:    virtual BaseCar* CreateCar() = 0;};class BMWFactory : public IFactory{public:    BMWCar* CreateCar()    {        return new BMWCar();    }};class BenzFactory : public IFactory{public:    BenzCar* CreateCar()    {        return new BenzCar();    }};
工厂方法模式的缺点:每种产品对应一个工厂,当产品过多时,需要大量的工厂来生产,造成了类膨胀。

抽象工厂模式

         抽象工厂模式是对工厂模式的进一步抽象与集中。抽象体现在每个工厂生产一个品牌的产品,集中体现在在一个工厂中可以生产多个同品牌的产品

class BusinessCar : public BaseCar{    virtual void show() = 0;};class SportCar : public BaseCar{    virtual void show() = 0;};class BMWBusinessCar : public BusinessCar{public:    void show()    {        cout << "宝马商务汽车" << endl;    }};class BMWSportCar : public SportCar{public:    void show()    {        cout << "宝马跑车" << endl;    }};class BenzBusinessCar : public BusinessCar{public:    void show()    {        cout << "奔驰商务汽车" << endl;    }};class BenzSportCar : public SportCar{public:    void show()    {        cout << "奔驰跑车" << endl;    }};// 定义一个抽象工厂class IFactory{public:    virtual BusinessCar* CreateBusinessCar() = 0;    virtual SportCar* CreateSportCar() = 0;};class BMWFactory : public IFactory{public:    BusinessCar* CreateBusinessCar()    {        return new BMWBusinessCar();    }    SportCar* CreateSportCar()    {        return new BMWSportCar();    }};class BenzFactory : public IFactory{public:    BusinessCar* CreateBusinessCar()    {        return new BenzBusinessCar();    }    SportCar* CreateSportCar()    {        return new BenzSportCar();    }};

总结:

简单工厂模式:

        一个抽象产品类,可以派生出多个具体产品类。

        一个工厂类,可以创建出多个产品类的实例

工厂方法模式:
        一个抽象产品类,可以派生出多个具体产品类。   
       一个抽象工厂类,可以派生出多个具体工厂类。   
        每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
        多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
        一个抽象工厂类,可以派生出多个具体工厂类。   
        每个具体工厂类可以创建多个具体产品类的实例。  
区别:
        工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
        工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

参考博文:

http://blog.csdn.net/wuzhekai1985/article/details/6660462
http://www.cnblogs.com/hegezhou_hot/archive/2010/11/30/1892227.html

Builder创建者模式

Builder模式旨在将对象的创建与表示分离,使得同样的构建过程可以创建不同的表示。

当创建的多个对象需要使用同一创建过程,但是具体创建细节不同时,非常适用于Builder模式。

下面以组装一台汽车为例。组装一辆汽车都需要经过上引擎、轮子等过程,但是不同品牌的汽车使用的部件是不一样的。满足于构建过程相同,而构造细节不同的模式

#include <string>#include <iostream>using namespace std;class Car{public:    string GetWheel()    {        return m_wheel;    }    void SetWheel(const string& wheel)    {        m_wheel = wheel;    }    string GetEngine()    {        return m_engine;    }    void SetEngine(const string& engine)    {        m_engine = engine;    }    string GetBland()    {        return m_bland;    }    void SetBland(const string& bland)    {        m_bland = bland;    }    void PrintCarInfo()    {        cout << m_bland << "配置信息:" << endl;        cout << "  轮胎:" << m_wheel << endl;        cout << "  引擎:" << m_engine << endl;    }private:    string m_wheel;    string m_engine;    string m_bland;};//ICarBuilder类,便是提对外接口,该接口内部实现同一过程的组装class ICarBuilder{public:    Car* Build()    {        m_car = new Car;        SetBland();        BuildWheel();        BuildEngine();        return m_car;    }protected:    virtual void SetBland() = 0;    virtual void BuildWheel() = 0;    virtual void BuildEngine() = 0;protected:    Car* m_car;};//Builder构造子类实现具体的构造细节,但是都采用了继承至 ICarBuilder 类的构造过程class BMWBuilder : public ICarBuilder{protected:    void SetBland()    {        m_car->SetBland("宝马汽车");    }    void BuildWheel()    {        m_car->SetWheel("米奇林");    }    void BuildEngine()    {        m_car->SetEngine("奔驰");    }};class BenzBuilder : public ICarBuilder{protected:    void SetBland()    {        m_car->SetBland("奔驰汽车");    }    void BuildWheel()    {        m_car->SetWheel("韩泰");    }    void BuildEngine()    {        m_car->SetEngine("三菱");    }};int main(){    BMWBuilder bmwBuilder;    BenzBuilder benzBuilder;    Car *bmw, *benz;    bmw = bmwBuilder.Build();    benz = benzBuilder.Build();    bmw->PrintCarInfo();    benz->PrintCarInfo();    delete bmw;    delete benz;    return 0;}
参考文章:

http://www.cnblogs.com/bastard/archive/2011/11/21/2257625.html

原型模式

/******************************************************************** *                    原型模式 ******************************************************************** * 实现原理:根据一个基础类对象,调用clone方法复制出多个同类型对象 * 注意:使用原型模式,需要关注深拷贝问题 ********************************************************************/#include <iostream>#include <string>using namespace std;class WorkExperience{public:    WorkExperience()    {    }    WorkExperience(const string& company, const string& worktime)     {        this->company = company;        this->worktime = worktime;    }    string GetCompany()    {        return company;    }    void SetCompany(const string& company)    {        this->company = company;    }    string GetWorkTime()    {        return worktime;    }    void SetWorkTime(const string& worktime)    {        this->worktime = worktime;    }private:    string company;    string worktime;};class PersonalInfo{public:    PersonalInfo()    {    }    PersonalInfo(const string& name, const string& sex, int age)    {        this->name = name;        this->sex = sex;        this->age = age;    }    string GetName()    {        return name;    }    void SetName(const string& name)    {        this->name = name;    }    string GetSex()    {        return sex;    }    void SetSex(const string& sex)    {        this->sex = sex;    }    int GetAge()    {        return age;    }    void SetAge(int age)    {        this->age = age;    }private:    string name;    string sex;    unsigned int age;};/* 定义一个简历原型 */class Resume{public:    virtual Resume* Clone() = 0;    void SetPersonalInfo(const string& name, const string& sex, int age)    {        personalInfo->SetName(name);        personalInfo->SetSex(sex);        personalInfo->SetAge(age);    }    void SetWorkExperience(const string& company, const string& worktime)    {        workExperience->SetCompany(company);        workExperience->SetWorkTime(worktime);    }    void PrintResume()    {        cout << "个人信息:" << endl;        cout << "    姓名:" << personalInfo->GetName() << "\t性别:" << personalInfo->GetSex() << "\t年龄:" << personalInfo->GetAge() << endl;        cout << "工作经验:" << endl;        cout << "    公司名称:" << workExperience->GetCompany() << "\t工作时间:" << workExperience->GetWorkTime() << endl;    }protected:    PersonalInfo* personalInfo;    WorkExperience* workExperience;};class ResumeA : public Resume{public:    ResumeA()    {        personalInfo = new PersonalInfo;        workExperience = new WorkExperience;    }    ResumeA(const ResumeA& resume)    {        personalInfo = new PersonalInfo;        personalInfo->SetName(resume.personalInfo->GetName());        personalInfo->SetSex(resume.personalInfo->GetSex());        personalInfo->SetAge(resume.personalInfo->GetAge());        workExperience = new WorkExperience;        workExperience->SetCompany(resume.workExperience->GetCompany());        workExperience->SetWorkTime(resume.workExperience->GetWorkTime());    }    Resume* Clone()    {        return new ResumeA(*this);    }};int main(){    ResumeA* pr1 = new ResumeA;    pr1->SetPersonalInfo("张三", "男", 20);    pr1->SetWorkExperience("腾讯科技", "2004~2008");    pr1->PrintResume();    ResumeA* pr2 = (ResumeA*)pr1->Clone();    delete pr1;    pr2->SetPersonalInfo("李四","女",18);    pr2->SetWorkExperience("阿里巴巴", "2008~2012");    pr2->PrintResume();    delete pr2;    return 0;}
上面例子中的clone方法只是简单的调用了复制拷贝构造函数来完成对象的克隆,原型模式的优势并不能得到很好的体现。当需要克隆的数据量较大时,如果在clone方法内采用直接内存拷贝的方式,而避免使用调用构造函数,这才能将其优势显示出来。

返回顶部

0 0
原创粉丝点击