设计类的六大原则
- 单一职责原则
- 就是说每一个类只做一件事情,职责划分清晰
- 两个不一样的功能就不能放在同一个类中,一个类中应当是一组相关性很高的函数、数据
- 开闭原则
- 对扩展开放,只添加新内容,对修改封闭,不修改旧内容
- 里氏替换原则
- 简单说就是父类能够出现完成的任务,子类也应当能够出现完成
- 在继承类的时候,需要重写父类中的所有方法,尤其需要注意父类中的protected方法,子类尽量不要暴露自己的public方法给外界调用
- 依赖倒置原则
- 就是说高层模块不应该依赖底层模块,而应该依赖他原本的抽象类
- 相同层模块之间的依赖应当通过接口来完成
- 迪米特法则
- 尽量减少对象之间的交互,来降低类之间的耦合度
- 接口隔离原则
- 不要对外部暴露没有实际意义的接口,并且接口应当精简、单一
四种设计模式及其实现
设计模式我们已经在之前有介绍过了,这里我们介绍并实现具体的四种设计模式
单例模式
一个类只能创建一个对象
在整个系统中只有一个实例,并且提供一个访问它的全局访问点,这个实例被所有程序模块共享
饿汉模式
程序启动的时候就会创建实例对象,因为单例对象已经确定了,因此比较适用于多线程环境中
多线程获取单例对象不需要加锁,可以有效避免资源竞争
class Singleton
{
public:
static Singleton &GetInstance()
{
return _eton;
}
int GetData()
{
return _data;
}
private:
Singleton() : _data(114) {};
~Singleton() {};
Singleton(const Singleton &) = delete;
static Singleton _eton;
int _data;
};
Singleton Singleton::_eton;
int main()
{
std::cout << Singleton::GetInstance().GetData() << std::endl;
return 0;
}
懒汉模式
在effective C++中有一种更加简单优雅的单例模式,静态变量能够在满足线程安全的前提下完成懒汉模式的设计
这是在C++11之后才支持的,定义的是静态局部对象
class Singleton
{
public:
static Singleton& GetInstance()
{
static Singleton _eton;
return _eton;
}
int GetData()
{
return _data;
}
private:
Singleton() : _data(114) {
};
~Singleton() {};
Singleton(const Singleton &) = delete;
int _data;
};
工厂模式
工厂模式是一种创建类型的设计模式,主要是用于创建对象
因此在工厂模式中,我们创建对象时不会对上层暴露创建的逻辑,而是用一个共同的结构来指向新创建的对象,以此来实现创建于使用的分离
简单说就是,我们我们可以通过创建一个工厂,再交给他一个类型,让这个工厂来创建对应类型的实例
简单工程模式
简单工厂模式指的是,由一个工厂对象,通过类型决定创建出来的产品类的实例
假设有一个工厂可以生产水果,就可以告诉工厂我们需要的水果品类,他就可以给我们生产了
#include <iostream>
#include <memory>
class Fruit
{
public:
virtual void name() = 0;
};
class Apple : public Fruit
{
public:
void name() override
{
std::cout << "苹果" << std::endl;
}
};
class Banana : public Fruit
{
public:
void name() override
{
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
{
return std::make_shared<Banana>();
}
}
};
int main()
{
std::shared_ptr<Fruit> fruit1 = FruitFactory::create("苹果");
std::shared_ptr<Fruit> fruit2 = FruitFactory::create("香蕉");
fruit1->name();
fruit2->name();
return 0;
}
这种方式的缺点就是,当产生了新的子类时,就需要重新对create继续开发了
工厂方法模式
一个产品对应一个工厂,新增一个产品的时候,就新增一个工厂
#include <iostream>
#include <memory>
class Fruit
{
public:
virtual void name() = 0;
};
class Apple : public Fruit
{
public:
void name() override
{
std::cout << "苹果" << std::endl;
}
};
class Banana : public Fruit
{
public:
void name() override
{
std::cout << "香蕉" << std::endl;
}
};
class FruitFactory
{
public:
virtual std::shared_ptr<Fruit> create() = 0;
};
class AppleFactory : public FruitFactory
{
std::shared_ptr<Fruit> create() override
{
return std::make_shared<Apple>();
}
};
class BananaFactory : public FruitFactory
{
std::shared_ptr<Fruit> create() override
{
return std::make_shared<Banana>();
}
};
int main()
{
std::shared_ptr<FruitFactory> ff1(new AppleFactory());
std::shared_ptr<Fruit> fruit1 = ff1->create();
std::shared_ptr<FruitFactory> ff2(new BananaFactory());
std::shared_ptr<Fruit> fruit2 = ff2->create();
fruit1->name();
fruit2->name();
return 0;
}
这里不好的地方就是,当类比较多时,需要创建的工厂就比较多,比较浪费
抽象工厂模式
简单理解就是,有一个超级工厂,可以生产工厂子类,再由工厂子类生产具体产品,如果你玩过钢铁雄心4的话,就能理解,民用工厂可以生产军用工厂,军用工厂可以生产具体装备
大工厂生产小工厂,小工厂生产产品
#include <iostream>
#include <memory>
class Fruit
{
public:
virtual void name() = 0;
};
class Apple : public Fruit
{
public:
void name() override
{
std::cout << "苹果" << std::endl;
}
};
class Banana : public Fruit
{
public:
void name() override
{
std::cout << "香蕉" << std::endl;
}
};
class Animal
{
public:
virtual void name() = 0;
};
class Cat : public Animal
{
public:
void name() override
{
std::cout << "小猫" << std::endl;
}
};
class Dog : public Animal
{
public:
void name() override
{
std::cout << "小狗" << std::endl;
}
};
class Factory
{
public:
virtual std::shared_ptr<Fruit> CreateFruit(const std::string &name) = 0;
virtual std::shared_ptr<Animal> CreateAnimal(const std::string &name) = 0;
};
class AnimalFactory : public Factory
{
public:
std::shared_ptr<Fruit> CreateFruit(const std::string &name) override
{
return nullptr;
}
std::shared_ptr<Animal> CreateAnimal(const std::string &name) override
{
if (name == "小猫")
{
return std::make_shared<Cat>();
}
else
{
return std::make_shared<Dog>();
}
}
};
class FruitFactory : public Factory
{
public:
std::shared_ptr<Fruit> CreateFruit(const std::string &name) override
{
if (name == "苹果")
{
return std::make_shared<Apple>();
}
else
{
return std::make_shared<Banana>();
}
}
std::shared_ptr<Animal> CreateAnimal(const std::string &name) override
{
return nullptr;
}
};
class FactoryProducer
{
public:
static std::shared_ptr<Factory> create(const std::string &name)
{
if (name == "动物工厂")
return std::make_shared<AnimalFactory>();
else
return std::make_shared<FruitFactory>();
}
};
int main()
{
// 创建动物工厂
std::shared_ptr<Factory> animalFactory = FactoryProducer::create("动物工厂");
std::shared_ptr<Animal> cat = animalFactory->CreateAnimal("小猫");
std::shared_ptr<Animal> dog = animalFactory->CreateAnimal("小狗");
cat->name(); // 输出“小猫”
dog->name(); // 输出“小狗”
// 创建水果工厂
std::shared_ptr<Factory> fruitFactory = FactoryProducer::create("水果工厂");
std::shared_ptr<Fruit> apple = fruitFactory->CreateFruit("苹果");
std::shared_ptr<Fruit> banana = fruitFactory->CreateFruit("香蕉");
apple->name(); // 输出“苹果”
banana->name(); // 输出“香蕉”
return 0;
}
建造者模式
建造者模式是一种创建型的设计模式,用多个简单的对象一步步构建成一个复杂的对象
能够将一个纷杂的对象的构建和他的表示分离,提供一种创建对象的最佳方式
主要用于解决对象构建过于复杂的问题
建造者模式主要基于四个核心类的实现
- 抽象产品类
- 具体产品类:一个具体的产品对象类
- 抽象Builder类:创建一个产品对象所需要的各个部件的抽象接口
- 具体产品的Builder类:实现抽象接口,构建各个部件
- 指挥者Director类:统一构建过程,提供给调用者使用,通过指挥者来获取产品
#include <iostream>
#include <string>
#include <memory>
// 抽象产品类:Phone
class Phone
{
public:
Phone() {}
void setBoard(const std::string &board)
{
_board = board;
}
void setDisplay(const std::string &display)
{
_display = display;
}
void show()
{
std::cout << "OS: " << _os << " | Board: " << _board << " | Display: " << _display << std::endl;
}
virtual void setOs() = 0;
protected:
std::string _board;
std::string _display;
std::string _os;
};
// 具体产品类:iPhone
class iPhone : public Phone
{
public:
void setOs() override
{
_os = "iOS 17";
}
};
// 抽象Builder类
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<Phone> build() = 0;
};
// 具体产品的Builder类:iPhoneBuilder
class iPhoneBuilder : public Builder
{
public:
iPhoneBuilder() : _phone(std::make_shared<iPhone>()) {}
void buildBoard(const std::string &board) override
{
_phone->setBoard(board);
}
void buildDisplay(const std::string &display) override
{
_phone->setDisplay(display);
}
void buildOs() override
{
_phone->setOs();
}
std::shared_ptr<Phone> build() override
{
return _phone;
}
private:
std::shared_ptr<Phone> _phone;
};
// Director类:用于控制构建流程
class Director
{
public:
Director(Builder *bd) : _builder(bd) {}
void construct(const std::string &board, const std::string &display)
{
_builder->buildBoard(board);
_builder->buildDisplay(display);
_builder->buildOs();
}
private:
Builder *_builder;
};
// 主函数
int main()
{
// 创建iPhone构建器
Builder *builder = new iPhoneBuilder();
// 通过Director构建iPhone
std::unique_ptr<Director> director(new Director(builder));
director->construct("华硕", "三星");
// 获取构建好的iPhone
std::shared_ptr<Phone> iphone = builder->build();
iphone->show();
delete builder; // 释放内存
return 0;
}
代理模式
有些对象不适宜被直接访问,就可以让代理对象在中间起一个中介的作用
这里代理也分为静态代理和动态代理,可以分别对应上面的饿汉模式和懒汉模式,是类似的
动态代理还涉及到许多其他知识,这里我们先不做介绍
#include <iostream>
#include <string>
class RentHouse
{
public:
virtual void rentHouse() = 0;
};
class Landlord : public RentHouse
{
public:
void rentHouse() override
{
std::cout << "租房子了" << std::endl;
}
};
class Intermediary : public RentHouse
{
public:
void rentHouse() override
{
std::cout << "发布公告" << std::endl;
std::cout << "看房" << std::endl;
_landlord.rentHouse();
std::cout << "售后" << std::endl;
}
private:
Landlord _landlord;
};
int main()
{
Intermediary intermediary;
intermediary.rentHouse();
return 0;
}
这里主要是给功能加强的意思
让原来的对象,能够完成他功能以外的模式