設計模式之--適配器模式(adapter)

工作一年多了,紙上的筆記寫了不少,但一直沒有機會整理。現在離職了,就用這段時間整理一下自己的筆記,也順便豐富一下自己的博客吧,要不也真的對不起在這裏潛水兩年的時間。

適配器:基於現有類所提供的服務,向客戶提供接口,以滿足客戶的期望

《Java設計模式》

[b][color=brown][size=large]類適配器[/size][/color][/b]
客戶的開發人員定義了一個接口,期望用這個接口來完成整數的求和操作,接口定義如下:

public interface Operation{
public int add(int a,int b);
}

開發人員在瞭解這個接口的定義後,發現一個第三方類,裏面有一個方法能實現他們期望的功能,其代碼如下:

public class OtherOperation{
public int otherAdd(int a,int b){
return a + b;
}
}

以上第三方類[b][color=brown]OtherOperation[/color][/b]的方法[b][color=brown]public int otherAdd(int a,int b)[/color][/b]所提供的功能,完全能符合客戶的期望,所以只需要想辦法把[b][color=brown]OtherOperation[/color][/b]的[b][color=brown]otherAdd(int a,int b)[/color][/b]和客戶的[b][color=brown]Operation[/color][/b]接口聯繫起來,讓這個第三方類來爲客戶提供他們期望的服務就行了,這樣就避免了開發人員再度去研究類似[b][color=brown]OtherOperation[/color][/b]的[b][color=brown]otherAdd(int a,int b)[/color][/b]方法的實現(利用已有的輪子,避免重複發明),這方法之一,就是用適配器模式:

public class AdapterOperation extends OtherOperation implements Operation{
public int add(int a,int b){
return otherAdd(a,b);
}
}

以上就是適配器的實現方法之一,[color=red]類適配器[/color],在以上實現中存在着三中角色分別是:
1:適配目標角色:Operation。
2:適配類(原)角色:OtherOperation。
3:適配器角色:AdapterOperation。
其中適配器角色是適配器模式的核心。
適配器的主要工作就是通過封裝現有的功能,使他滿足需要的接口。

[b][size=large][color=darkred]對象適配器[/color][/size][/b]
我們再來看看另一種情況:
假如客戶接口期望的功能不止一個,而是多個:

public interface Operation{
public int add(int a,int b);
public int minus(int a,int b);
public int multiplied(int a,int b);
}

而能提供這些實現的原可能不止一個:

public class OtherAdd{
public int otherAdd(int a,int b){
return a + b;
}
}

public class OtherMinus{
public int minus(int a,int b){
return a - b;
}
}

public class OtherMultiplied{
public int multiplied(int a,int b){
return a * b;
}
}

由於java是不能實現多繼承的,所以我們不能通過構建一個適配器,讓他來繼承所有原以完成我們的期望,這時候怎麼辦呢?只能用適配器的另一種實現--[color=red]對象適配器[/color]:

public class AdapterOperation implements Operation{
private OtherAdd add;
private OtherMinus minus;
private OtherMultiplied multiplied;

public void setAdd(OtherAdd add){
this.add = add;
}

public void setMinus(OtherMinus minus){
this.minus = minus;
}

public void setMultiplied(OtherMultiplied multiplied){
this.multiplied = multiplied;
}

//適配加法運算
public int add(int a,int b){
return add.otherAdd(a,b);
}

//適配減法運算
public int minus(int a,int b){
return minus.minus(a,b);
}

//適配乘法運算
public int multiplied(int a,int b){
return multiplied.multiplied(a,b);
}
}

上面代碼很明顯,適配器並不是通過繼承來獲取[color=brown]適配類(原)[/color]的功能的,而是通過[color=brown]適配類[/color]的對象來獲取的,這就解決了java不能多繼承所帶來的不便了。這也是java提倡的編程思想之一,即[color=brown]儘量使用聚合不要使用繼承[/color]。
還有一種情況是需要使用[color=darkred]對象適配器[/color]的。我們來看看,
單我們的客戶提供的需求並不是一個明確的接口,而是一個類,並沒有定義期望的方法,如下

public class A{
public int add(int a,int b){
return a + b;
}
}

現在客戶要一個新類B,要求能在保留類A功能的情況下增加一個運算減法的功能,並要求B能隨時替換掉A但不能對已有系統造成影響。這樣我們只能新建一個類B,並讓B繼承A。

public class B extends A{
b(){
super();
}

public int minus(int a,int b){
//待實現的減法運算函數..
}
}

這時候,我們發現類C已經提供了實現減法的函數,

public class C{
public int minus(int a,int b){
return a - b;
}
}

爲了避免重複去設計該函數,我們決定引入C類,通過適配C類來達到我們的期望,但問題是A和C都是一個具體類,我們無法讓B同時繼承這個兩個類,而B繼承A又是必須的,所以我們只能考慮把C給內聚到B內部,[color=red]對象適配器[/color]又得派上用場了。

public class B extends A{

private C c;

B(){
super();
}

public void setMinus(C c){
this.c= c;
}

public int minus(int a,int b){
return c.minus(a,b);
}
}

這樣,在需要A類的地方都能用B類來代替,同時又保證了新的功能的引入。

[b][color=brown][size=large]更靈活的實現--隱藏目標接口的抽象適配器[/size][/color][/b]

做java 桌面應用的都知道WindowListener接口,

public interface WindowListener extends EventListener{
public void windowActivated(WindowEvent e);
public void windowClosed(WindowEvent e);
public void windowClosing(WindowEvent e);
public void windowDeactivated(WindowEvent e);
public void windowDeiconified(WindowEvent e);
public void windowIconified(WindowEvent e);
public void windowOpened(WindowEvent e);
}

要實現這個接口,我們就必須實現它所定義的所有方法,但是實際上,我們很少需要同時用到所有的方法,我們要的只是其中的兩三個。爲了不使我們實現多餘的方法,
jdk WindowListener提供了一個WindowListener的默認實現類WindowAdapter類,這是一個抽象類,

public abstract class WindowAdapter implements WindowListener{
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
}

WindowAdapter類對WindowListener接口的所有有方法都提供了空實現,
有了WindowAdapter類,我們只需要去繼承WindowAdapter,然後選擇我們所關心的方法來實現就行了,這樣就避免了直接去實現WindowListener接口。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章