详解设计模式系列

1.观察者模式

观察者模式作用:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式结构图:

在这里插入图片描述
Observer模式定义的是一对多的关系,这里一就是图中的Subject 类,而多则是Obesrver 类,当Subject 类的状态发生变化时,通知与对应的Observer去更新相应状态,并支持添加和删除Observer 对象的操作。

Obesrver 模式的实现步骤如下:

1.subject 类都是采用链表等容器来存放 Observer 对象

2.取出Observer 对象的公共属性形成Observer基类

3.subject 类保存Observer 对象的指针,这样就使subject 类和具体的Observer 对象实现了解耦。也就是Subject 不需要去关心到底是哪个Observer 对放进了自己的容器中。

Obesrver 模式的实际应用场景:

(1)推模型,把具体的内容都广播出去。如果一次发送所有的内容,比较耗流量。

(2)拉模型,比如把subject对象地址给到各个观察者。把摘要等地址信息,发送就好了,由观察者自己去获取服务器的数据,这种粒度比较小,也是有主动推送的,比较节省流量。一般像今日头条,这种都是拉模型。

(3) 实际上也有推拉结合。

典型的实际场景,微信公众号推送,如下图:
在这里插入图片描述
推拉模型的Observer接口定义:
在这里插入图片描述
Subject类的接口定义:
在这里插入图片描述
推拉模型的通知方式:
在这里插入图片描述
实际观察者对象的实现:
在这里插入图片描述
Subject类的实际实现:
在这里插入图片描述
测试函数
在这里插入图片描述
2.工厂模式

Factory作用:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method(具体的工厂方法),使一个类的实例化延迟到其子类。

UML结构图如下:
在这里插入图片描述
抽象基类:

(1)Product:创建出来的对象的抽象基类。

(2)Creator:创建对象的工厂方法的抽象基类。

实现步骤:

(1) Creator::FactoryMethod是纯虚函数,由子类实现,创建出对应的Product。一个Factory和一个Product是一一对应的关系。

(2)创造两个基类,一个Product为创建对象的抽象基类,一个Factory是创建工厂的抽象基类。在互相协作的时候都是由相应的 Factory 派生类来生成Product的派生类,也就是说如果要新增一种Product,那就需要新增一个Factory。

实际应用场景:

如数据导出,导出为Excel,文本,XML等。支付接口,可能对应不同的支付网关:支付宝、财付通、网银等。

Product抽象基类定义:
在这里插入图片描述
Product的子类实现:

保存为文件
在这里插入图片描述
保存为数据库
在这里插入图片描述
保存为XML
在这里插入图片描述
保存为Protobuffer的形式
在这里插入图片描述
具体Factory定义。
在这里插入图片描述
这个factoryMethod实际上可以由子类去实现,这里就放在工厂里面一起实现:
在这里插入图片描述
子类对象实现工厂,具体各类方法放在子类去实现。主要是重写factoryMethod。
在这里插入图片描述
测试方法:

工厂对象对外暴露接口,接收参数,实现产品的输出。
在这里插入图片描述
3.单例模式

单例模式作用:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

UML结构图:
在这里插入图片描述
单例模式实现步骤:

(1)仅有一个实例,提供一个类的静态成员变量,并且是唯一。

(2)提供一个访问它的全局访问点,需要提供一个访问这个静态成员变量的静态成员函数,对类的所有对象而言也是唯一。在 C++中,可以直接使用类域进行访问而不必初始化一个类的对象。

实际应用场景:

配置文件,基本都是单例设计模式。

单例模式分为懒汉式和饿汉式。懒汉式就是延迟加载,节省空间,比如延迟加载文件。饿汉式就是应用启动,就加载,比如网络模块响应的加载。

需要设计一个垃圾回收器GarbageCollector,及时回收单例对象,防止内存泄漏。下面是一个最简单的单例模式,线程不安全。
在这里插入图片描述
测试结果:

测试发现地址不一致,并不是唯一对象,导致线程不安全,而且垃圾回收器只能回收一个,会发生内存泄漏的事件。
在这里插入图片描述
懒汉式,单例线程安全模式。下面这个结构,加锁的粒度大,对于高并发时,效率低。
在这里插入图片描述
测试结果,发现生成了唯一的对象,线程安全。
在这里插入图片描述
为了解决上面的加锁粒度大,导致的效率下降,需要在加锁前,判断对象是否为空,如果为空,再加锁。那下面这种结构模式,为什么还要二次判断对象是否为空呢?因为对象的new不是原子操作,一般的步骤是,1.分配内存,2.调用构造,3.赋值操作,到第三步的时候,才会生成对象。如果这个顺序被打乱了,因为CPU和编译器高并发下可能会进行乱序重排操作,因而创建对象new CSingleton的第2步可能会晚于第3步进行指令调用,因而导致出现未定义的的行为,就会出现异常。这个现象是非常隐蔽,在不同的编译器和CPU下都有可能发生。\

在这里插入图片描述
使用局部静态对象,表面上看起来好像是饿汉式,实际它会在main函数之后,才生成,本质还是懒汉式。注意,局部静态对象,c++11不是线程安全。并且不能使用隐式的构造函数,会影响局部静态变量。由于隐式的构造函数不会加锁,而导致线程不安全。

严格的使用了原子操作,线程安全,并且高效。

在这里插入图片描述
不能使用自动默认的构造函数
在这里插入图片描述
测试结果:
在这里插入图片描述
正真的饿汗式,全局静态对象,并且初始化。如下图:
在这里插入图片描述

正真的饿汗式,在main函数前面,这个对象就已经生成了。
在这里插入图片描述
4.总结

这里主要写了三种比较常见的设计模式,后面会继续更新,欢迎分享,收藏,点赞,关注。下面是上面代码的github地址,欢迎给星。

https://github.com/ananqin/Observer_Factory_Singleleton
微信公众号
头条号

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值