设计模式总结

设计模式是前辈们对代码开发经验的总结,是解决特定问题的⼀系列套路。它不是语法规定,⽽是⼀套来提⾼代码可复⽤性、可维护性、可读性、稳健性以及安全性的解决⽅案。

六⼤原则

单⼀职责原则
类的职责应该单⼀,⼀个⽅法只做⼀件事,职责划分清晰了
开闭原则

对扩展开放,对修改封闭
对软件实体的改动,最好⽤扩展⽽⾮修改的⽅式。
⾥⽒替换原则
通俗点讲,就是只要⽗类能出现的地⽅,⼦类就可以出现,⽽且替换为⼦类也不会产⽣任何错误或异常。
在继承类时,务必重写⽗类中所有的⽅法,尤其需要注意⽗类的protected⽅法,⼦类尽量不要暴露⾃⼰的public⽅法供外界调⽤。
依赖倒置原则
⾼层模块不应该依赖低层模块,两者都应该依赖其抽象. 不可分割的原⼦逻辑就是低层模式,原⼦逻辑组装成的就是⾼层模块。
模块间依赖通过抽象(接⼝)发⽣,具体类之间不直接依赖
迪⽶特法则【最少知道法则】
尽量减少对象之间的交互,从⽽减⼩类之间的耦合。⼀个对象应该对其他对象有最少的了解。
接⼝隔离原则
客⼾端不应该依赖它不需要的接⼝,类间的依赖关系应该建⽴在最⼩的接⼝上
使⽤建议:接⼝设计尽量精简单⼀,但是不要对外暴露没有实际意义的接⼝。
⽤例:修改密码,不应该提供修改⽤⼾信息接⼝,⽽就是单⼀的最⼩修改密码接⼝,更不要暴露数据库操作

从整体上来理解六⼤设计原则,可以简要的概括为⼀句话,⽤抽象构建框架,⽤实现扩展细节,具体 到每⼀条设计原则,则对应⼀条注意事项:

单⼀职责原则告诉我们实现类要职责单⼀;
⾥⽒替换原则告诉我们不要破坏继承体系;
依赖倒置原则告诉我们要⾯向接⼝编程;
接⼝隔离原则告诉我们在设计接⼝的时候要精简单⼀;
迪⽶特法则告诉我们要降低耦合;
开闭原则是总纲,告诉我们要对扩展开放,对修改关闭。

单例模式

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个

访问它的全局访问点,该实例被所有程序模块共享。

比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:饿汉模式,懒汉模式

饿汉模式

就是说不管你将来用不用,程序启动时就会创建⼀个唯⼀的实例对象。 因为单例对象已经确定, 所以⽐较适⽤于多线程环境中, 多线程获取单例对象不需要加锁, 可以有效的避免资源竞争, 提⾼性能。

cpp 复制代码
#include <iostream>
using namespace std;
 
class Singleton {
private:
    static Singleton _eton;
    int _data;
private:
    Singleton() :_data(99) {
        cout << "单例对象构造" << endl;
    }
    ~Singleton() {}
public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static Singleton& getInstance()
    {
        return _eton;
    }
    int getData() {
        return _data;
    }
};
Singleton Singleton::_eton;
 
 
int main()
{
    //cout << Singleton::getInstance().getData() << endl;
    return 0;
}

结果演示

注释前:

注释后:

由此可见,在main函数启动后,就会自动构造单例对象,即便是没有调用该单例对象。

懒汉模式

第⼀次使⽤要使⽤单例对象的时候创建实例对象。如果单例对象构造特别耗时或者耗费资源(加载插件、加载⽹络资源等), 可以选择懒汉模式, 在第⼀次使⽤的时候才创建对象。

cpp 复制代码
class B
{
public:
	static B* GetInstance()
	{
		if (_inst == nullptr)
		{
			_inst = new B;
		}
 
		return _inst;
	}
 
	static void DelInstance()
	{
		if (_inst)
		{
			delete _inst;
			_inst = nullptr;
		}
	}
 
private:
	B()
	{}
 
	~B()
	{
		cout << "数据写到文件" << endl;
	}
 
	B(const B& aa) = delete;
	B& operator=(const B& aa) = delete;
 
	static B* _inst;
 
	class gc
	{
	public:
		~gc()
		{
			DelInstance();
		}
	};
 
	static gc _gc;
};
 
B* B::_inst = nullptr;
B::gc B::_gc;

下面再介绍一种《Effective C++》⼀书作者 Scott Meyers 提出的⼀种更加优雅简便的单例模式 Meyers' Singleton in C++。

C++11 Static local variables 特性以确保C++11起,静态变量将能够在满⾜ thread-safe 的前提下唯⼀地被构造和析构。

cpp 复制代码
#include <iostream>
using namespace std;
 
class Singleton {
private:
    int _data;
private:
    Singleton() :_data(99) {
        cout << "单例对象构造" << endl;
    }
    ~Singleton() {}
public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static Singleton& getInstance()
    {
        static Singleton _eton;
        return _eton;
    }
    int getData() {
        return _data;
    }
};
 
 
int main()
{
    cout << Singleton::getInstance().getData() << endl;
    return 0;
}

结果演示

没注释:

注释后:

由此可见,懒汉模式中,只有第一次创建对象时,才会构造单例对象。

工厂模式

⼯⼚模式是⼀种创建型设计模式, 它提供了⼀种创建对象的最佳⽅式。在⼯⼚模式中,我们创建对象时不会对上层暴露创建逻辑,⽽是通过使⽤⼀个共同结构来指向新创建的对象,以此实现创建-使⽤的分离。
⼯⼚模式可以分为:简单工厂模式,工厂方法模式,抽象工厂模式。

简单工厂模式

简单⼯⼚模式: 简单⼯⼚模式实现由⼀个⼯⼚对象通过类型决定创建出来指定产品类的实例。假设
有个⼯⼚能⽣产出⽔果,当客⼾需要产品的时候明确告知⼯⼚⽣产哪类⽔果,⼯⼚需要接收⽤⼾提
供的类别信息,当新增产品的时候,⼯⼚内部去添加新产品的⽣产⽅式。

简单⼯⼚模式:通过参数控制可以⽣产任何产品
优点:简单粗暴,直观易懂。使⽤⼀个⼯⼚⽣产同⼀等级结构下的任意产品
缺点:

  1. 所有东西⽣产在⼀起,产品太多会导致代码量庞⼤
  1. 开闭原则遵循(开放拓展,关闭修改)的不是太好,要新增产品就必须修改⼯⼚⽅法。
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>
class Fruit {
public:
	Fruit() {}
	virtual void show() = 0;
};
class Apple : public Fruit {
public:
	Apple() {}
	virtual void show() {
		std::cout << "我是一个苹果" << std::endl;
	}
};
class Banana : public Fruit {
public:
	Banana() {}
	virtual void show() {
		std::cout << "我是一个香蕉" << std::endl;
	}
};
class FruitFactory {
public:
	static std::shared_ptr<Fruit> create(const std::string& name) {
		if (name == "苹果") {
			return std::make_shared<Apple>();
		}
		else if (name == "⾹蕉") {
			return std::make_shared<Banana>();
		}
		return std::shared_ptr<Fruit>();
	}
};
int main()
{
	std::shared_ptr<Fruit> fruit = FruitFactory::create("苹果");
	fruit->show();
	fruit = FruitFactory::create("⾹蕉");
	fruit->show();
	return 0;
}

运行结果:

这个模式的结构和管理产品对象的⽅式⼗分简单, 但是它的扩展性⾮常差,当我们需要新增产品的时候,就需要去修改⼯⼚类新增⼀个类型的产品创建逻辑,违背了开闭原则。

工厂方法模式

⼯⼚⽅法模式: 在简单⼯⼚模式下新增多个⼯⼚,多个产品,每个产品对应⼀个⼯⼚。假设现在有A、B 两种产品,则开两个⼯⼚,⼯⼚ A 负责⽣产产品 A,⼯⼚ B 负责⽣产产品 B,⽤⼾只知道产品的⼯⼚名,⽽不知道具体的产品信息,⼯⼚不需要再接收客⼾的产品类别,⽽只负责⽣产产品。

⼯⼚⽅法:定义⼀个创建对象的接⼝,但是由⼦类来决定创建哪种对象,使⽤多个⼯⼚分别⽣产指定的固定产品

优点:

  1. 减轻了⼯⼚类的负担,将某类产品的⽣产交给指定的⼯⼚来进⾏

  2. 开闭原则遵循较好,添加新产品只需要新增产品的⼯⼚即可,不需要修改原先的⼯⼚类

缺点:对于某种可以形成⼀组产品族的情况处理较为复杂,需要创建⼤量的⼯⼚类.

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>


class Fruit {
public:
	Fruit() {}
	virtual void show() = 0;
};
class Apple : public Fruit {
public:
	Apple() {}
	virtual void show() {
		std::cout << "我是一个苹果" << std::endl;
	}
private:
	std::string _color;
};
class Banana : public Fruit {
public:
	Banana() {}
	virtual void show() {
		std::cout << "我是一个香蕉" << std::endl;
	}
};
class FruitFactory {
public:
	virtual std::shared_ptr<Fruit> create() = 0;
};
class AppleFactory : public FruitFactory {
public:
	virtual std::shared_ptr<Fruit> create() {
		return std::make_shared<Apple>();
	}
};
class BananaFactory : public FruitFactory {
public:
	virtual std::shared_ptr<Fruit> create() {
		return std::make_shared<Banana>();
	}
};
int main()
{
	std::shared_ptr<FruitFactory> factory(new AppleFactory());
	std::shared_ptr<Fruit> fruit = factory->create();
	fruit->show();
	factory.reset(new BananaFactory());
	fruit = factory->create();
	fruit->show();
	return 0;
}

运行结果:


⼯⼚⽅法模式每次增加⼀个产品时,都需要增加⼀个具体产品类和⼯⼚类,这会使得系统中类的个数成倍增加,在⼀定程度上增加了系统的耦合度。

抽象工厂模式

抽象⼯⼚模式: ⼯⼚⽅法模式通过引⼊⼯⼚等级结构,解决了简单⼯⼚模式中⼯⼚类职责太重的问
题,但由于⼯⼚⽅法模式中的每个⼯⼚只⽣产⼀类产品,可能会导致系统中存在⼤量的⼯⼚类,势
必会增加系统的开销。此时,我们可以考虑将⼀些相关的产品组成⼀个产品族(位于不同产品等级
结构中功能相关联的产品组成的家族),由同⼀个⼯⼚来统⼀⽣产,这就是抽象⼯⼚模式的基本思
想。

抽象⼯⼚:围绕⼀个超级⼯⼚创建其他⼯⼚。每个⽣成的⼯⼚按照⼯⼚模式提供对象。
思想:将⼯⼚抽象成两层,抽象⼯⼚ & 具体⼯⼚⼦类, 在⼯⼚⼦类种⽣产不同类型的⼦产品

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

class Fruit {
public:
	Fruit() {}
	virtual void show() = 0;
};
class Apple : public Fruit {
public:
	Apple() {}
	virtual void show() {
		std::cout << "我是一个苹果" << std::endl;
	}
private:
	std::string _color;
};
class Banana : public Fruit {
public:
	Banana() {}
	virtual void show() {
		std::cout << "我是一个香蕉" << std::endl;
	}
};
class Animal {
public:
	virtual void voice() = 0;
};
class Lamp : public Animal {
public:
	void voice() { std::cout << "咩咩咩\n"; }
};
class Dog : public Animal {
public:
	void voice() { std::cout << "汪汪汪\n"; }
};
class Factory {
public:
	virtual std::shared_ptr<Fruit> getFruit(const std::string& name) = 0;
	virtual std::shared_ptr<Animal> getAnimal(const std::string& name) = 0;
};
class FruitFactory : public Factory {
public:
	virtual std::shared_ptr<Animal> getAnimal(const std::string& name) {
		return std::shared_ptr<Animal>();
	}
	virtual std::shared_ptr<Fruit> getFruit(const std::string& name) {
		if (name == "苹果") {
			return std::make_shared<Apple>();
		}
		else if (name == "⾹蕉") {
			return std::make_shared<Banana>();
		}
		return std::shared_ptr<Fruit>();
	}
};
class AnimalFactory : public Factory {

public:
	virtual std::shared_ptr<Fruit> getFruit(const std::string& name) {
		return std::shared_ptr<Fruit>();
	}
	virtual std::shared_ptr<Animal> getAnimal(const std::string& name) {
		if (name == "⼩⽺") {
			return std::make_shared<Lamp>();
		}
		else if (name == "⼩狗") {
			return std::make_shared<Dog>();
		}
		return std::shared_ptr<Animal>();
	}
};
class FactoryProducer {
public:
	static std::shared_ptr<Factory> getFactory(const std::string& name) {
		if (name == "动物") {
			return std::make_shared<AnimalFactory>();
		}
		else {
			return std::make_shared<FruitFactory>();
		}
	}
};
int main()
{
	std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("⽔果");
	std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");
	fruit->show();
	fruit = fruit_factory->getFruit("⾹蕉");
	fruit->show();
	std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动物");
	std::shared_ptr<Animal> animal = animal_factory->getAnimal("⼩⽺");
	animal->voice();
	animal = animal_factory->getAnimal("⼩狗");
	animal->voice();
	return 0;
}

运行结果:

建造者模式

建造者模式是⼀种创建型设计模式, 使⽤多个简单的对象⼀步⼀步构建成⼀个复杂的对象,能够将⼀个复杂的对象的构建与它的表⽰分离,提供⼀种创建对象的最佳⽅式。主要⽤于解决对象的构建过于复杂的问题。
建造者模式主要基于四个核⼼类实现:

抽象产品类:
具体产品类:⼀个具体的产品对象类
抽象Builder类:创建⼀个产品对象所需的各个部件的抽象接⼝
具体产品的Builder类:实现抽象接⼝,构建各个部件
指挥者Director类:统⼀组建过程,提供给调⽤者使⽤,通过指挥者来构造产品

cpp 复制代码
#include <iostream>
#include <memory>
/*抽象电脑类*/
class Computer {
public:
	Computer() {}
	void setBoard(const std::string& board) { _board = board; }
	void setDisplay(const std::string& display) { _display = display; }
	virtual void setOs() = 0;
	std::string toString() {
		std::string computer = "Computer:{\n";
		computer += "\tboard=" + _board + ",\n";
		computer += "\tdisplay=" + _display + ",\n";
		computer += "\tOs=" + _os + ",\n";
		computer += "}\n";
		return computer;
	}
protected:
	std::string _board;
	std::string _display;
	std::string _os;
};
/*具体产品类*/
class MacBook : public Computer {
public:
	MacBook() {}
	virtual void setOs() {
		_os = "Max Os X12";
	}
};
/*抽象建造者类:包含创建⼀个产品对象的各个部件的抽象接⼝*/
class Builder {
public:
	virtual void buildBoard(const std::string& board) = 0;
	virtual void buildDisplay(const std::string& display) = 0;
	virtual void buildOs() = 0;
	virtual std::shared_ptr<Computer> build() = 0;
};
/*具体产品的具体建造者类:实现抽象接⼝,构建和组装各个部件*/
class MacBookBuilder : public Builder {
public:
	MacBookBuilder() : _computer(new MacBook()) {}
	virtual void buildBoard(const std::string& board) {
		_computer->setBoard(board);
	}
	virtual void buildDisplay(const std::string& display) {
		_computer->setDisplay(display);
	}
	virtual void buildOs() {
		_computer->setOs();
	}
	virtual std::shared_ptr<Computer> build() {
		return _computer;
	}
private:
	std::shared_ptr<Computer> _computer;
};
/*指挥者类,提供给调⽤者使⽤,通过指挥者来构造复杂产品*/
class Director {
public:
	Director(Builder* builder) :_builder(builder) {}
	void construct(const std::string& board, const std::string& display) {
		_builder->buildBoard(board);
		_builder->buildDisplay(display);
		_builder->buildOs();
	}
private:
	std::shared_ptr<Builder> _builder;
};
int main()
{
	Builder* buidler = new MacBookBuilder();
	std::unique_ptr<Director> pd(new Director(buidler));
	pd->construct("英特尔主板", "VOC显示器");
	std::shared_ptr<Computer> computer = buidler->build();
	std::cout << computer->toString();
	return 0;
}

运行结果:

代理模式

代理模式指代理控制对其他对象的访问,也就是代理对象控制对原对象的引⽤。在某些情况下,⼀个对象不适合或者不能直接被引⽤访问,⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤。
代理模式的结构包括⼀个是真正的你要访问的对象(⽬标类),⼀个是代理对象。⽬标对象与代理对象实现同⼀个接⼝,先访问代理类再通过代理类访问⽬标对象。
代理模式分为静态代理、动态代理:

静态代理指的是,在编译时就已经确定好了代理类和被代理类的关系。也就是说,在编译时就已经确定了代理类要代理的是哪个被代理类。
动态代理指的是,在运⾏时才动态⽣成代理类,并将其与被代理类绑定。这意味着,在运⾏时才能确定代理类要代理的是哪个被代理类。
以租房为例,房东将房⼦租出去,但是要租房⼦出去,需要发布招租启⽰, 带⼈看房,负责维修,这些⼯作中有些操作并⾮房东能完成,因此房东为了图省事,将房⼦委托给中介进⾏租赁。 代理模式实现:

cpp 复制代码
/*房东要把⼀个房⼦通过中介租出去理解代理模式*/
#include <iostream>
#include <string>
class RentHouse {
public:
	virtual void rentHouse() = 0;
};
/*房东类:将房⼦租出去*/
class Landlord : public RentHouse {
public:
	void rentHouse() {
		std::cout << "将房子租出去\n";
	}
};
/*中介代理类:对租房⼦进⾏功能加强,实现租房以外的其他功能*/
class Intermediary : public RentHouse {
public:
	void rentHouse() {
		std::cout << "发布招租启示\n";
		std::cout << "带人看房\n";
		_landlord.rentHouse();
		std::cout << "负责租后维修\n";
	}
private:
	Landlord _landlord;
};
int main()
{
	Intermediary intermediary;
	intermediary.rentHouse();
	return 0;
}

运行结果:

相关推荐
触底反弹6 小时前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范
杨充1 天前
6.设计原则的全景图
设计模式·开源·全栈
杨充1 天前
2.面向对象的特性
设计模式
杨充1 天前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充1 天前
8.反模式与坏味道
设计模式·开源·代码规范
杨充1 天前
3.接口vs抽象类比较
设计模式
咖啡八杯1 天前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法