C++基本设计模式01
1 简单工厂模式:不直接在客户端创建类对象,利用工厂类的方法CreateObject来创建。
优点:1 客户端和具体类解耦 即分开来 2 不需要担心对象创建的复杂程度。
缺点:1 增加新功能通过改变源代码 ,不符合开闭原则。 2 工程类职责过多,该类发生问题影响许多类。
#include<iostream>
#include<string>
using namespace std;
//水果抽象类
class AbstractFruit{
public:
virtual void ShowName() = 0;
};
class Apple:public AbstractFruit{
public:
virtual void ShowName(){
cout<<"我是苹果"<<endl;
}
};
class Banana:public AbstractFruit{
public:
virtual void ShowName(){
cout<<"我是香蕉"<<endl;
}
};
class Pear:public AbstractFruit{
public:
virtual void ShowName(){
cout<<"我是鸭梨"<<endl;
}
};
//简单工厂模式 利用工厂创建水果
class FruitFactory{
public:
//最好使用静态 这样类名也可以调用
static AbstractFruit* CreateObject(string fruit){
if(fruit=="苹果"){
return new Apple;
}else if(fruit=="香蕉"){
return new Banana;
}else if(fruit=="鸭梨"){
return new Pear;
}else{
return NULL;
}
}
};
void test01(){
FruitFactory *fac=new FruitFactory;
AbstractFruit *fruit=fac->CreateObject("苹果");
fruit->ShowName();
delete fruit;
fruit=fac->CreateObject("香蕉");
fruit->ShowName();
delete fruit;
//创建鸭梨
fruit=fac->CreateObject("鸭梨");
fruit->ShowName();
delete fruit;
delete fac;
}
int main(){
test01();
return 0;
}
总结简单工厂模式:不直接在客户端创建类对象,利用工厂类的方法CreateObject来创建。例子:苹果、香蕉、鸭梨。通过简单工厂类的方法CreateObject创建对象返回相应的水果,比较简单。
2 工厂方法模式: 将工厂抽象出来 一个工厂具体类对应一个水果具体类,即简单工厂模式+开闭法则。
优点: 符合开闭法则。
缺点: 类成倍的增加,维护难度加大。
#include<iostream>
#include<string>
using namespace std;
//水果抽象类
class AbstractFruit{
public:
virtual void ShowName() = 0;
};
class Apple:public AbstractFruit{
public:
virtual void ShowName(){
cout<<"我是苹果"<<endl;
}
};
class Banana:public AbstractFruit{
public:
virtual void ShowName(){
cout<<"我是香蕉"<<endl;
}
};
class Pear:public AbstractFruit{
public:
virtual void ShowName(){
cout<<"我是鸭梨"<<endl;
}
};
//工厂方法模式 将工厂抽象出来
class AbstractFruitFactory{
public:
virtual AbstractFruit* CreateObject()=0; //因为要创建对象 所以需要创建对象纯虚函数
};
//苹果工厂
class AppleFactory:public AbstractFruitFactory{
public:
virtual AbstractFruit* CreateObject(){
return new Apple;
}
};
//香蕉工厂
class BananaFactory:public AbstractFruitFactory{
public:
virtual AbstractFruit* CreateObject(){
return new Banana;
}
};
//鸭梨工厂
class PearFactory:public AbstractFruitFactory{
public:
virtual AbstractFruit* CreateObject(){
return new Pear;
}
};
void test01(){
//先创建两个抽象类指针 用于接收具体工厂和具体水果
AbstractFruitFactory *factory=NULL;
AbstractFruit *fruit=NULL;
//通过苹果工厂 创建苹果
factory=new AppleFactory;//多态的必要条件之一,基类指针指向派生类,另一个是具有virtual。
fruit=factory->CreateObject();
fruit->ShowName();
delete factory;
delete fruit;
//通过香蕉工厂 创建香蕉
factory=new BananaFactory;
fruit=factory->CreateObject();
fruit->ShowName();
delete factory;
delete fruit;
//通过鸭梨工厂 创建鸭梨
factory=new PearFactory;
fruit=factory->CreateObject();
fruit->ShowName();
delete factory;
delete fruit;
}
int main(){
test01();
return 0;
}
总结工厂模式:两个抽象类,一个派生工厂对应一个派生类生产。例子没必要深刻记忆,记住前面那句话便可。
3 抽象工厂模式:针对的是产品族,而不是产品结构。
产品族: 同一产地或者同一厂商,功能不同 即中国产地的,不同品种水果。
产品等级: 功能相同,产地或者厂商不同,即同一水果在不同产地。
如果此时增加一个西瓜,产品等级符合开辟原则,只需要写多个西瓜抽象类就可以不用改变源代码。
而产品族则需要改变源代码,需要在抽象工厂类添加一个函数,不符合开辟法则,所以说抽象工厂是针对!!!产品族!!!的。
例子1的思想:
思想:抽象工厂是针对于产品族的 所以一个具体工厂包含苹果香蕉鸭梨,而苹果又分中国的,美国的,倭国的。
显然一个抽象水果类无法完成,所以需要将苹果,香蕉,鸭梨各自抽象出来,然后就可以分成多个产地的苹果,香蕉,鸭梨。
//抽象苹果
class AbstractApple{
public:
virtual void ShowName() = 0;
};
//中国苹果
class ChinaApple : public AbstractApple{
public:
virtual void ShowName(){
cout << "中国苹果!" << endl;
}
};
//美国苹果
class USAApple : public AbstractApple{
public:
virtual void ShowName(){
cout << "美国苹果!" << endl;
}
};
//倭国苹果
class JapanApple : public AbstractApple{
public:
virtual void ShowName(){
cout << "倭国苹果!" << endl;
}
};
//抽象香蕉
class AbstractBanana{
public:
virtual void ShowName() = 0;
};
//中国香蕉
class ChinaBanana : public AbstractBanana{
public:
virtual void ShowName(){
cout << "中国香蕉!" << endl;
}
};
//美国香蕉
class USABanana : public AbstractBanana{
public:
virtual void ShowName(){
cout << "美国香蕉!" << endl;
}
};
//倭国香蕉
class JapanBanana : public AbstractBanana{
public:
virtual void ShowName(){
cout << "倭国香蕉!" << endl;
}
};
//抽象鸭梨
class AbstractPear{
public:
virtual void ShowName() = 0;
};
//中国鸭梨
class ChinaPear : public AbstractPear{
public:
virtual void ShowName(){
cout << "中国鸭梨!" << endl;
}
};
//美国鸭梨
class USAPear : public AbstractPear{
public:
virtual void ShowName(){
cout << "美国鸭梨!" << endl;
}
};
//倭国鸭梨
class JapanPear : public AbstractPear{
public:
virtual void ShowName(){
cout << "倭国鸭梨!" << endl;
}
};
//产品族:不同品种 例如苹果香蕉鸭梨 产品等级:同一品种 例如中国苹果美国苹果倭国苹果
class AbstracFactory{
public:
//因为抽象工厂针对产品族 所以每个工厂创建苹果香蕉鸭梨这组产品族
virtual AbstractApple* CreateApple()=0;
virtual AbstractBanana* CreateBanana()=0;
virtual AbstractPear* CreatePear()=0;
};
//中国工厂
class ChinaFactory:public AbstracFactory{
public:
virtual AbstractApple* CreateApple(){
return new ChinaApple;
}
virtual AbstractBanana* CreateBanana(){
return new ChinaBanana;
}
virtual AbstractPear* CreatePear(){
return new ChinaPear;
}
};
//美国工厂
class USAFactory:public AbstracFactory{
public:
virtual AbstractApple* CreateApple(){
return new USAApple;
}
virtual AbstractBanana* CreateBanana(){
return new USABanana;
}
virtual AbstractPear* CreatePear(){
return new USAPear;
}
};
//倭国工厂
class JapanFactory:public AbstracFactory{
public:
virtual AbstractApple* CreateApple(){
return new JapanApple;
}
virtual AbstractBanana* CreateBanana(){
return new JapanBanana;
}
virtual AbstractPear* CreatePear(){
return new JapanPear;
}
};
void test01(){
//定义四个抽象类指针
AbstracFactory *factory=NULL;
AbstractApple *apple=NULL;
AbstractBanana *banana=NULL;
AbstractPear *pear=NULL;
//创建中国工厂 并且显示其产品族
factory=new ChinaFactory();
apple=factory->CreateApple();
banana=factory->CreateBanana();
pear=factory->CreatePear();
apple->ShowName();
banana->ShowName();
pear->ShowName();
delete apple;
delete banana;
delete pear;
delete factory;
}
int main(){
test01();
return 0;
}
例子2:电脑练习。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
/*
设计一个电脑主板架构,电脑包括(显卡,内存,CPU)3个固定的插口
显卡具有显示功能(display,功能实现只 要打印出意义即可)内存具有存储功能(storage)
cpu具有计算功能(calculate)
现有Intel厂商,nvidia厂商,Kingston厂商,均会生产以上三种硬件。要求组装两台电脑:
1台(Intel的CPU,Intel的显卡,Intel的内存)
1台(Intel的CPU, nvidia的显卡,Kingston的内存)
用抽象工厂模式实现
抽象工厂类: 针对产品族 而不是产品结构 而且工厂按照需求来建立 例如这里需要两个工厂建造电脑
例子有:苹果香蕉鸭梨 和 电脑组装
*/
//抽象类卡
class AbstructCard{
public:
virtual void display()=0;
};
//具体类 英特尔的显卡
class IntelCard:public AbstructCard{
public:
virtual void display(){
cout<<"这是英特尔的显卡"<<endl;
}
};
//具体类 英伟达的显卡
class NvidiaCard:public AbstructCard{
public:
virtual void display(){
cout<<"这是英伟达的显卡"<<endl;
}
};
//具体类 Kingston的显卡
class KingstonCard:public AbstructCard{
public:
virtual void display(){
cout<<"这是Kingston的显卡"<<endl;
}
};
//抽象类内存
class AbstructStorage{
public:
virtual void storage()=0;
};
//具体类 Intel的内存
class IntelStorage:public AbstructStorage{
public:
virtual void storage(){
cout<<"这是英特尔的存储内存"<<endl;
}
};
//具体类 Nvidia的内存
class NvidiaStorage:public AbstructStorage{
public:
virtual void storage(){
cout<<"这是Nvidia的存储内存"<<endl;
}
};
//具体类 Kingston的内存
class KingstonStorage:public AbstructStorage{
public:
virtual void storage(){
cout<<"这是Kingston的存储内存"<<endl;
}
};
//抽象类CPU
class AbstructCpu{
public:
virtual void caculate()=0;
};
//具体类 英特尔的CPU
class IntelCPU:public AbstructCpu{
public:
virtual void caculate(){
cout<<"这是英特尔的CPU"<<endl;
}
};
//具体类 Nvidia的CPU
class NvidiaCPU:public AbstructCpu{
public:
virtual void caculate(){
cout<<"这是Nvidia的CPU"<<endl;
}
};
//具体类 Kingston的CPU
class KingstonCPU:public AbstructCpu{
public:
virtual void caculate(){
cout<<"这是Kingston的CPU"<<endl;
}
};
//抽象工厂类 请记得是帮别人创建对象
class AbstructFactory{
public:
virtual AbstructCard* CreateCard() = 0;
virtual AbstructStorage* CreateStorage() = 0;
virtual AbstructCpu* CreateCaculate() = 0;
};
//具体工厂类 按照电脑零件的需求 创建工厂 不必向苹果那样!!!!!
//生产第一种要求的电脑
//这里再次强调,当零件(显卡内存CPU)写好后,抽象工厂的定义是按照需要实现的。
class FirstComputerFactory:public AbstructFactory{
public:
virtual AbstructCard* CreateCard(){
return (new IntelCard);
}
virtual AbstructStorage* CreateStorage() {
return (new IntelStorage);
}
virtual AbstructCpu* CreateCaculate(){
return (new IntelCPU);
}
};
//具体工厂类 生产第二种电脑的工厂
class SecondComputerFactory:public AbstructFactory{
public:
virtual AbstructCard* CreateCard(){
return (new NvidiaCard);
}
virtual AbstructStorage* CreateStorage(){
return (new KingstonStorage);
}
virtual AbstructCpu* CreateCaculate(){
return (new IntelCPU);
}
};
#if 0
//具体工厂类 Kingston工厂 不必创建每一个工厂 按需求建立工厂
class KingstonFactory:public AbstructFactory{
public:
virtual AbstructCard* CreateCard(){
return (new KingstonCard);
}
virtual AbstructStorage* CreateStorage(){
return (new KingstonStorage);
}
virtual AbstructCpu* CreateCaculate(){
return (new KingstonCPU);
}
};
#endif
//电脑类
class Computer{
public:
//电脑一开始初始化为空
Computer(){
m_card=NULL;
m_storage=NULL;
m_cpu=NULL;
}
//开始设置电脑零件
void setComputerCard(AbstructCard* card){
m_card=card;
}
void setComputerStorage(AbstructStorage* storage){
m_storage=storage;
}
void setComputerCpu(AbstructCpu* cpu){
m_cpu=cpu;
}
//启动电脑
void run(){
if(m_card!=NULL){
m_card->display();;
}
if(m_storage!=NULL){
m_storage->storage();
}
if(m_cpu!=NULL){
m_cpu->caculate();
}
}
//释放成员变量
~Computer(){
if(m_card!=NULL){
delete m_card;
}
if(m_storage!=NULL){
delete m_storage;
}
if(m_cpu!=NULL){
delete m_cpu;
}
}
public:
AbstructCard* m_card;
AbstructStorage* m_storage;
AbstructCpu* m_cpu;
};
void test01(){
#if 0
//这样写在组装第二台电脑非常麻烦
AbstructFactory* factory=NULL;
AbstructCard* card=NULL;
AbstructStorage* storage=NULL;
AbstructCpu* cpu=NULL;
//开始组装电脑1
factory=new IntelFactory;
Computer* computer=new Computer;
computer->setComputer(factory->CreateCard(),storage=factory->CreateStorage()
,cpu=factory->CreateCaculate());
delete factory;
#endif
//生产电脑需要 工厂和原始电脑 电脑1
Computer* comp1=new Computer;
AbstructFactory* factory=new FirstComputerFactory;
//装配零件
comp1->setComputerCard(factory->CreateCard());
comp1->setComputerStorage(factory->CreateStorage());
comp1->setComputerCpu(factory->CreateCaculate());
comp1->run();
delete comp1;
delete factory;
cout<<"================="<<endl;
//电脑2
Computer* comp2=new Computer;
factory=new SecondComputerFactory;
//装配零件
comp2->setComputerCard(factory->CreateCard());
comp2->setComputerStorage(factory->CreateStorage());
comp2->setComputerCpu(factory->CreateCaculate());
comp2->run();
delete comp2;
delete factory;
}
int main(){
test01();
return 0;
}
总结抽象工厂模式:针对产品族,而不是产品结构。 例子1,中国工厂能生产中国苹果、香蕉、鸭梨。美国工厂能生产美国苹果、香蕉、鸭梨。倭国工厂能生产倭国苹果、香蕉、鸭梨;例子2,电脑练习,按需求生产工厂,最后定义电脑类生产电脑。
即具体零部件具有多个抽象类,工厂类只有一个。
对比简单工厂模式:
- 1)简单工厂模式符合开辟原则,但是源码太大,不易维护。
- 2)而抽象工厂模式不符合开辟原则,增加新的内容需要改变抽象工厂类的源代码,容易维护。
- 3)简单工厂与抽象工厂看具体情况选择即可,并且强调抽象工厂模式,当具体零件写好后,工厂类按照实际需求编写即可,无需死板固定思路。
4 单例模式:所谓单例模式,就是只有一个实体对象。
/*
实现单例步骤:
1 构造私有
2 设有一个私有静态本类指针
3 提供静态函数接口
*/
下面是单例模式的两个典型例子:懒汉模式和饿汉模式。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<mutex>
using namespace std;
#define SAVE_DELETE(obj) if(obj){delete obj;obj=NULL;}
#define SAVE_A_DELETE(obj) if(obj){delete [] obj;obj=NULL;}
//单例模型实例 懒汉模式 --调用时才初始化对象
class Singleton_lazy {
private:
Singleton_lazy() {}
~Singleton_lazy(){}//可有可无
public:
static Singleton_lazy* get_Singleton_lazy() {
if (m_lazy == NULL) {
unique_lock<mutex> uLock(m_mutex);
if (m_lazy == NULL) {
m_lazy = new Singleton_lazy;
}
}
return m_lazy;
}
class Garbor {
public:
Garbor(){}
~Garbor(){
SAVE_DELETE(m_lazy);
}
};
private:
static Singleton_lazy* m_lazy;
static mutex m_mutex;
static Garbor m_garbor;
};
//类外初始化静态变量
Singleton_lazy* Singleton_lazy::m_lazy = NULL;
mutex Singleton_lazy::m_mutex;
Singleton_lazy::Garbor Singleton_lazy::m_garbor;
//单例模型实例 饿汉模式 --初始化比main函数还快 所以叫饿汉
class Singleton_hungry {
private:
Singleton_hungry() {
//cout<<"我是饿汉"<<endl;
}
public:
static Singleton_hungry* get_Singleton_hungry() {
return m_hun;
}
class Garbor {
public:
Garbor() {}
~Garbor() {
SAVE_DELETE(m_hun);
}
};
private:
static Singleton_hungry* m_hun;
};
//类外初始化静态变量
Singleton_hungry* Singleton_hungry::m_hun = new Singleton_hungry;
int main() {
//懒汉模式
Singleton_lazy *a = Singleton_lazy::get_Singleton_lazy();
Singleton_lazy *b = Singleton_lazy::get_Singleton_lazy();
if (a == b) {
cout << "是单例模式" << endl;
}
else {
cout << "不是单例模式" << endl;
}
//饿汉模式
Singleton_hungry *c = Singleton_hungry::get_Singleton_hungry();
Singleton_hungry *d = Singleton_hungry::get_Singleton_hungry();
if (c == d) {
cout << "是单例模式" << endl;
}
else {
cout << "不是单例模式" << endl;
}
return 0;
/*
单例内存释放问题: 因为单例只有一个对象 即使在不断调用它也不会不断开辟内存 不会导致程序崩溃
程序结束后系统自动回收 我们平时不回收对象内存是因为会不断开辟内存 容易造成内存泄漏
并不是说程序结束不会回收 以前不回收的风险好大
但是单列模式一般不考虑内存回收问题 让他程序结束自动回收
实在想自己回收可以内嵌一个类 将该类对象作为单例类的数据 也是程序结束回收 但没必要
栈是函数调用完毕就回收
*/
}
单例模式要注意的两个问题:
1)可以不考虑它的内存问题,因为只有一个实体对象。
2)单例模式遇上多线程。
当我们的懒汉模式遇到多线程时,两个线程同时执行if(lazy==NULL),若刚好都满足条件,那么就不符合单个对象了;而饿汉模式在多线程下,因为对象在mian函数之前就已经类外初始化完毕了,所以不管你怎么调用静态函数,它返回的都是同一个对象。 所以可以得出:
/*
1 懒汉模式碰到多线程是不安全的 因为可能同时调用时会new两个对象—代码已解决多线程问题。
2 饿汉模式碰到多线程是安全的 因为在调用时就已经确定好返回哪个对象
*/
总结单例模式:
实现单例步骤:
1 构造私有
2 设有一个私有静态本类指针
3 提供静态函数接口
例子,懒汉模式和饿汉模式。
最后将这4个基本模式对比记忆:
1 总结简单工厂模式:不直接在客户端创建类对象,利用工厂类的方法CreateObject来创建。例子:苹果、香蕉、鸭梨。通过简单工厂类的方法CreateObject创建对象返回相应的水果,比较简单。
2 总结工厂模式:一个工厂对应一个类生产。例子没必要深刻记忆,记住前面那句话便可。
3 总结抽象工厂模式:针对产品族,而不是产品结构。 例子1,中国工厂能生产中国苹果、香蕉、鸭梨。美国工厂能生产美国苹果、香蕉、鸭梨。倭国工厂能生产倭国苹果、香蕉、鸭梨;例子2,电脑练习,按需求生产工厂,最后定义电脑类生产电脑。
4 总结单例模式:
实现单例步骤:
1 构造私有
2 设有一个私有静态本类指针
3 提供静态函数接口
例子,懒汉模式和饿汉模式。