2005年2月19日星期六

《ASD》设计模式:Singleton和Monostate

Singleton几乎是最简单的模式了,我甚至认为,在一般情况下,他不是模式,而只是一个idiom。
但是,他确实功能强大,而且非常实用,又很常用。(所谓居家旅行杀人灭口必备之工具)
关于Singleton没有多少可以说的了。一句话的解释是,利用静态指针或引用来维护一个系统中某个类的唯一实例;利用静态方法来获取这个唯一实例;是全局变量的优雅替代。
《ASD》一书中,也没有对Singleton讲出多少新意来。

对于利用静态变量做出来的技巧,都可以考虑用模版类来自动化。Singleton就是一个非常好的例子。这个问题我会在以后关于《Modern C++ Design》的记录中来讨论。

Monostate模式却有些新意思,甚至有点搞笑的味道。
如果,以各类可以有多个实例,但是没个实例中的成员都一样,那又如何?那就是说,不论这个类有多少个实例,其实每个实例使用的内存都是同一段静态内存。每个实例都是同一个实例的不同化身。这也算是全局变量的优雅替代。
但是Monostate的实现要比Singleton来的麻烦,必须把每个变量都声明成静态变量。
那么这样做有什么好处呢?
《ASD》如是说:
透明性:使用者使用Monostate对象和使用普通对象没有什么区别。
可派生型:每个Monostate对象的派生类依然是Monostate。(我的理解是,这个特性的前提条件是,派生类不能添加非静态成员变量)
多态性:派生类中可以override父类的方法。
我认为透明性其实没有什么意思,而且有点危险。如果调用者不知道自己调用的是Monostate,而把它当作普通类来使用,那么Monostate的表现可够她大吃一惊的。
可是后两个特性却很有意思,非常有意思。
仔细考量Monostate的内存布局。所有的monostate派生类都共享同一块内存,但是派生类的函数内容却有所不同。也就是说,如果把所有的monostate类对象看作是同一个对象(从内存的角度来看,他们也的确就是一个对象),那么这个对象的函数会根据调用点的不同,而由不同的表现。
即,这个对象的功能可以响应当前的状态。这是一个非常优雅的状态机
这就是Monostate模式的真面目,全局唯一的状态机。
如何实现Monostate模式的状态机,关键一点就是,在父类中,包含一个到子类的指针。父类的所有函数,都委托给该指针指向的子类对象。子类的函数,在状态切换时,把这个指针改变为指向下一个状态子类的实例。

没有评论: