【前言】
其实一个好的GUI系统,架构设计很重要。其实一切的核心恐怕没有比控件基类的设计更重要的了。在我自己的这篇文章(http://hi.baidu.com/microgrape/blog/item/50ed5b123691ae165baf5379.html)中说到GUI的最重要的几个组成部分,控件基类全部都涉及。一个基类如果要担负这么多任务,但是如果设计不好,那势必造成功能紊乱。。。
【CEGUI】
CEGUI的基类是Window。它从属性集和事件集继承而来,如下:
class CEGUIEXPORT Window : public PropertySet, public EventSet
我们会奇怪:另外的职责哪里去了?相信在类的设计中,最常用的除了“继承”关系以外,就应该是“组合”关系,而且最常用的就是“Pimpl idiom”或者叫“Opaque pointer”又或者叫“Handle classes”方法,就是维护指向一个基类的指针。Window类中也是这样做的:
WindowRenderer* d_windowRenderer; // 负责表现的部分
RenderedStringParser* d_customStringParser;
Font* d_font;
等等。
【MyGUI】
MyGUI的基类是Widget类。
它从以下基类派生:
class MYGUI_EXPORT Widget :
public IObject, // 整个MyGUI中的抽象基类
public ICroppedRectangle, // 负责表现的矩形
public UserData, // 包含数据
public WidgetInput, // 负责用户输入
public delegates::IDelegateUnlink,
public SkinItem, // 负责皮肤系统
【附带:WPF】
WPF(Windows Presentation Foundations)是微软的最新的UI框架。其基类是System.Windows.Controls.Control(不是System.Windows.Forms.Control,那是WinForm的基类)。这个类是从WPF的FrameworkElement类派生的,而这个类具有以下的派生关系:
public class FrameworkElement : UIElement, IFrameworkInputElement, IInputElement, ISupportInitialize, IHaveResources, IQueryAmbient
其中UIElement具有以下的基类:
public class UIElement : Visual, IAnimatable, IInputElement
【思考:关于继承和依赖】
继承所带来的最大的好处是:节省了很多编码量,共性的东西已经在父类中实现,所有子类中都不需要再处理这些逻辑。例如CEGUI的基类继承自PropertySet,那就意味着所有跟Property相关的代码都要在基类PropertySet中实现,Window类中不应该再有。缺点就是:继承自PropertySet,就意味着不能继承自XXXPropertySet,CEGUI的Window类已经不能接受PropertySet方面的扩展;也就意味着PropertySet本身就是个强大的基类,强大到不需要扩展就可以实现所有的功能。满足这些条件的时候更适合于用继承来实现。当然别忘了,public继承的语义是:is-a,别违反了这种语义。
而使用“组合”呢,最明显的好处就是:允许强大的扩展。另外的好处可以google一下“pimpl idiom”。但是缺点呢就是:所有的接口的代码就得重写。例如:CEGUI要执行render时,就可以调用RenderingSurface的draw去进行渲染,而自己完全不需要管理渲染的问题,而且RenderingSurface是可以被无限扩展的。
所以应该谨慎使用继承,确定在不需要扩展的时候才使用继承。否则就应该多写一些代码而使用组合。