对于初学者来说,Singleton 模式应该是最容易理解和应用的设计模式之一了。毫不掩饰地说,Singleton 模式也是滇狐最讨厌的设计模式之一。虽然不容否认,它是一个非常有用的设计模式,但在现实生活中,绝大部分情况下,该设计模式被滥用了,构建出一些模块间耦合度很高,可扩展性极差的程序。这里滇狐不打算详细讨论 Singleton 模式,只想谈谈在 ACE 里使用 Singleton 的一些注意事项。
静态对象是万恶之源,最大的罪恶是初始化顺序无法预料,静态对象之间出现互相依赖时,非常容易发生种种莫名其妙的故障。ACE_Singleton
很好地解决了这个问题,它在一个对象第一次被使用的时候创建,这样当一个对象在构造期间依赖另一个对象的时候,通过这个机制就能保证被依赖的对象完整构造后,依赖者才继续往下执行。
然而,ACE_Singleton
引用的对象在构造的时候,需要依赖
Object_Manager
对象。如果我们选择不使用静态
Object_Manager
的话,Object_Manager
需要在我们显示调用 ACE::init()
之后才能正常使用;而就算我们使用了静态的
Object_Manager
,它的构造时期也是不可预料的,因此,永远不要在静态对象里引用
ACE_Singleton
。
当我们调用 ACE::fini()
的时候,所有登记并被构造的 ACE_Singleton
引用的对象就被析构了。虽然 ACE_Singleton
完美地解决了互相依赖的对象之间的构造顺序的问题,但对于析构顺序,我们仍然是不可知的。如果我们在一个
Singleton 的析构过程中引用了另外一个
Singleton,而被引用的 Singleton
却又不幸地被提前析构了,那你的程序就等着 Crash 吧。
说到这里,滇狐忍不住又要感叹一句,Singleton 模式大大增加了模块之间的耦合度,降低了模块的灵活性,实在不是一个很好的设计模式。
虽然在有的平台下,ACE 会自动将 main
函数重定义,并主动替你把 ACE::init()
和
ACE::fini()
调用好,但这一行为不能保证在所有平台下都正常运作。ACE::init()
和 ACE::fini()
里面都有嵌套层次计数机制,因此只要它们能够保证成对出现,并且不出现交叉嵌套,多调用一遍并不会出现任何问题,我们不妨在
main
函数的开头和结尾分别再调用一次
ACE::init()
和 ACE::fini()
。