C++不常用设计模式梳理

僤鯓⒐⒋嵵緔 提交于 2020-03-12 04:58:22

C++常用设计模式的相关博文到这里就整理的差不多了,我们实际工作中常用的设计模式就是我前面整理的那些。GoF所提到的23种设计模式还有一些我没有整理到,包括:享元模式、建造者模式、外观模式、中介者模式、备忘录模式、迭代器模式、职责链模式、访问者模式、命令模式、解释器模式。这些模式因为各种各样的原因在我们的工作中很少会遇到,所以这篇博文就先对这些剩下的模式做一个简单的介绍。

1,享元模式

定义:运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。

UML图:

我的理解:

第一次看到享元模式的定义我就很蒙圈,首先是它的英文名称叫flyweight,翻译成轻量级我觉得更合适一点。其次是啥叫细粒度?其实不就是一些轻量级(更直接的一点的说法就是对象sizeof()得出来的结果很小)的对象嘛。那么多少这些对象可以称为大量呢?假设我们某个类的对象a使用sizeof()得出来的结果50个字节。那20*1024个a对象的大小差不多就是1M,除了一些网络游戏应用我想不出哪些地方会用到这么多的对象,反正我工作中是遇不到这么多的对象创建。享元模式给出的解决方法其实就是UML图中红色的部分。这个方法非常的经典,很多地方都可以使用这个方法,比如:线程池、内存池等等。因此掌握这个方法非常重要!

其核心思想就是:维护一个对象池,当系统需要某个对象时,我们先去池子里看看有没有这个对象,如果有就直接返回,如果没有就先创建一个新的对象,放入池中,然后再返回这个对象。

//我们需要创建的类,这个类可以是个真实的类也可以是虚基类,这里假设是真实的类
class Shape 
{
private:
    string key;
public:
    Shape(const string& key) {}
};

//创建这个类的工厂
class ShapeFactory
{
   private:
        static map<string,Shape*> pool;//对象池,这里就用map来存
   public:
        //这里可以写成静态方法使用静态对象,也可以两个都不是静态的
        static Shape * GetShapee(const string &key)
        {
            map<string,Shape*>::iterator it = pool.find(key);
            if(it != pool.end())
            {
                return pool[key];
            }
            else
            {
                Shape* pShape = new Shape(key);
                pool[key]= pShape;
                return pShape;
            }
        }
       
       static Clear() 
       {
          //这里new的对象别忘记要delete
       }
};

 

2,建造者模式

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程(稳定的)可以创建不同的表示(变化的)

UML图:

我的理解:

建造者模式是一种创建型的模式,它应用的场景是复杂对象的创建,实际工作中我们很少会遇到所谓“复杂”的对象。所以一般的工厂方法、抽象工厂等设计模式就够用了。只看建造者模式的定义,可以看到它其实和模板方法模式的表述非常的相似,不同的地方是建造者模式处理的对象更复杂所以它做了更细化的处理。这也是设计模式思想的一种体现,如果一类的操作很复杂,那就把它拆分成几个类

 

3,外观模式(也叫门面模式)

定义:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口(稳定的),这个接口使得这一子系统(变化的)更加容易使用。

UML图:

我的理解:

从它的定义可以看出,外观模式中的Facade就是那个应对变化和稳定的分界线,也就是所谓的接口。和其他的设计模式不同,外观模式更像是站在系统的角度上对整个软件进行设计的模式,而前面说的很多模式只是处理一两个类之间的关系。这样理解的话可以认为外观模式是我们软件设计的准则,即不管内部的实现如何变化,但要保持对外接口的稳定

 

4,中介者模式

定义:用一个中介对象来封装(封装的就是变化)一系列的对象交互。中介者使各对象不需要显式地相互引用(所谓显示地也就是编译时就要确定了,这里中介者的出现使其变为运行时确定),从而使其耦合松散,而且可以独立地改变它们之间的交互。

UML图:

我的理解:

中介者模式解决的是一个软件系统内部各个对象之间相互依赖的关系,也就是说把系统内部各个对象之间的相互依赖变成各个对象和这个中介者的依赖关系。那么这个中介者Mediator可以看作是一个软件系统内部各个对象之间的接口(这里再想想外观模式,Facade是整个软件系统对外的接口),哈哈哈!仔细想想这是不是很好的体现了设计模式的精髓,即隔离变化,统一接口。对照着上面的UML图再来看看,如果要系统内部的各个对象(Colleague类的所有子类)和中介者类(Mediator)产生依赖,那么很自然的Mediator类就拥有Colleague类的指针(设计模式中常见的手法:组合),同时Colleague类可能有很多的子类,因此Mediator类只拥有一个指针显然是不够的,它得存一个Colleague类指针的数组(链表、队列等等都可以)。看到这是不是就想起了观察者模式!!!是不是很像!!!当然这里可能一些处理的细节会有所偏差,但是思想都有共同之处。

 

5,备忘录模式

定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。

UML图:

我的理解:

这么说吧,我感觉工作中基本不会遇到需要使用备忘录模式的情况。。。要保存状态用序列化不好吗?而且如果Originator对象非常复杂(比如含有指针),Memento还有实现对其的深拷贝,这就很容易出错了。

 

6,迭代器模式

定义:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示

这个就直接不说了,STL中的迭代器实现的不好吗?

 

7,职责链模式

定义:为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求(就是把处理函数设为虚函数呗)。将这些对象连成一条链(每个子类都有一个后来者的指针呗,这里直接用父类的指针),并沿着这条链传递该请求,直到有一个对象处理它。

UML图:

我的理解:

对照着UML来看就很好理解了,总来说就以下几点:

(1)Handler是所有处理对象的基类,所以Handler必须有一个处理请求的虚函数HandleRequest()。还得有一个指向自己的指针。这个指针就是让子类设置继任者用的,这里设置函数为SetSuccessor(Handler *pSuccessor)。

(2)有了这个指针就好办了,每个子类都必须设定另外一个子类作为它的继任者(最后一个对象除外)。即调用父类的SetSuccessor()函数。

(3)最后一步,每个子类都实现自己的HandleRequest()。这个时候请求来了,如果自己能处理就自己处理,如果自己处理不了怎么办?那就调用pSuccessor->HandleRequest()把问题扔给后面一个继任者呗。

 

8,访问者模式

定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

UML图:

我的理解:

对照上面的UML图来看,它不但要求Visitor类和Element类是稳定的(这个很好理解,这俩是基类),而且还要求ConcreteElementA和ConcreteElementB是稳定的,也就是说后面需要再添加一个ConcreteElementC的话,就需要修改Visitor类了,这就和我们设计模式的理念冲突了。所以说访问者模式可以适用的情况非常的苛刻,我们在实际工作中很少会遇到这种情况。这里大家了解即可。

 

9,命令模式

定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。

这个就直接不说了,因为有更好的函数对象(或者叫仿函数)来解决这个问题。

 

10,解释器模式

定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

这个也不说了,反正我也不会去写一个解释器的。。。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!