从 Command 模式看 C++ 之缺陷
设计有 UI 的软件,Command 模式可以说是可能用到的设计模式中最常用的一种了。它隐藏了关于命令发起者的相关对象以及命令处理过程的细节。也就是建立一个第三方的对象,用来解耦发送者和接收者的联系。
Command 模式最常用的用途就是给软件做 undo/redo 的功能。只用维护一个链表放置命令序列,就可以方便的记住发出的命令。每个 Command 对象实现一个乒乓开关(或者实现一对 undo/redo ),在对象内部保留住相关对象,自己执行 undo 或 redo 操作即可。
在动态语言里,一个 Command 对象,往往用一个 closure 来实现。closure 天然的具有封装参数和过程的能力。而 C++ 中,我们必须实现一个单独的类。这不仅使代码冗长,而且因为这个类往往和命令操作的对象栖息相关。不想写过多的供外部使用的方法的话,最直接的方案是 friend 一下所有的相关 Command 类。可无论怎样,一大堆代码或是难看的宏是避免不了了。
由于 C++ 没有 gc 的能力,所以在命令执行中构造和删除对象要十分小心。因为带 undo 功能的软件,即使你删除一系列对象,也不能真正从内存中释放掉。转而应该保留在 Command 对象内部。
典型的需求是向一个 TreeView 中删除节点的操作,只能是从 TreeView 上摘除(unlink)而不是删除,否则无法 undo 。当然还有一种实现方法是:从命令序列的头开始从头执行所有的指令,效率极低且不总是有效。只要命令序列中有涉及外部数据的读取,由于我们无法保证外存数据的不变,所以就不能保证 undo 的有效性。
智能指针是一种折中的解决方法。而一般在 C++ 中更高效的使用 Command 模式的方案是:任何的对象的诞生和消亡都由 Command 对象来负责,而 Document 中的对象之间只用指针记录其关系。这在设计角度,实在是没有支持 gc 和 closure 的动态语言来的简洁。
Comments
Posted by: abc | (11) January 27, 2007 12:24 PM
Posted by: gql_w | (10) January 24, 2007 09:23 AM
Posted by: gamecqit | (9) January 19, 2007 07:21 AM
Posted by: Atry | (8) January 18, 2007 06:27 PM
Posted by: Cloud | (7) January 18, 2007 05:48 PM
Posted by: gql_w | (6) January 18, 2007 05:31 PM
Posted by: Anonymous | (5) January 18, 2007 03:46 PM
Posted by: Cloud | (4) January 18, 2007 01:29 PM
Posted by: 猛禽 | (3) January 18, 2007 12:51 PM
Posted by: Atry | (2) January 18, 2007 09:45 AM
Posted by: Atry | (1) January 17, 2007 10:17 PM