實例形式的變壓器模式的類圖定義如下。
圖2. 實例變壓器模式的類圖定義
在圖1可以看出,模式所涉及的成員有:
- 目標(Target)。這就是我們所期待得到的接口。目標可以是實的或抽象的類。
- 源(Adaptee)。現有需要適配的接口。
- 變壓器(Adapter)。變壓器類是本模式的核心。變壓器把源接口轉換成目標接口。 顯然,這一角色必須是實類。
本模式的示范代碼如下:
package com.javapatterns.adapter; public interface Target { /** * Class Adaptee contains operation sampleOperation1. */ void sampleOperation1(); /** * Class Adaptee doesn't contain operation sampleOperation2. */ void sampleOperation2(); }代碼清單4. Target的源代碼。
package com.javapatterns.adapter; public class Adapter implements Target { public Adapter(Adaptee adaptee){ super(); this.adaptee = adaptee; } public void sampleOperation1(){ adaptee.sampleOperation1(); } public void sampleOperation2(){ // Write your code here } private Adaptee adaptee; }代碼清單5. Adapter的源代碼。
package com.javapatterns.adapter; public class Adaptee { public void sampleOperation1(){} }代碼清單6. Adaptee的源代碼。
實例形式的變壓器模式的效果
第一、 一個變壓器可以把多種不同的源適配到同一個目標。換言之,同一個變壓器可以把源類和它的子類都適配到目標接口。
第二、 與類形式的變壓器模式相比,要想置換源類的方法就不容易。如果一定要置換掉源類的一個或多個方法,就只好先做一個源類的子類, 將源類的方法置換掉,然后再把源類的子類當作真正的源進行適配。
第三、 雖然要想置換源類的方法不容易,但是要想增加一些新的方法則方便得很。 而且新增加的方法同時適用于所有的源。
利用變壓器模式指方為圓
中國古代有趙高指鹿為馬的故事。鹿與馬有很多相似之處,沒見過的人本就分辨不清,指一指可能沒什么大不了的。 指方為圓是否太過?非也。本例就是要指方為圓,需要的只是變壓器模式這個魔術手指(Magic Finger)。
變壓器模式在本例子的類圖如下。
圖6. 指方為圓的變壓器模式類圖
package com.javapatterns.adapter.cube2ball; public class Cube { public Cube(double width) { this.width = width; } public double calculateVolume() { return width * width * width; } public double calculateFaceArea() { return width * width; } public double getWidth() { return this.width; } public void setWidth(double width) { this.width = width; } private double width; }代碼清單8. Cube類的源代碼。。
package com.javapatterns.adapter.cube2ball; public interface BallIF { double calculateArea(); double calculateVolume(); double getRadius(); void setRadius(double radius); }代碼清單9. BallIF接口的源代碼。
package com.javapatterns.adapter.cube2ball; public class MagicFinger implements BallIF { public MagicFinger(Cube adaptee) { super(); this.adaptee = adaptee; radius = adaptee.getWidth(); } public double calculateArea() { return PI * 4.0D * ( radius * radius ); } public double calculateVolume() { return PI * 4.0D/3.0D * ( radius * radius * radius ); } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } private double radius = 0; private static final double PI = 3.14D; private Cube adaptee; }代碼清單10. MagicFinger類的源代碼。
如果讀者還記得中學的數學的話,應該可以看出,我們的指方為圓系統其實還是有道理的。它接受一個正方體, 返還此正方體的內切球,也就是能放進此正方體的最大的球。
顯然,本例子里,我們使用的是實例形式的變壓器模式。這樣做的好處是,如果一旦我們決定不僅要支持正方體, 而且要支持四面體等多面體,我們可以使用同一個MagicFinger類,而不必針對每一個多面體都建立一個MagicFinger類。 這樣也比較符合“魔術手指”這個名字。