k_eckelhttp://www.mscenter.edu.cn/blog/k_eckel

1 问题

    面向对象系统开发和设计过程中,我们会希望某个类的对象都表现得一致,像只有一个对象存在一样。Singleton模式很好地保证了获取单一对象,从而获得了单一对象表现的效果,但是Singleton模式却要付出以下几个代价(Robert . C Martin):

1)  没有好的方法去Destroy(摧毁)Singleton对象、或解除其职责。即使将Singleton模式中的_instance显示地设置为null,还是不能解决问题:因为系统其他模块可能依旧持有对这个Singleton对象的引用,此模块中的instance方法的调用(获取Singleton对象,详细参见Singleton模式实现)又会创建一个新的实例。在C++中,由于可以

2)  效率问题:每次调用instance方法都要执行if语句,实际除了第一次创建实例有意义,其他的都是没有必要的;

3)  不能继承:Singleton派生出来的类并不是Singleton,需要添加静态函数和变量才能成为Singleton

4)  不透明性:Singleton的使用者都知道自己在使用一个Singleton实例(调用instance方法,能不知道吗?),对于用户来说不透明(注意计算机中的透明和一般意义上透明的含义不同!)。

其中最为关键的问题就是1)中的:谁来为Singleton买单(负责善后)。这个问题是一

个很难解决的问题。实际上如果我们仅仅只需要系统的某类对象表现的像只有一个对象,我们完全可以绕过这个屏障,采用下面介绍的Monostate模式获得同样的效果。

2 模式选择

    实际上还有可以其他的模式来获得Singleton类似的效果,这就是Monostate模式。我们可以从字面意义上获得对Monostate模式的一个感性的认识:

1)  Monostate = Mono + state

2)  Mono = Single(单一);

3)  State表示状态。

因此Monostate模式就是“(保持)单一状态”的模式。Singleton模式保证的是唯一

实例,当然也就保证了单一的状态了。Monostate模式的采用的实现机理和Singleton模式不同,但是是非常直观和简洁:既然要保证不同的实例表现的像一个对象,很显然,让这些变量(实例)共享相同的数据域即可,也就是说把类所有的数据域定义为静态变量(Static)接口。

    于是Monostate模式通过这种曲线救国的方式获得了表现上的多个对象活动得像一个对象一样,但是Singleton模式却是真的只有一个对象。

 

3 模式实现

    Monostate模式很简单,关键是将类的数据域全部声明为static即可:

#include <iostream>

using namespace std;

 

class Monostate

{

public:

       Monostate();

 

       void SetData(int data);

 

       int GetData();

 

       ~Monostate();

 

private:

       static int _data;

};

 

int Monostate::_data = 0;

 

Monostate::Monostate()

{

}

 

Monostate::~Monostate()

{

}

 

void Monostate::SetData(int data)

{

       _data = data;

}

 

int Monostate::GetData()

{

       return _data;

}

 

int main(int argc,char* argv[])

{

       Monostate* m1 = new Monostate();

       Monostate* m2 = new Monostate();

 

       cout<<"m1->_data = "<<m1->GetData()<<" == "

              <<"m1->_data = "<<m1->GetData()<<endl;

 

       m1->SetData(5);

 

       cout<<"m1->_data = "<<m1->GetData()<<" == "

              <<"m1->_data = "<<m1->GetData()<<endl;

 

    delete m1;

       delete m2;

 

       Monostate* m3 = new Monostate();

 

       cout<<"m3->_data = "<<m3->GetData()<<endl;

 

       return 0;

}

     在示例代码中可以看到,Monostate的两个实例m1m2,其外观表现完全一致。并且无论创建多少的Monostate对象,都会表现的像一个对象。并且就算你把当前所有的Monostate对象销毁或者解除职责,Monostate保存的数据也不会丢失。示例运行结果可以说明这一点:

      

m1->_data = 0 == m1->_data = 0

m1->_data = 5 == m1->_data = 5

m3->_data = 5

 

3 模式讨论

    Monostate模式和Singleton模式都能够获得“系统某个类别对象都表现的像只有一个对象”,Singleton模式重在通过保证系统中只有唯一实例,而Monostate模式重在保证唯一状态(当然Singleton模式更多的是用来保证唯一实例)。Monostate模式更多关注的是行为,即行为上的一致;Singleton模式更多关注的是结构,强制结构上的单一,仅产生唯一实例。

    Monostate模式比Singleton模式有着一些优势和特点:

1)  没有到底谁负责销毁的问题,你可以在你不想Monostate对象的时候将它销毁,因为它和任何其他的对象没有任何区别;

2)  透明性:用户并不需要也不关心是否使用了Monostate模式对象,原因还是Monostate对象和其他对象是一样的;

当然Monostate模式也有自己的限制和代价:

1)  内存占用:即使不使用Monostate对象,也要占用内存,因为有static成员变量(当然在Singleton的实现中如果保存在Singleton中保存一个Singleton静态对象,这个问题也是存在的);

2)  效率:因为Monostate模式中创建的是真正的对象,因此需要创建和销毁开销。

Posted on 2005-07-08 21:28  k_eckel's mindview  阅读(1208)  评论(1编辑  收藏  举报