单件模式(singleton pattern)

看到有的书上的单件模式是这样的:
singleton.h:

class Singleton {
public :
  static Singleton *GetInstance();
private :
   Singleton();
  static Singleton *s_singleton;
};



singleton.cpp :

Sington::Singleton() {

}

Singleton *Singleton::s_singleton = nullptr;

Singleton *Singleton::GetInstance() {
  if (nullptr == s_singleton) {
    s_singleton = new Singleton;
  }

  return s_singleton;
}


这样在single.cpp里面的定义的static成员变量是属于non-local成员变量(除了在函数体内定义的static对象称为local  static 对象,其他的static对象都称为non-local  static 对象,包括全局对象,静态全局变量,定义于namespace 中的对象,类静态成员)。但是这样的定义方法是不好的,因为当类逐渐多起来,类之间的以来关关系越来越复杂的时候,我们就可能会遇到初始化次序问题。为了避免这个问题,我们就应该把non-local static对象转换成为local  static对象。
举个例子(为了简单起见,违反了很对规范,莫怪~):
a.h:
<pre name="code" class="html">class A{
public :
  int _i;
};



extern A a;    //  允许其他文件使用这个变量

 
b.h :
#include "a.h"

class B{
public :
  B(A a){ printf("%d", a._i);}
};


这样的话,B可能会用用到尚未初始化的A类型的外部变量,也就是non-local static变量。而C++对编译于不同的编译单元内的non-local static对象的初始化次序也没有明确定义。

要解决这个问题就压迫把non-local  static对象编程local  static对象。
我们都知道,C++语法中有这样的说明,函数内的静态变量在函数调用期间第一次遇上静态变量的定义的时候才会被初始化。所以,我们可以通过返回一个静态变量的引用来替换直接访问non-local对象(静态变量的生存期是从定义的地方开始,一直到程序结束,所以,不用担心会访问的静态对象被销毁)。
修改第一个例子:
sington.h
class Singleton {
public :
  static Singleton &GetInstance();  //  返回值为引用类型
private: 
   Singleton();
    //  没有了静态成员变量
};


singleton.cpp
Sington::Singleton() {

}

Singleton &Singleton::GetInstance() {
  static Singleton s_singleton;
  return s_singleton;
}



这样就可以避免以上提到的问题啦。通过GetInstance()函数,我们就能获得唯一的一个Singleton的实例啦。


更进一步的,如果想要生成不止一个,但是又不是无限个对象的话,也可以通过单件模式实现。只要在生成对象的接口函数中加上一个静态变量和一个判断就可以了。

例如,我们现在有一个名为Boy的类。我们想只能生成10个Boy,避免男孩太多(生太多会被罚款的,虽然10个也会)。如果你觉得太多,也可以改成两个。
我们提供一个接口函数--getBoy,这个函数返回一个指向Boy的指针,其实更好的做法是用一个智能指针作为返回值,不过在这里不是重点。
boy.h
#ifndef _BOY_H
#define _BOY_H


class Boy {
public :
  Boy *getBoy();
private :
  enum {MAXOFBOYCOUNT = 10};
  Boy();
  ~Boy();
};

#endif // _BOU_H



boy.cpp
#include "boy.h"

Boy::Boy() {

}

Boy::~Boy() {

}

Boy *Boy::getBoy() {
  static size_t count = 0;
  if (count <= MAXOFBOYCOUNT) {
    ++count;
    return new Boy();
  }

  return nullptr;
}

如果我们想改变要生成的男孩的个数,只要改变类中的匿名枚举类的值就好啦。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值