重溫《深入淺出設計模式》轉接器模式 (Book Review of Head First Design Pattern, Adapter Pattern)
2020-07-03
轉接器模式常與表象模式進行比較,從使用上的觀點來看,前者是為了將類別能夠配合多型的方法使用,將目標類別以介面的方式,實作一個轉接器來轉換被既有的類別來達成;表象模式則是將龐雜的類別包裝成簡易的介面,讓使用者與龐雜的類別保持低耦合、最小知識,同時易於使用。
轉接器模式
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
After Pattern
轉接器模式可以透過合成的方式,藉由實作介面的達成物件的用途轉型,並且讓客戶端使用上不會感覺到物件類別的差異。Duck Adapter 實作的是 Turkey interface 所以是將 duck 轉為 turkey 多型使用;Turkey Adapter 則相反,是將 turkey 轉為 duck 多型使用。
轉接器是一個輕巧簡易使用的模式,在使用上只要利用轉接器去實作要多型使用對象的 Interface 即可完成,然而在實際的情境可能要多型使用的對象是類別而非 Interface,這時或可先將類別的要多型使用的方法抽出成 Interface,並且讓轉接器去實作此類別來完成。
DuckAdapter.cs
IDuck.cs
<- MallardDuck.cs
public interface IDuck
{
void Fly();
void Quack();
}
public class MallardDuck : IDuck
{
public void Quack()
{
Console.WriteLine("Quack (Duck style)");
}
public void Fly()
{
Console.WriteLine("I'm flying (Duck style)");
}
}
// From Duck Class To Turkey Class
public class DuckAdapter : ITurkey
{
private readonly IDuck _duck;
public DuckAdapter(IDuck duck)
{
this._duck = duck;
}
public void Gobble()
{
_duck.Quack();
}
public void Fly()
{
_duck.Fly();
}
}
TurkeyAdapter.cs
ITurkey.cs
<- WildTurkey.cs
public interface ITurkey
{
void Gobble();
void Fly();
}
public class WildTurkey : ITurkey
{
public void Gobble()
{
Console.WriteLine("Gobble gobble (Turkey style)");
}
public void Fly()
{
Console.WriteLine("I'm flying a short distance (Turkey style)");
}
}
// From Turkey Class To Duck Class
public class TurkeyAdapter : IDuck
{
private readonly ITurkey _turkey;
public TurkeyAdapter(ITurkey turkey)
{
this._turkey = turkey;
}
void IDuck.Fly()
{
for (int i = 0; i < 5; i++)
{
_turkey.Fly();
}
}
void IDuck.Quack()
{
_turkey.Gobble();
}
}
DuckTestDrive.cs
TurkeyTestDrive.cs
public static void Main(string[] args)
{
MallardDuck duck = new MallardDuck();
ITurkey duckAdapter = new DuckAdapter(duck);
Console.WriteLine("A Duck is doing Turkey things : ");
duckAdapter.Gobble();
duckAdapter.Fly();
Console.WriteLine("\n-------------------------------------------------\n");
WildTurkey turkey = new WildTurkey();
IDuck turkeyAdapter = new TurkeyAdapter(turkey);
Console.WriteLine("A Turkey is doing Duck things : ");
turkeyAdapter.Quack();
turkeyAdapter.Fly();
}
小結
✔️將變動的部分封裝起來
✔️類別應該對需求保持開放;應該對既有的程式碼修改保持關閉
被轉接的類別 (Adaptee) 可能會有變動,但透過 Adapter 使用的 Client 不會受影響
✔️多用合成,少用繼承
Adapter 使用合成的方式將 Adaptee 包裝在其中
✔️讓需要互動的物件之間的關係鬆綁
Client 與 Adaptee 低耦合
✔️針對介面撰寫,而非針對實踐方式撰寫
Target 是 Interface , Adapter 針對 Target 去撰寫演算邏輯。