[学习笔记]设计模式之Singleton(二)
让我们看看改变后的WorldMgr:
复制代码
1 class WorldMgr {
2 public:
3 static void Register(const char* name, WorldMgr*);
4 static WorldMgr* getInstance();
5
6 //Existing interface goes here
7 protected:
8 WorldMgr();
9 static WorldMgr* Lookup(const char* name);
10 private:
11 static WorldMgr* _instance;
12 static List* _registry;
13 }
复制代码
注意我们高亮了新添加的一些语句。Register以给定的泰坦名字注册WorldMgr实例。为保证注册表简单,我们将让它存储一列NamePair对象。每个NamePair将一个名字映射到一个单例。Lookup操作根据给定单件的名字进行查找。我们假定一个环境变量指定了所需要的单件的名字:
复制代码
1 WorldMgr* WorldMgr::_instance = 0;
2
3 WorldMgr* WorldMgr::getInstance() {
4 if (_instance == 0) {
5 const char* name = getenv("TITAN");
6 // Lookup returns 0 if there's no such WorldMgr;
7 _instance = Lookup(name);
8 }
9 return _instance;
10 }
复制代码
那么又在何处让Titan注册自己呢?一种可能是在构造器中,让我们以Mnemosyne为例:
1 Mnemosyne::Mnemosyne() {
2 // ...
3 WorldMgr::Register("Mnemosyne", this);
4 }
当然,除非实例化类否则这个构造器不会被调用。我们可以在包含Mnemosyne实现的文件中定义:
static Mnemosyne theWorldMgr;
如此一来WorldMgr类不再负责创建单例。它的主要职责是使得供选择的单例对象在系统中可以被访问。但是这个静态对象方法还是有一个潜在的缺点:也就是所有可能的WorldMgr子类的实例都必须被创建,否则它们不会被注册。 不过对于时の魔导士而言,这点就不重要啦,因为他确实需要创建所有的Titan们,并让他们开始担负起维护世界运作的重任。
特点总结
跟随魔导士的步伐,我们见证了一个伟大议会WorldMgr的诞生,同时它也是Singleton模式的很好实例。我们可以看到,Singleton有很多优点:
对唯一实例的受控访问。因为Singleton类封装它的唯一实例,所以它可以严格地控制客户怎样以及何时访问它。
缩小命名空间。Singleton模式是对全局变量的一种改进。它避免了那些存储唯一实例的全局变量污染名空间。
允许对操作和表示的精化。Singleton类可以有子类,而且用这个扩展类的实例来配置一个应用是很容易的。我们可以用所需要的类的实例在运行时刻配置应用。
允许可变数目的实例。这个模式使得我们易于改变想法,并允许Singleton类的多个实例。此外,我们可以用相同的方法来控制应用所使用的实例的数目。只有允许访问Singleton实例的操作需要改变。