详解设计模式系列
Posted 记录世界 from antonio
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解设计模式系列相关的知识,希望对你有一定的参考价值。
1.观察者模式
观察者模式作用:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式结构图:
Observer模式定义的是一对多的关系,这里一就是图中的Subject 类,而多则是Obesrver 类,当Subject 类的状态发生变化时,通知与对应的Observer去更新相应状态,并支持添加和
删除Observer 对象的操作。
Obesrver 模式的实现步骤如下:
1.subject 类都是采用链表等容器来存放 Observer 对象
2.取出Observer 对象的公共属性形成Observer基类
3.subject 类保存Observer 对象的指针,这样就使subject 类和具体的Observer 对象实现了解耦。也就是Subject 不需要去关心到底是哪个Observer 对放进了自己的容器中。
Obesrver 模式的实际应用场景:
(1)推模型,把具体的内容都广播出去。如果一次发送所有的内容,比较耗流量。
(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.总结
https://github.com/ananqin/Observer_Factory_Singleleton
欢迎关注头条号
以上是关于详解设计模式系列的主要内容,如果未能解决你的问题,请参考以下文章