C++设计模式一览

单例模式

单例模式的使用场景:

        单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值