设计模式【工厂模式、观察者模式、策略模式、单例模式】

什么是设计模式

  • 设计模式是什么

    • 设计模式是指在软件开发中,经过验证的、用于解决在特定环境下、重复出现的、特定问题的解决方案。(解决问题的固定套路)
  • 解决了什么问题

    • 期望修改少量的代码,就可以适应需求的变化

23种设计模式

工厂模式

主要是对对象的创建进行了一个封装。让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

简单工厂

//产品
class Car {
public:
	Car(string na) : name(na) {}
	virtual void Show() = 0;
protected:
	string name;
};
class BMW : public Car {
public:
	BMW(string na) : Car(na) {}
	void Show() override {
		cout << "得到一辆宝马" << name << endl;
	}
};
class AUDI : public Car {
public:
	AUDI(string na) : Car(na) {}
	void Show() override {
		cout << "得到一辆奥迪" << name <<  endl;
	}
};


//工厂
enum carType {
	bmw,
	audi
};
class SimpleFactory {
public:
	Car* createCar(carType ct) {
		switch (ct) {
		case bmw:
			return new BMW("x6");
		case audi:
			return new AUDI("a8");
		}
		return nullptr;
	}
};
#include <memory> //智能指针
int main() {
    unique_ptr<SimpleFactory> factory(new SimpleFactory());
    unique_ptr<Car> car1(factory->createCar(bmw));
    unique_ptr<Car> car2(factory->createCar(audi));
    car1->Show();
    car2->Show();
    return 0;
}

优点:

  1. 一个调用者想创建一个对象,只要知道其名称就可以了;
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
  3. 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

开-闭原则:

对扩展开发、对修改关闭;

也就是说,我们可以添加代码,但是添加代码的时候不能对现有的代码进行修改。

工厂方法

为了解决简单工厂的缺点。定义一个Factory基类,基类中定义一个纯虚函数(创建产品),之后定义派生类(具体产品的工厂)负责创建对应的产品。一个工厂创建一种产品。

//产品(同上)
...
    
//工厂
class Factory {
public:
	virtual Car* createCar(string name) = 0;
};
//宝马工厂
class BMWFac : public Factory {
public:
	Car* createCar(string name) override {
		return new BMW(name);
	}
};
//奥迪工厂
class AUDIFac : public Factory {
public:
	Car* createCar(string name) override {
		return new AUDI(name);
	}
};
int main() {
    unique_ptr<Factory> bmwfactory(new BMWFac());
    unique_ptr<Factory> audifactory(new AUDIFac());
    
    unique_ptr<Car> car1(bmwfactory->createCar("x6"));
    unique_ptr<Car> car2(audifactory->createCar("a8"));
    car1->Show();
    car2->Show();
    return 0;
}

缺点:

宝马工厂不应该只卖一种商品,而我们的宝马工厂BmwFac里面只有一个createCar方法,如果想要添加产品的话,就需要增加新的类。但是这些产品其实都应该在一个BmwFac工厂里面。这才是现实的逻辑,另外,工厂类太多,会不好维护。

抽象工厂

把有关联关系的、属于一个产品系列的所有产品的接口函数,放在一个抽象工厂里面,派生类(具体产品的工厂)负责创建系列里面的产品。

//产品1 汽车
...

//产品2 车灯
class Light {
public:
	virtual void Show() = 0;
};
class BMWLight : public Light
{
public:
	void Show() { cout << "BMW light!" << endl; }
};
class AUDILight : public Light
{
public:
	void Show() { cout << "AUDI light!" << endl; }
};

//抽象工厂
class AbstractFactory
{
public:
	virtual Car* createCar(string name) = 0; // 工厂方法 创建汽车
	virtual Light* createCarLight() = 0; // 工厂方法 创建汽车关联的产品,车灯
};
// 宝马工厂
class BMWFac : public AbstractFactory
{
public:
	Car* createCar(string name)
	{
		return new BMW(name);
	}
	Light* createCarLight()
	{
		return new BMWLight();
	}
};

// 奥迪工厂
class AUDIFac : public AbstractFactory
{
public:
	Car* createCar(string name)
	{
		return new AUDI(name);
	}
	Light* createCarLight()
	{
		return new AUDILight();
	}
};
int main() {
    unique_ptr<AbstractFactory> bmwfactory(new BMWFac());
    unique_ptr<AbstractFactory> audifactory(new AUDIFac());

    unique_ptr<Car> car1(bmwfactory->createCar("x6"));
    unique_ptr<Car> car2(audifactory->createCar("a8"));
    unique_ptr<Light> light1(bmwfactory->createCarLight());
    unique_ptr<Light> light2(audifactory->createCarLight());
    car1->Show();
    light1->Show();
    car2->Show();
    light2->Show();
    return 0;
}

观察者模式

定义对象间的一种一对多(变化)的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

#include <list>
#include <iostream>
//设备接口类
class IDisplay {
public:
	virtual void Show(double temperature) = 0;
	virtual ~IDisplay() {}
};

//具体的设备类
class DisplayA : public IDisplay {
public:
	void Show(double temperature) override {
		std::cout << "DisplayA Show:" << temperature << std::endl;
	}
};
class DisplayB : public IDisplay {
public:
	void Show(double temperature) override {
		std::cout << "DisplayB Show:" << temperature << std::endl;
	}
};

//数据中心类,天气变化时通知所有设备
class DataCenter {
public:
	void Attach(IDisplay* ob) { //添加设备
		v.push_back(ob);
	}
	void Detach(IDisplay* ob) { //删除设备
		v.remove(ob);
	}
	void Notify(double temper = 0.0) {
		for (auto ob : v) 
			ob->Show(temper);
	}
private:
	std::list<IDisplay*> v; 
};
int main() {
    IDisplay* A = new DisplayA();
    IDisplay* B = new DisplayB();

    DataCenter* center = new DataCenter();
    center->Attach(A);
    center->Attach(B);
    center->Notify(37.5);
    center->Detach(B);
    center->Notify(0.5);
    return 0;
}

策略模式

定义一系列的算法,把他们一个一个封装起来,并且使他们可以互相替换。该模式使得算法可以独立于使用它的客户程序而变化。

如:新增算法、算法内容发生改变、切换算法

//打折方法接口类
class ProStategy {
public:
	virtual double func(double x) = 0;
	virtual ~ProStategy() {}
};

//具体的打折方法类
class Spring : public ProStategy {
public:
	virtual double func(double x) override {
		return x * 0.8;
	}
};
class GuoQing : public ProStategy {
public:
	virtual double func(double x) override {
		return x * 0.9;
	}
};

//商城类
class Market {
public:
	Market(ProStategy* sss = nullptr) : s(sss) {}
	~Market() {}
	void Choose(ProStategy* sss) { //更换打折策略
		if (sss != nullptr) 
			s = sss;
	}
	double Sell(double& x) {	//计算售价
		if (s != nullptr) 
			return s->func(x);
		return 0.0;
	}
private:
	ProStategy* s;
};
int main() {
    double x = 100.0;
    ProStategy* s = new Spring(); //春节打折
    ProStategy* g = new GuoQing();//国庆打折

    Market* m = new Market(s);
    std::cout << m->Sell(x) << std::endl;
    
    m->Choose(g);
    std::cout << m->Sell(x) << std::endl;

    return 0;
}

单例模式

一个类在实例化时只能new出一个唯一的对象。

分类

  • 懒汉式:系统运行时,实例并不存在,只有当需要使用该实例时,才回去创建并使用实例。要考虑线程安全。
  • 饿汉式:系统一运行就初始化实例,当需要时直接调用即可。这种方式本身就线程安全。

特点

  • 构造函数和析构函数为私有类型,目的是禁止外部构造和析构。
  • 拷贝构造函数和赋值构造函数是私有类型,目的是禁止外部拷贝和赋值,确保实例的唯一性。
  • 类中有一个获取实例的静态方法,可以全局访问。

懒汉模式

系统运行时,实例并不存在,只有当需要使用该实例时,才会去创建并使用实例。要考虑线程安全。

class single{
public:
    static single* getInstance(){
        if(instance == nullptr){
            instance = new single();
        }
        return instance;
    }
private:
    static single* instance;
    single(){};
};

single* single::instance = nullptr; //类外初始化静态变量

int main(){
    single* s = single::getInstance();
}
class single{
public:
    static single* getInstance()
    {
        if(instance == nullptr){
            m.lock();
            //再判断一次,确保不会再加锁期间多个线程同时进入
            if(instance == nullptr){
                instance = new single();
            }
            m.unlock();
        }
        return instance;
    }
private:
    static single* instance;
    static std::mutex m;
    single(){};
};

single* single::instance = nullptr;
mutex single::m;

饿汉模式

系统一运行就初始化实例,当需要时直接调用即可。这种方式本身就线程安全

class single{
public:
    static single* getInstance(){
        return instance;
    }
private:
    static single* instance;
    single(){};
};

//再main函数执行前就初始化instance对象,是线程安全的
singel* single::instance = new single; //类外初始化静态变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值