1. 介面卡模式簡介
1.1 模式定義
介面卡模式:通過一個類的介面轉換成客戶希望的另外一個介面,使原本由於介面不相容而不能一起工作的那些類可以一起工作。
介面卡從結構上分為:類介面卡和物件介面卡。其中類介面卡使用繼承關係來對類進行適配,物件介面卡使用物件引用來進行適配。
C#實現類介面卡時,Target只能是介面。實現物件介面卡時,Target可以是抽象類也可以是介面。
1.2 使用頻率
中高
2. 類介面卡模式結構
2.1 結構圖
2.1.1 類介面卡結構圖
2.1.2 物件介面卡結構圖
2.2 參與者
介面卡模式參與者:
◊ Target:Client所使用的目標介面,可以是介面或抽象類。由於C#/Java不支援多類繼承,故把Target定義為介面。
◊ Adaptee:需要適配的類介面。
◊ Adapter:介面卡,負責Adaptee的介面與Target介面進行適配。
◊ Client:與符合Target介面的物件協調的類。
在介面卡模式中,類Adapter實現介面卡的功能,它在Client於Adaptee之間加入Adapter,這樣Client把請求發給介面為Target的類Adapter,再由Adapter呼叫Adaptee,從而實現Client呼叫Adaptee。
3. 介面卡模式結構實現
3.1 類介面卡結構實現
ITarget.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public interface ITarget { void Request(); } }
Adaptee.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } } }
Adapter.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public class Adapter : Adaptee, ITarget { public void Request() { this.SpecificRequest(); } } }
Client.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public class Client { static void Main(string[] args) { ITarget t = new Adapter(); t.Request(); } } }
執行輸出:
Called SpecificRequest()
請按任意鍵繼續. . .
3.2 物件介面卡結構實現
Client需要呼叫Request方法,而Adaptee並沒有該方法,為了使Client能夠使用Adaptee類,需要提供一個類Adapter。這個類包含了一個Adaptee的例項,將Client與Adaptee銜接起來。
ITarget.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public interface ITarget { void Request(); } }
Target.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Target : ITarget { public virtual void Request() { Console.WriteLine("Called Target Request()"); } } }
Adaptee.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } } }
Adapter.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Adapter : Target { private Adaptee _adaptee = new Adaptee(); public override void Request() { _adaptee.SpecificRequest(); } } }
Client.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Client { static void Main(string[] args) { ITarget t = new Adapter(); t.Request(); } } }
4. 介面卡模式實踐應用
以手機充電的電源介面卡為例,用介面卡模式的解決方案。
4.1 類介面卡結構實現
ITarget.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public interface ITarget { void GetPower(); } }
Power.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public class Power { public void GetPower220V() { Console.WriteLine("從電源中得到220V的電壓"); } } }
Adapter.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public class Adapter : Power, ITarget { public void GetPower() { this.GetPower220V(); Console.WriteLine("得到手機的充電電壓!"); } } }
Client.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public class Client { static void Main(string[] args) { Console.WriteLine("手機:"); ITarget t = new Adapter(); t.GetPower(); } } }
執行輸出:
手機:
從電源中得到220V的電壓
得到手機的充電電壓!
請按任意鍵繼續. . .
4.2>、物件介面卡結構實現
ITarget.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public interface ITarget { void GetPower(); } }
Power.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public class Power { public void GetPower220V() { Console.WriteLine("從電源中得到220V的電壓"); } } }
Adapter.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public class Adapter : ITarget { public Power _power; public Adapter(Power power) { this._power = power; } /// <summary> /// 得到想要的電壓 /// </summary> public void GetPower() { _power.GetPower220V(); Console.WriteLine("得到手機的充電電壓!"); } } }
Client.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public class Client { static void Main(string[] args) { Console.WriteLine("手機:"); ITarget t = new Adapter(new Power()); t.GetPower(); } } }
5、介面卡模式應用分析
介面卡模式適用情形:
◊ 當適用一個已存在的類,而它的介面不符合所要求的情況;
◊ 想要建立一個可以複用的類,該類可以與原介面的類協調工作;
◊ 在物件適配中,當要匹配數個子類的時候,物件介面卡可以適配它們的父類介面。
介面卡模式特點:
類介面卡
◊ 使得Adapter可以重定義Adaptee的部分行為。因為Adapter是Adaptee的一個子類;
◊ 僅僅引入了一個物件,並不需要額外的指標間接得到Adaptee。
物件介面卡
◊ 允許一個Adapter與多個Adaptee同時工作。Adapter也可以一次給所有的Adaptee新增功能;
◊ 使得重定義Adaptee的行為比較困難。需要生成一個Adaptee的子類,然後使Adapter引入這個子類而不是引用Adaptee本身。