单一责任原则(Single Responsibility Principle)
开闭原则(Open Closed Principle)
里氏替换原则(Liskov Substitution Principle)
依赖倒置原则(Dependence Inversion Principle)
迪米特法则(Law of Demeter) 最少知道法则
接口隔离原则
总结:从整体上理解六大设计原则,可以简要概括为一句话,用抽象构建框架,用实现扩展细节,具体到每一条设计原则,则对应一条注意事项
单例模式,顾名思义,就是只能由一个实例,那么我们就必须保证:该类不能被复制,该类不能被公开的创造。
单例模式又可以分为懒汉模式和饿汉模式
懒汉模式:对于一个进程来说,我们只有在第一次使用的时候才去创建。优点是节省进程加载的时间。缺点是在第一次使用的时候才去创建。
饿汉模式:在代码转化为进程时,先于main函数之前就已经创建好了,不需要使用的时候再去创建。优点是可以直接使用,该资源早早创建出来,影响进程加载的速度。
饿汉单例模式:
构造、拷贝构造、赋值私有化,不能被显示构造。
静态单例对象的指针,在程序初始化时完成创建。
提供一个获取单例对象的静态对象,可以在任意位置获取单例对象
其生命周期与程序的生命周期是相同的。这个同样适用于多线程的情况,没有线程安全问题。
/* 饿汉单例模式 以空间换时间 */
class Singleton{
public:
static Singleton* getInstance() { return _eton; }
int getData() { return _data; }
private:
Singleton(int data = 99) : _data(data){}
~Singleton(){};
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
static Singleton* _eton;
int _data;
};
Singleton* Singleton::_eton =new Singleton;
懒汉单例模式:
构造、拷贝构造、赋值私有化,不能被显示构造。
静态单例对象的指针,在程序初始化时完成创建。
提供一个获取单例对象的静态对象,可以在任意位置获取单例对象
其生命周期与程序的生命周期是相同的。懒汉单例模式会有线程安全问题,可以通过两种方式解决。
方法一:加锁 + 双检查 (C++98)
class Singleton
{
public:
//3、提供一个全局访问点获取单例对象
static Singleton* GetInstance()
{
//双检查
if (_inst == nullptr)
{
_mtx.lock();
if (_inst == nullptr)
{
_inst = new Singleton;
}
_mtx.unlock();
}
return _inst;
}
private:
//1、将构造函数设置为私有,并防拷贝
Singleton()
{}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
//2、提供一个指向单例对象的static指针
static Singleton* _inst;
static mutex _mtx; //互斥锁
};
//在程序入口之前先将static指针初始化为空
Singleton* Singleton::_inst = nullptr;
mutex Singleton::_mtx; //初始化互斥锁
方法二:C++11后在静态函数中直接构造单例对象
/* 懒汉单例模式 懒加载 -- 延时加载思想 -- 一个对象用的时候再实例化 */
// 这里介绍 作者提出的一种更加优雅简便的单例模式 Meyers Singleton int C++
// C++11后是线程安全的
class Singleton{
public:
static Singleton& getInstance() {
static Singleton _eton;
return _eton;
}
int getData() { return _data; }
private:
Singleton(int data = 99) : _data(data){}
~Singleton() {};
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
int _data;
};
工厂模式是一种创建型的设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象不会对上层暴露创建逻辑,而是通过使用一个共同结构来指向新创建的对象,因此实现创建-使用的分离。
简单工厂模式:简单工厂模式实现需要由一个工厂对象通过类型决定创建出来的制定产品类的实例。假设有个工厂可以生产水果,当客户需要产品时明确告知工厂生产哪种水果,工厂需要接收用户提供的类别信息,当新增产品的时候,工厂内部取添加新产品的生产方式
class Fruit{
public:
virtual void name() = 0;
private:
};
class Apple : public Fruit{
public:
void name() override{
std::cout << "I'm a apple" << std::endl;
}
};
class Banana : public Fruit{
public:
void name() override {
std::cout << "I'm a banana" << std::endl;
}
};
class FruitFactory {
public:
static std::shared_ptr<Fruit> create(const std::string &name) {
if (name == "苹果") {
return std::make_shared<Apple>();
} else {
return std::make_shared<Banana>();
}
}
};
int main() {
std::shared_ptr<Fruit> fruit = FruitFactory::create("苹果");
fruit->name();
fruit = FruitFactory::create("香蕉");
fruit->name();
return 0;
}
这个模式的结构和管理产品对象的方式非常简单,但是它的扩展性非常差,当我们需要新增产品的时候,就需要去修改工厂类新增一个类型的产品创造逻辑,违背了开闭原则
工厂方法模式:在简单的工厂模式下新增了多个工厂,多个产品,每个产品对应一个工厂。假设现在有A、B两种产品,则开两个工厂,工厂A主要负责生产产品A,工厂B主要生产产品B,用户只要知道产品的工厂名,而不需要知道具体的产品信息,工厂不需要接收客户的产品类别,只负责生产产品。
工厂方法模式不同于简单工厂模式的地方在于工厂方法模式把对象的创建过程放到里子类里。这样工厂父对象和产品父对象一样,可以是抽象类或者接口,只定义相应的规范或操作,不涉及具体的创建或实现细节。
/* 工厂方法模式 */
class Fruit{
public:
virtual void name() = 0;
private:
};
class Apple : public Fruit{
public:
void name() override{
std::cout << "I'm a apple" << std::endl;
}
};
class Banana : public Fruit{
public:
void name() override {
std::cout << "I'm a banana" << std::endl;
}
};
class FruitFactory {
public:
virtual std::shared_ptr<Fruit> createFruit() = 0;
};
class AppleFactory : public FruitFactory {
public:
virtual std::shared_ptr<Fruit> createFruit() override {
return std::make_shared<Apple>();
}
};
class BananaFactory : public FruitFactory {
public:
virtual std::shared_ptr<Fruit> createFruit() override {
return std::make_shared<Banana>();
}
};
int main() {
std::shared_ptr<FruitFactory> ff(new AppleFactory());
std::shared_ptr<Fruit> fruit1 = ff->createFruit();
fruit1->name();
ff.reset(new BananaFactory());
std::shared_ptr<Fruit> fruit2 = ff->createFruit();
fruit2->name();
return 0;
}
工厂方法模式每次增减一个产品时,都需要增加一个具体的产品类和工厂类,这使得系统中类的个数成倍的增加,在一定程度上增加了系统的耦合度
抽象工厂模式:工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必增加系统的开销,此时我们可以考虑将一些相关的产品组成一个产品族(位于不同产品等级结构中功能相互关联的产品组成的家族),由于一个工厂统一生产,这就是抽象工厂模式的基本思想。
#include
#include
/* 简单工厂模式 */
class Fruit{
public:
virtual void name() = 0;
private:
};
class Apple : public Fruit{
public:
void name() override{
std::cout << "I'm a apple" << std::endl;
}
};
class Banana : public Fruit{
public:
void name() override {
std::cout << "I'm a banana" << std::endl;
}
};
class Animal {
public:
virtual void name() = 0;
};
class Lamp : public Animal {
public:
virtual void name() override {
std::cout << "I'm a Lamp" << std::endl;
}
};
class Dog : public Animal {
public:
virtual void name() override {
std::cout << "I'm a dog" << 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:
virtual std::shared_ptr<Fruit> getFruit(const std::string& name) override{
if (name == "苹果") {
return std::make_shared<Apple>();
} else {
return std::make_shared<Banana>();
}
}
virtual std::shared_ptr<Animal> getAnimal(const std::string& name) override{
return std::shared_ptr<Animal>();
}
};
class AnimalFactory : public Factory {
public:
virtual std::shared_ptr<Fruit> getFruit(const std::string& name) override {
return std::shared_ptr<Fruit>();
}
virtual std::shared_ptr<Animal> getAnimal(const std::string& name) override {
if (name == "山羊") {
return std::make_shared<Lamp>();
} else {
return std::make_shared<Dog>();
}
}
};
class FactoryProducer {
public:
static std::shared_ptr<Factory> create(const std::string &name) {
if (name == "水果") {
return std::make_shared<FruitFactory>();
} else {
return std::make_shared<AnimalFactory>();
}
}
};
int main() {
std::shared_ptr<Factory> ff = FactoryProducer::create("水果");
std::shared_ptr<Fruit> fruit = ff->getFruit("苹果");
fruit->name();
fruit = ff->getFruit("香蕉");
fruit->name();
ff = FactoryProducer::create("动物");
std::shared_ptr<Animal> animal = ff->getAnimal("山羊");
animal->name();
animal = ff->getAnimal("小狗");
animal->name();
return 0;
}
抽象工厂模式适用于生产多个工厂系列产品衍生的设计模式,增加新的产品等级结构复杂,需要对原有系统进行较大修改,甚至需要修改抽象层代码,违背了开闭原则
建造者模式是一种创建型的设计模式,使用多个简单对象一步一步构建成一个复杂的对象,能够将一个复杂的对象的构建与它的表示分离,提供一种创建对象的最佳方式。主要用于解决对象的构建过于复杂的问题。
1.建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者(Concrete Builder)角色。具体建造者类必须实现这个接口所要求的方法:一个是建造方法,另一个是结果返还方法。此时就是米线店的员工,按照收银员的要求的去准备具体的套餐,放入适当的米线,凉菜和饮料。
2.具体建造者(Concrete Builder)角色:担任这个角色的是于应用程序紧密相关的类,它们在应用程序调用下创建产品实例。这个角色主要完成的任务包括:实现Builder角色提供的接口,一步一步完成创建产品实例的过程。在建造过程完成后,提供产品的实例。是具体的做某个套餐的员工。
3.指导者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。导演者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者对象。是收银员,他知道我想要什么套餐,他会告诉里面的米线店员工去准备什么套餐。
4.产品(Product)角色:产品便是建造中的复杂对象。指导者角色是于客户端打交道的角色。导演者角色将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。具体建造者角色是做具体建造工作的,但却不为客户端所知。就是最后的套餐,所有东西放到一起端过来。
建造者模式主要基于四个核心实现:
#include
#include
#include
/* 通过MacBook的构造理解建造者模式*/
class Computer{
public:
Computer(){};
void setBoard(const std::string &board) { _board = board; }
void setDisplay(const std::string &display) { _display = display; }
virtual void setOs() = 0;
void showParamaters() {
std::string param = "Computer Paramaters: \n";
param += "\tBoard: " + _board + "\n";
param += "\tDispaly: " + _display + "\n";
param += "\tOs: " + _os + "\n";
std::cout << param << std::endl;
}
protected:
std::string _board;
std::string _display;
std::string _os;
};
class MacBook : public Computer{
public:
virtual void setOs() override {
_os = "Mac 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()) {}
void buildBoard(const std::string& board) {
_computer->setBoard(board);
}
void buildDisplay(const std::string& display) {
_computer->setDisplay(display);
}
void buildOs() {
_computer->setOs();
}
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 * builder = new MacBookBuilder();
std::unique_ptr<Director> director(new Director(builder));
director->construct("华硕主板", "三星显示器");
std::shared_ptr<Computer> computer = builder->build();
computer->showParamaters();
return 0;
}
代理模式指的是代理控制对其他对象的访问,也就是代理对象控制对原对象的引用。在某些情况下,一个对象不适合或者不能直接被引用访问,而代理对象可以在客户端和目标对象之间起到中介作用
代理模式的结构包括一个是真正的你要访问的目标对象(目标类)、一个是代理对象。目标对象与代理对象实现同一个接口,先访问代理类再通过代理类访问目标对象。代理模式一般分为静态代理、动态代理
以租房为例,租客租房,中间经过房屋中介向房东租房,使用代理模式实现
#include
/* 代理模式 */
class RentHouse {
public:
virtual void rentHouse() = 0;
};
class Landlord : public RentHouse {
public:
void rentHouse() {
std::cout << "房子租出去了" << std::endl;
}
};
class Intermediary : public RentHouse {
public:
void rentHouse() {
std::cout << "发布招租启事" << std::endl;
std::cout << "带人看房" << std::endl;
_landload.rentHouse();
std::cout << "负责租后维修" << std::endl;
}
private:
Landlord _landload;
};
int main() {
Intermediary intermediary;
intermediary.rentHouse();
return 0;
}