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方法内采用直接内存拷贝的方式,而避免使用调用构造函数,这才能将其优势显示出来。
返回顶部
- 各种设计模式一览
- C++设计模式一览
- 设计模式一览
- 设计模式一览
- 23种设计模式一览
- 设计模式---->经典设计模式一览
- (2.2.1)设计模式一览
- 设计模式——经典设计模式一览
- Android设计模式之23种设计模式一览
- Android设计模式之23种设计模式一览
- Android设计模式之23种设计模式一览
- Android设计模式之23种设计模式一览
- Android设计模式之23种设计模式一览
- Android开发进阶:23种设计模式一览(设计模式教你追MM)
- 竹迩带你玩懂设计模式(2)-设计模式一览
- 设计模式----工厂模式(c++)
- 【设计模式C++】工厂模式
- C++/设计模式
- 用指针编写一函数求三个整数的最大值
- “举一反三”合并数组--《剑指offer》
- 简单易学的机器学习算法——K-Means算法
- JAVA 面向对象的基本特征
- 安装eclipse主题插件
- C++设计模式一览
- hgjhghjgjjgjkhjgjhjhj
- 特征提取——主成分分析PCA(K-L变换)及几何解释
- 正则表达式
- jvm笔记
- 黑马程序员——ObjectInputStream和ObjectOutputStream
- 线性布局LinearLayout和相对布局RelativeLayout 比较
- 使用VisualSVN Server搭建SVN服务器
- shell——读取文件每一行