Window和WindowImp
我们将定义一个独立的Wi n d o w I m p类层次来隐藏不同窗口系统的实现。Wi n d o w I m p是一个封装了窗口系统相关代码的对象的抽象类。为了使L e x i运行于一个特定的窗口系统,我们用该系统的一个Wi n d o w I m p子类实例设置Wi n d o w对象。下面的图显示了Wi n d o w 和Wi n d o w I m p层次结构之间的关系。
通过在Wi n d o w I m p类中隐藏实现,我们避免了对窗口系统的直接依赖,这可以让Wi n d o w类层次保持相对较小并且较稳定。同时我们还能方便地扩展实现层次结构以支持新的窗口系统。
1. Wi n d o w I m p的子类
Wi n d o w I m p的子类将用户请求转变成对特定窗口系统的操作。考虑我们在2 . 2节所用的例子,我们根据Wi n d o w实例的D r a w R e c t操作定义了R e c t a n g e l : : D r a w:
这里_ i m p是Wi n d o w的成员变量,它保存了设置Wi n d o w的Wi n d o w I m p。窗口的实现是由_ i m p所指的Wi n d o w I m p子类的实例定义的。对于一个X Wi n d o w I m p (即X窗口系统的Wi n d o w I m p子类),D e v i c e R e c t的实现可能如下:
D e v i c e R e c t这样做是因为XDr a w R e c t a n g l e(在X系统中画矩形的接口)是根据矩形的左下顶点、宽度和高度定义矩形的, D e v i c e R e c t必须根据参数值来计算这些值。首先它必须确定左下顶点(因为( x 0 , y 0 )可能是矩形四个顶点中的任一个),然后计算宽度和高度。
P M Wi n d o w I m p(Presentation Manager的Wi n d o w I m p子类)定义D e v i c e R e c t时会有所不同:
为什么这和X版本有如此大的差别?因为P M没有像X那样显式画矩形的操作,它有一个更一般性的接口可以指定多个段(或称之为路径)的顶点、画出这些线段并且填充它们所围成的区域。
D e v i c e R e c t的P M实现很显然与X的实现有很大不同,但问题不大。Wi n d o w I m p用一个可能巨大但却稳定的接口隐藏了各个窗口系统接口的差异。这使得Wi n d o w子类的实现者可以将
更多的精力放在窗口的抽象上,而不是窗口系统的细节。它也支持我们增加新的窗口系统,而不会搞乱Wi n d o w类。
2. 用Wi n d o w I m p来配置Wi n d o w s
我们还没有论述的一个关键问题是:怎样用一个合适的Wi n d o w I m p子类来配置一个窗口?也就是说,什么时候初始化_ i m p,谁知道正在使用的是什么窗口系统(也就是哪一个Wi n d o w I m p子类)?窗口在能做它所感兴趣的事情之前,都需要某种Wi n d o w I m p。这些问题的答案存在很多种可能性,但我们只关注使用Abstract Factory(3.1)模式的情形。我们可以定义一个抽象工厂类Wi n d o w S y s t e m F a c t o r y,它提供了创建不同种与窗口系统有关的实现对象的接口:
w i n d o w S y s t e m F a c t o r y变量是Wi n d o w S y s t e m F a c t o r y某个子类的实例,它是公共可见的,正如g u i F a c t o r y是公共可见的定义视感的变量。w i n d o w S y s t e m F a c t o r y变量可用相同的方法进行初始化。