详解设计模式系列

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

欢迎关注头条号

                            

    

     

以上是关于详解设计模式系列的主要内容,如果未能解决你的问题,请参考以下文章

Java集合框架源码详解系列——迭代器设计模式详解

Java集合框架源码详解系列——迭代器设计模式详解

详解设计模式系列

搜索引擎系列八:solr-部署详解(solr两种部署模式介绍独立服务器模式详解SolrCloud分布式集群模式详解)

Java设计模式系列适配器模式及适用场景详解

单例设计模式详解+源代码+JDK源码应用——Java设计模式系列学习笔记