問題:
在物件導向的軟體設計中,經常需要將一些現存的對象放在新的環境中或與新的對象一起工作,但是他的介面與新環境要求的介面不同,而雙方又都無法改變。
定義:
適配器模式 也稱封裝樣式或者封裝,將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
意圖:
定義一個Adapter角色,將一個已存在的Adaptee類,通過繼承或封裝的手段,讓他與現有的類實現同一介面的辦法,轉換成客戶希望的另外一個介面,使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
參與者:
•目標(Target)角色:
這是客戶所期待的介面。目標可以是具體的或抽象的類,也可以是介面。
•源(Adaptee)角色:
需要適配的類。
•適配器(Adapter)角色:
通過在繼承或內部封裝(Wrap)一個Adaptee對象,把源介面轉換成目標介面。此角色要繼承Target。
分類
適配器模式的變化比較多,可以通過繼承和組合方式進行適配,適配器可以是一組適配器產品,適配器也可以是抽象類別型。
•類適配器:
提供一個實現該介面的類,並且擴充已有的類,通過建立子類來實現適配。
•對象適配器:
對象適配器”通過組合除了滿足“使用者期待介面”還降低了代碼間的不良耦合。
執行個體說明:
諾基亞手機工廠
生產工廠 有兩個生產車間,生產方式有所不同,下面例子通過 對象適配器 適配生產車間1,通過類適配器適配生產車間2,讓他們有一個共同的面向客戶的介面。
uml圖如下:
代碼:
/// <summary>
/// N8手機抽象產品類,目標(Target)角色,用戶端調用介面
/// </summary>
public interface IPhoneFactory
{
void Create(string Name, int Count);
}
/// <summary>
/// 一號生產車間 Adaptee 角色
/// </summary>
public class PhoneFactory1
{
public int Count { get; set; }
public void Create(string Name)
{
System.Console.WriteLine("生產{0}個{1}手機", this.Count, Name);
}
}
/// <summary>
/// 二號生產車間 Adaptee 角色
/// </summary>
public class PhoneFactory2
{
public void Build(string Name, int Count)
{
System.Console.WriteLine("生產{0}個{1}手機", Count, Name);
}
}
/// <summary>
/// 適配器1用於適配一號生產車間,通過在內部封裝(Wrap)一個Adaptee對象,把源介面轉換成目標介面。
/// </summary>
public class FactoryAdapter1 : IPhoneFactory
{
PhoneFactory1 phoneFactory1 = new PhoneFactory1();
public void Create(string Name, int Count)
{
phoneFactory1.Count = Count;
phoneFactory1.Create(Name);
}
}
/// <summary>
/// 適配器2 用於適配二號生產車間,通過在繼承一個Adaptee對象,把源介面轉換成目標介面。
/// </summary>
public class FactoryAdapter2 : PhoneFactory2, IPhoneFactory
{
public void Create(string Name, int Count)
{
base.Build(Name, Count);
}
}
/// <summary>
/// 用戶端測試
/// </summary>
public void AdapterTest()
{
IPhoneFactory pf = new FactoryAdapter1();
pf.Create("N8", 10);
pf = new FactoryAdapter2();
pf.Create("N8", 10);
}
優點:
•對代碼複用、類庫遷移等方面的實現變得非常容易。
•類適配器因為Adapter是Adaptee的一個子類所以可以通過重寫重新定義Adaptee的部分行為。
•對象適配器允許一個Adapter與多個Adaptee,即Adaptee本身以及它的所有子類一起工作。
缺點:
•需要改變(適配)多個已有子類的介面,如果使用類的適配器模式,就要針對每個類做一個適配器。
•類適配器使用了“多繼承”的實現方式,帶來了不良的高耦合。
應用情景:
•系統需要使用現有的類,而此類的介面不符合系統的需要。
•想要建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
PS:
適配器模式是否能成功運用的關鍵在於代碼本身是否是基於介面編程的,如果不是的話,那麼適配器無能為力。
Adapter模式主要應用於“希望複用一些現存的類,但是介面又與複用環境要求不一致的情況”,在遺留代碼複用、類庫遷移等方面非常有用。
Adapter模式的實現可以非常。處了類適配器和對象適配器,還可以將Adapter模式中的“現存對象”作為新的介面方法參數,來達到適配的目的。
類適配器採用“多繼承”的實現方式,帶來了不良的高耦合,所以一般不推薦使用。對象適配器採用“對象組合”的方式,符合松耦合。