对于初学者来说,Singleton 模式应该是最容易理解和应用的设计模式之一了。毫不掩饰地说,Singleton 模式也是滇狐最讨厌的设计模式之一。虽然不容否认,它是一个非常有用的设计模式,但在现实生活中,绝大部分情况下,该设计模式被滥用了,构建出一些模块间耦合度很高,可扩展性极差的程序。这里滇狐不打算详细讨论 Singleton 模式,只想谈谈在 ACE 里使用 Singleton 的一些注意事项。

1 不要让静态对象依赖 Singleton 对象

静态对象是万恶之源,最大的罪恶是初始化顺序无法预料,静态对象之间出现互相依赖时,非常容易发生种种莫名其妙的故障。ACE_Singleton 很好地解决了这个问题,它在一个对象第一次被使用的时候创建,这样当一个对象在构造期间依赖另一个对象的时候,通过这个机制就能保证被依赖的对象完整构造后,依赖者才继续往下执行。

然而,ACE_Singleton 引用的对象在构造的时候,需要依赖 Object_Manager 对象。如果我们选择不使用静态 Object_Manager 的话,Object_Manager 需要在我们显示调用 ACE::init() 之后才能正常使用;而就算我们使用了静态的 Object_Manager,它的构造时期也是不可预料的,因此,永远不要在静态对象里引用 ACE_Singleton

2 Singleton 在析构过程中不要相互引用

当我们调用 ACE::fini() 的时候,所有登记并被构造的 ACE_Singleton 引用的对象就被析构了。虽然 ACE_Singleton 完美地解决了互相依赖的对象之间的构造顺序的问题,但对于析构顺序,我们仍然是不可知的。如果我们在一个 Singleton 的析构过程中引用了另外一个 Singleton,而被引用的 Singleton 却又不幸地被提前析构了,那你的程序就等着 Crash 吧。

说到这里,滇狐忍不住又要感叹一句,Singleton 模式大大增加了模块之间的耦合度,降低了模块的灵活性,实在不是一个很好的设计模式。

3 多调用一次 ACE::init() 和 ACE::fini() 又何妨

虽然在有的平台下,ACE 会自动将 main 函数重定义,并主动替你把 ACE::init()ACE::fini() 调用好,但这一行为不能保证在所有平台下都正常运作。ACE::init()ACE::fini() 里面都有嵌套层次计数机制,因此只要它们能够保证成对出现,并且不出现交叉嵌套,多调用一遍并不会出现任何问题,我们不妨在 main 函数的开头和结尾分别再调用一次 ACE::init()ACE::fini()

标签:ACE 笔记 Singleton