![](https://img-blog.csdnimg.cn/img_convert/98fdaa578f945b417ffc71adce96acc4.png)
设计模式简介:https://www.runoob.com/design-pattern/design-pattern-intro.html
单例模式和工厂模式都是创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
设计模式的六大原则
开闭原则:在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
迪米特法则:最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
合成复用原则:继承和组合,优先使用组合。
接口隔离原则:客户端只依赖于它所需要的接口;它需要什么接口就提供什么接口,把不需要的接口剔除掉。类间的依赖关系应建立在最小的接口上。
依赖倒转原则:针对接口编程,依赖于抽象而不依赖于具体。
里氏代换原则(LSP):任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
简单工厂模式
利用工厂类去创建需要的对象
优点:
客户端和实现类解耦
对于一些创建比较复杂的类,客户端不用考虑
缺点:
增加新的功能需要修改源代码(与开闭原则不符)
在实现类过多的时候,工厂类的职责过重
适用场景:
需要创建的类不多的时候。
工厂方法模式
由于简单工厂模式不符合开闭原则,那么工厂方法模式通过将工厂抽象出去,以达到与开闭原则相符的效果
![](https://img-blog.csdnimg.cn/img_convert/6ccff377653e05cd5f9cef8808c483d3.png)
优点相对简单工厂模式来说,符合了开闭原则,但这也导致增加一个类就需要增加一个工厂,增加了维护成本。
简单工厂模式 + “开闭原则” = 工厂方法模式
![](https://img-blog.csdnimg.cn/img_convert/f6f380de81c13dfcc6b99cd86ad31caf.png)
适用场景:
客户端不知道具体需要哪种东西的时候,如上图所示。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
注意:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
抽象工厂模式
抽象工厂针对的是产品族,而不是产品等级结构。
产品族:属于同一产地或厂商功能不同
产品等级结构:功能相同,产地或厂商不同
抽象工厂模式,针对的是产品族而不是产品等级结构,因为如果要扩充产品族的话,工厂需要增加代码来实现,从而不符合开闭原则;但是扩充产品等级结构则不需要修改工厂代码,只需要新增一个派生类即可。
![](https://img-blog.csdnimg.cn/img_convert/95eed390d105e0c325ffa06963a159cc.png)
如上图所示,需要相应的东西直接使用对应的工厂进行生产即可,在定义水果或工厂时,也不需要指定具体的工厂或水果。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
![](https://img-blog.csdnimg.cn/img_convert/d48bbe8581df50fa55cdae8340cfee68.jpeg)
单例模式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
实现单例模式的步骤
//懒汉模式
class SingletonLazy
{
private:
SingletonLazy(){}
private:
static SingletonLazy* pSingleton;
public:
static SingletonLazy* getInstance(){
if (pSingleton == nullptr) {
pSingleton = new SingletonLazy;
}
return pSingleton;
}
};
SingletonLazy* SingletonLazy::pSingleton = nullptr;
//饿汉模式
class SingletonHungary
{
private:
SingletonHungary(){}
private:
static SingletonHungary* pSingleton;
public:
static SingletonHungary* getInstance(){
return pSingleton;
}
};
SingletonHungary* SingletonLazy::pSingleton = new SingletonHungary;//初始化创建
单例模式下的对象一般不需要释放
饿汉式对多线程是安全的,因为其在初始化就创建了
懒汉式对多线程是不安全的,因为可能存在两个线程同时调用实例化的情况存在。