什么是结构性模式 结构性模式描述类和对象怎样结合在一起成为较大的结构 结构性模式描述两种不同的东西类与类的实例根据它们所描述的东西的不同 结构性模式可以分为类结构模式和实例结构模式两种 类结构模式使用继承(inheritance)来把类接口等组合在一起形成更大的结构 当一个类从父类继承并实现某接口时这个新的类就把父类的结构和接口的结构结合起来 类结构模式是静态的一个类结构模式的典型的例子就是类形式的变压器模式 实例结构模式描述各种不同类型的把对象组合在一起实现新的功能的方法实例结构模式是动态的 一个典型的实例结构模式就是代理人模式代理人模式将在以后介绍其它的例子包括后面将要介绍的复合模式 飞行重量模式装饰模式以及实例形式的变压器模式等 有一些模式会有类结构模式的形式和实例结构模式的形式两种成为以上两种形式的结构模式的极好注解 本节要介绍的变压器模式就是这样它有类形式和实例形式两种 变压器模式的介绍 变压器模式把一个类的接口变换成客户端所期待的另一种接口变压器模式使原本无法在一起工作的两个类能够在一起工作 如前所述变压器模式是关于类结构的结构性模式因而是静态的模式 这很象变压器(Adapter)变压器把一种电压变换成另一种电压当我把美国的电器拿回中国大陆去用的时候 我就面临电压不同的问题美国的生活用电压是伏而中国的电压是伏我如果要在中国大陆使用我在美国使用的电器 我就必须有一个能把伏电压转换成伏电压的变压器而这正象是本模式所做的事因此此模式被称为变压器模式 读者可能也会想到Adapter在中文也可翻译为转换器(适配器)实际上转换器(适配器)也是一个合适的名字仍用电器作例子 美国的电器的插头一般是三相的即除了阳极阴极外还有一个地极中国大陆的建筑物内的电源插座一般只有两极没有地极 这时候即便电器的确可以接受伏电压电源插座和插头不匹配也使电器无法使用 一个三相到两相的转换器(适配器)就能解决这个问题因此此模式也可被称为转换器(适配器)模式 同时这种做法也很象包装过程被包装的物体的真实样子被包装所掩盖和改变因此有人把这种模式叫做包装(Wrapper)模式事实上 我们经常写很多这样的wrapper类把已有的一些类包裹起来使之能有满足需要的接口 变压器模式有类形式和实例形式两种不同的形式 类形式的变压器模式的类图定义如下 图 类形式的类变压器模式的类图定义 在图可以看出模式所涉及的成员有 目标(Target)这就是我们所期待得到的接口注意由于这里讨论的是类变压器模式因此目标不可以是类 源(Adaptee)现有需要适配的接口 变压器(Adapter)变压器类是本模式的核心变压器把源接口转换成目标接口显然这一角色不可以是接口 而必须是实类 本模式的示范代码如下 package comjavapatternsadapterclassAdapter; public interface Target { /** * Class Adaptee contains operation sampleOperation */ void sampleOperation(); /** * Class Adaptee doesnt contain operation sampleOperation */ void sampleOperation(); } 代码清单 Target的源代码 package comjavapatternsadapterclassAdapter; public class Adaptee { public void sampleOperation(){} } 代码清单 Adaptee的源代码 package comjavapatternsadapterclassAdapter; public class Adapter extends Adaptee implements Target { /** * Class Adaptee doesnt contain operation sampleOperation */ public void sampleOperation() { // Write your code here } } 代码清单 Adapter的源代码 类形式的变压器模式的效果 第一 使用一个实类把源(Adaptee)适配到目标(Target)这样一来如果你想把源以及源的子类都使用此类适配 就行不通了 第二 由于变压器类是源的子类因此可以在变压器类中置换(override)掉源的一些方法 第三 由于只引进了一个变压器类因此只有一个路线到达目标类问题得到简化 实例形式的变压器模式的类图定义如下 在图可以看出模式所涉及的成员有 目标(Target)这就是我们所期待得到的接口目标可以是实的或抽象的类 源(Adaptee)现有需要适配的接口 变压器(Adapter)变压器类是本模式的核心变压器把源接口转换成目标接口 显然这一角色必须是实类 本模式的示范代码如下 package comjavapatternsadapter; public interface Target { /** * Class Adaptee contains operation sampleOperation */ void sampleOperation(); /** * Class Adaptee doesnt contain operation sampleOperation */ void sampleOperation(); } 代码清单 Target的源代码 package comjavapatternsadapter; public class Adapter implements Target { public Adapter(Adaptee adaptee){ super(); thisadaptee = adaptee; } public void sampleOperation(){ adapteesampleOperation(); } public void sampleOperation(){ // Write your code here } private Adaptee adaptee; } 代码清单 Adapter的源代码 package comjavapatternsadapter; public class Adaptee { public void sampleOperation(){} } 代码清单 Adaptee的源代码 实例形式的变压器模式的效果 第一 一个变压器可以把多种不同的源适配到同一个目标换言之同一个变压器可以把源类和它的子类都适配到目标接口 第二 与类形式的变压器模式相比要想置换源类的方法就不容易如果一定要置换掉源类的一个或多个方法就只好先做一个源类的子类 将源类的方法置换掉然后再把源类的子类当作真正的源进行适配 第三 虽然要想置换源类的方法不容易但是要想增加一些新的方法则方便得很 而且新增加的方法同时适用于所有的源 在什么情况下使用变压器模式 在以下各种情况下使用变压器模式 第一 你需要使用现有的类而此类的接口不符合你的需要 第二 你想要建立一个可以重复使用的类用以与一些彼此之间没有太大关联的一些类 包括一些可能在将来引进的类一起工作这些源类不一定有很复杂的接口 第三 (对实例形式的变压器模式而言)你需要改变多个已有的子类的接口 如果使用类形式的变压器模式就要针对每一个子类做一个变压器类而这不太实际 JSE中的变压器模式的使用 在爪哇语言的标准SDK中有很多的变压器类如 库程序包java\awt\event中有 ComponentAdapter ContainerAdapter FocusAdapter HierarchyBoundsAdapter KeyAdapter MouseAdapter MouseMotionAdapter WindowAdapter 库程序包Javax\swing\event中有 InternalFrameAdapter MouseInputAdapter 这些都是变压器模式使用的实际例子值得指出的是WindowAdapter的建立者们不可能预见到你所要使用的目标接口 因此WindowAdapter不可能实现你的目标接口但是在考察了这些变压器类的使用范围之后我们会发现 WindowAdapter只需实现WindowListener的接口即可也就是说目标接口被省略了请见下面的解释 |