设计模式原则
- 单一职责原则
- 含义:每个类应该只有一个职责,只有一个原因可以引起类的变化
- 目的:通过将不同职责分离到不同的类中,从而提高代码的可读性和可维护性
- 开闭原则
- 含义:类、函数等应该对拓展开放、对修改关闭
- 目的:通过继承和多态机制,允许系统在不修改现有代码的情况下进行拓展,从而提高系统的稳定性和灵活性
- 里氏替换原则
- 含义:子类对象必须能够替换其基类对象,并且不会导致程序的逻辑错误
- 目的:确保继承关系的正确性,使得子类可以完全替代基类
- 依赖倒置原则
- 含义:高层模块不应该依赖其底层模块,两者应该依赖其抽象。抽象不依赖其细节,但是细节应该依赖抽象
- 目的:通过依赖接口或者抽象类类解耦高层和底层的模块,从而提高系统的可维护性和可拓展性
- 接口隔离原则
- 含义:客户端不应该依赖它不需要的接口,应该将大的接口拆分的成小的接口
- 目的:通过使用多个特定客户端接口,而不是一个通用接口,提高系统的灵活性和可维护性
- 合成/聚合复用原则
- 含义:多使用对象的合成而不是继承来达到复用的目的
- 目的:通过组合或者聚合其他对象类实现新的功能
- 迪米特原则
- 含义:一个对象应该对其他对象有最少的了解,减少与其他对象的交互
- 目的:通过减少对象直接的耦合,提高系统的模块化和可维护性
构建型模式
单例模式
单例模式的主要目的是确保一个类在整个程序中只有一个实例,并提供全局的访问点。
单例模式的特点
唯一实例:单例模式确保一个类只有一个实例存在,避免了不必要的实例化,节省了系统资源。
全局访问点:单例模式提供了一个全局访问点,可以通过这个访问点获取唯一的实例。
控制实例创建:通过单例模式,程序可以更好地控制实例的创建和生命周期。
单例模式的应用场景需要全局访问的唯一实例:如日志系统、配置管理、线程池、数据库连接等。
节省资源:某些资源消耗较大的对象,如文件系统、数据库连接等,可以通过单例模式避免重复创建,节省资源。
控制实例数量:需要严格控制某个类的实例数量,避免过多的实例对系统性能造成影响。
单例模式的优缺点优点 :
- 节省资源:通过控制实例的创建数量,节省系统资源。
- 全局访问:提供一个全局访问点,方便获取唯一实例。
- 实例控制:严格控制实例的创建和生命周期,确保系统的一致性。
缺点:
- 难以扩展:单例模式限制了类的扩展,增加新功能时可能需要修改现有代码。
- 隐藏依赖:全局访问点可能导致依赖关系隐藏,使代码难以理解和维护。
- 并发问题:在多线程环境下,需要特别注意线程安全问题,否则可能导致多个实例被创建。
Effective C++提供方法(仅支持C++11以后)
cpp
template<typename T>
class Singleton {
private:
Singleton(){}
~Singleton(){}
public:
Singleton(const Singleton&) = delete;
Singleton& operator = (const Singleton) = delete;
static T& getInstance() {
static Singleton _eton;
return _eton;
}
};
饿汉式
类加载的时候就创建实例,线程安全但是可能会造成资源浪费。(害怕吃不上,提前准备好)
相似方法总结
- 构造函数私有化,防止外部进行实例
- 禁止拷贝构造函数和赋值运算运算,防止被复制
- 互斥锁的设计
- 静态实例,类外初始化
- 公共方法中提供全局访问点
cpp
class Singleton
{
private:
Singleton() {};
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* instance;
public:
static Singleton* getInstance()
{
return instance;
}
};
//Singleton* instance = nullptr;
Singleton* Singleton::instance = nullptr;
懒汉式
第一次调用的时候,再创建实例,避免资源的浪费,但是可能会造成线程不安全。
cpp
class Singleton_lazy
{
private:
Singleton_lazy(){}
Singleton_lazy(const Singleton_lazy&) = delete;
Singleton_lazy& operator = (const Singleton&) = delete;
static Singleton_lazy* instance;
public:
static Singleton_lazy* getInstance()
{
if (instance == nullptr)
{
instance == new Singleton_lazy();
}
return instance;
}
};
Singleton_lazy* Singleton_lazy::instance = nullptr;
线程安全的懒汉式
使用互斥锁去保证线程安全。
cpp
#include<mutex>
class Singleton_lazy_mutex
{
private:
Singleton_lazy_mutex(){}
Singleton_lazy_mutex(const Singleton_lazy_mutex&) = delete;
Singleton_lazy_mutex& operator = (const Singleton_lazy_mutex&) = delete;
static Singleton_lazy_mutex* instance;
static std::mutex mtx;
public:
Singleton_lazy_mutex* getInstance()
{
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr)
{
instance = new Singleton_lazy_mutex();
}
return instance;
}
};
Singleton_lazy_mutex* Singleton_lazy_mutex::instance = nullptr;
std::mutex Singleton_lazy_mutex::mtx;
C++11标准实现线程安全
C++11引入线程安全的静态局部变量初始化
cpp
class singleton_11
{
private:
singleton_11(){}
singleton_11(const singleton_11&) = delete;
singleton_11& operator=(const singleton_11&) = delete;
public:
static singleton_11& getInstance()
{
static singleton_11 instance;
return instance;
}
};
双重检查锁定
第一次检查的时候不加锁,只有实例为空的时候才可以加锁,减少了加锁的开销。
cpp
class singleton_double
{
private:
singleton_double(){}
singleton_double(const singleton_double&) = delete;
singleton_double& operator=(const singleton_double&) = delete;
static singleton_double* instance;
static std::mutex mtx;
public:
singleton_double* getInstance()
{
if (instance == nullptr)
{
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr)
{
instance = new singleton_double();
}
}
return instance;
}
};
singleton_double* singleton_double::instance = nullptr;
std::mutex singleton_double::mtx;
工厂模式
简单工厂模式
设计一个汽车工厂,当需要某种类型的汽车时,直接告诉工厂自己的需求即可,不需要关注汽车的各种零部件如何组装,也不需要关注不同的类型的汽车的设计图纸。作为用户只需要问工厂伸手要就行。
简单工厂模式即是让工厂承担构建所有的对象的全部职责。用户想要什么类型的产品,只需让工厂生产出来即可。
工厂模式的弊端
- 超级类的产生:当生产的要求过多的时候,工厂需要承担的职责就会变多,从而变成超级类。例如市场对汽车的类型需要多样,从而导致工厂需要不断的更改其方法。工厂类此时拥有多个引起修改的原因,违背了单一职责原则。
- 生产新产品的时候,必须在工厂类中添加新的分支。违反设计模式中的开闭原则,因为的开闭原则下要求增加新功能的时候,只需要增加新的类,而不是修改现在已经拥有的类。
- 增加程序的复杂性,提高调试和维护成本:如果是一个简单的系统中,直接创建类对象可能比通过工厂类来创建更加的简单明了。
cpp
#include <iostream>
#include <string>
// 抽象产品类
class Product {
public:
virtual void use() = 0;
};
// 具体产品类A
class ConcreteProductA : public Product {
public:
void use() override {
std::cout << "Using Product A" << std::endl;
}
};
// 具体产品类B
class ConcreteProductB : public Product {
public:
void use() override {
std::cout << "Using Product B" << std::endl;
}
};
// 工厂类
class SimpleFactory {
public:
static Product* createProduct(const std::string& type) {
if (type == "A") {
return new ConcreteProductA();
} else if (type == "B") {
return new ConcreteProductB();
}
return nullptr;
}
};
// 客户端代码
int main() {
Product* productA = SimpleFactory::createProduct("A");
if (productA) {
productA->use();
delete productA;
}
Product* productB = SimpleFactory::createProduct("B");
if (productB) {
productB->use();
delete productB;
}
return 0;
}
工厂方法模式
工厂方法模式的产生就是为了解决简单工厂模式弊端。工厂方法模式规定每一个产品都有一个专属的工厂,例如越野车有越野车的工厂,轿车有轿车的工厂等。
工厂方法模式解决简单工厂模式的弊端。首先,生产的汽车种类变多的时候,工厂类不会变成超级类,当需要修改某个汽车厂只需要对某个汽车厂进行修改,不需要像之前对总工厂进行修改。从而符合单一职责的设计原则。其次,当生产新的汽车类型的时候,不需要修改现有的工厂,只需要添加新的工厂即可。保持了面向对象的可拓展性,符合开闭原则。
优缺点
优点
- 遵循开闭原则:可以在不修改现有代码的情况下增加新的产品类。
- 代码复用:工厂方法将具体产品的实例化逻辑封装在子类中,避免了重复代码。
- 解耦:将对象的创建与使用分离,减少了类之间的耦合。
- 单一职责原则:每个具体工厂类只负责一种具体产品的创建,职责单一,代码更清晰。
缺点
- 增加复杂性:每增加一个产品类,就需要增加一个相应的具体工厂类,增加了系统的复杂性。
- 类爆炸:可能会引入大量的子类,导致类数量急剧增加,维护起来比较繁琐。
cpp
class Product
{
public:
virtual void use() = 0;
virtual ~Product(){}
};
class car1 :public Product
{
public:
void use()override
{
std::cout << "越野车生产方法" << std::endl;
}
};
class car2 :public Product
{
public:
void use() override
{
std::cout << "轿车生产方法" << std::endl;
}
};
class Factory
{
public:
virtual Product* createProduct() = 0;
virtual ~Factory(){}
};
class createCar1 :public Factory
{
public:
Product* createProduct() override
{
return new car1;
}
};
class createCar2 :public Factory
{
public:
Product* createProduct()override
{
return new car2;
}
};
int main()
{
//建造越野车工厂,生产越野车
Factory* factory1 = new createCar1();
Product* product1 = factory1->createProduct();
product1->use();
delete product1;
delete factory1;
//小轿车工厂,生产小轿车
Factory* factory2 = new createCar2();
Product* product2 = factory2->createProduct();
product2->use();
delete product2;
delete factory2;
return 0;
}
抽象工厂模式
抽象工厂可以理解为一个超级工厂,通过该工厂可以创建生产其他各种类型物品的子工厂。这些生成的子工厂可以按照工厂的逻辑提供具体函数实现或者对象。
cpp
class Fruit {
public:
Fruit(){}
virtual void show() = 0;
};
class Apple :public Fruit {
public:
Apple(){}
void show()override {
std::cout << "生产苹果" << std::endl;
}
};
class Banana :public Fruit {
public:
Banana(){}
void show()override {
std::cout << "生产香蕉" << std::endl;
}
};
class Animal {
public:
virtual void voice() = 0;
};
class Dog :public Animal {
public:
void voice() override {
std::cout << "呕吼~~~" << std::endl;
}
};
class Lamp :public Animal {
public:
void voice() override {
std::cout << "沸羊羊" << std::endl;
}
};
//将水果工厂和动物工厂进行组合("超级工厂")
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:
std::shared_ptr<Animal> getAnimal(const std::string& name) override {
return std::shared_ptr<Animal>();
}
std::shared_ptr<Fruit> getFruit(const std::string& name) override {
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:
std::shared_ptr<Fruit> getFruit(const std::string& name) override {
return std::shared_ptr<Fruit>();
}
std::shared_ptr<Animal>getAnimal(const std::string& name) override {
if (name == "羊") {
return std::make_shared<Lamp>();
}
else if (name == "狗") {
return std::make_shared<Dog>();
}
return shared_ptr<Animal>();
}
};
//工厂生产者
class FactorProducter {
public:
static std::shared_ptr<Factory>getFacory(const std::string& name) {
if (name == "动物") {
return std::make_shared<AnimalFactory>();
}
else {
return std::make_shared<FruitFactory>();
}
}
};
int main()
{
//利用超级工厂(FactorProducter)创建一个生产水果的工厂(FruitFactory)
std::shared_ptr<Factory> fruit_factory = FactorProducter::getFacory("果子");
//然后水果工厂根据需求生产出苹果和香蕉
std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");
fruit->show();
fruit = fruit_factory->getFruit("香蕉");
fruit->show();
std::shared_ptr<Factory> animal_factory = FactorProducter::getFacory("动物");
std::shared_ptr<Animal> animal = animal_factory->getAnimal("狗");
animal->voice();
return 0;
}
建造者模式
建造者模式,即是用简单的对象一步一步构建成一个复杂对象的模式,将创建复杂对象的类进行分离,从而提供构建复杂对象的方法。
实现核心分析
- 抽象产品类
- 具体产品类:从抽象产品类构建的具体产品
- 抽象Builder类:构建一个产品对象,所需要工具的抽象
- 具体产品的Builder类:实现抽象接口,构建具体的组件
- 指挥者Director类:统一组件过程,提供给调用者使用,通过指挥者来构建具体的产品
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<memory>
#include<string>
using namespace std;
//抽象电脑类
class Computer {
protected:
string _board;
string _display;
string _os;
public:
using ptr = shared_ptr<Computer>;
Computer(){}
//主板、显示器、系统g
void setBoard(const string& board) { _board = board; }
void setDisplay(const string& display) { _display = display; }
virtual void setOs() = 0;
//转换为字符串
string toString() {
string computer = "Computer:{\n";
computer += "\tboard=" + _board + ",\n";
computer += "\tdisplay=" + _display + "\n";
computer += "\tOs=" + _os + ",\n";
computer += "}\n";
return computer;
}
};
//具体产品
class Lenovo :public Computer {
public:
using ptr = shared_ptr<Lenovo>;
Lenovo(){}
void setOs()override {
_os = "Amd 8090";
}
};
//抽象建造者模式
class Builder {
public:
using ptr = shared_ptr<Builder>;
virtual void buildBoard(const string& board) = 0;
virtual void buildDisplay(const string& display) = 0;
virtual void buildOs() = 0;
virtual Computer::ptr build() = 0;
};
//建造者构建具体产品
class LenoveBuilder :public Builder
{
public:
using ptr = shared_ptr<LenoveBuilder>;
LenoveBuilder():_computer(new Lenovo()){}
void buildBoard(const string& board)override
{
_computer->setBoard(board);
}
void buildDisplay(const string& display)override
{
_computer->setDisplay(display);
}
void buildOs() override
{
_computer->setOs();
}
Computer::ptr build() override
{
return _computer;
}
private:
Computer::ptr _computer;
};
//指挥者
class Director {
private:
Builder::ptr _builder;
public:
Director(Builder* builder) :_builder(builder){}
void construct(const string& board, const string& display) {
_builder->buildBoard(board);
_builder->buildDisplay(display);
_builder->buildOs();
}
};
int main()
{
//老板先找一个联想程序员,然后让该程序员干活(构建一个电脑并打印出来)
Builder* build = new LenoveBuilder();
unique_ptr<Director> pd(new Director(build));
pd->construct("amd", "三星");
Computer::ptr computer = build->build();
cout << computer->toString();
return 0;
}