首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

設計模式實戰:使用泛型改良適配器模式 (C#/C++/VB)

     編輯:關於C#

問題背景

經典類別適配器需對每個被適配類別撰寫專屬適配器 (TriangleDrawAdapter, CircleDrawAdapter...),導致類別爆炸。利用泛型可將「被適配類別」參數化,單一 DrawAdapter<T> 即可處理所有實作 IPaint 的類別。

核心技巧:泛型參數化被適配類別

C++ (Template) - 支援繼承式適配


template <typename T>
class DrawAdapter : public IDrawStrategy, private T 
{
public:
    virtual void draw() const { paint(); } // 直接呼叫 T::paint()
};

// 客戶端動態指定被適配類別
Grapher grapher(&DrawAdapter<Triangle>());
grapher.setShape(&DrawAdapter<Circle>());

C# (Generics) - 採用組合式適配

C# 泛型不支援繼承型別參數 (class Adapter<T> : T 編譯錯誤),改用組合 + 約束:


public class DrawAdapter<T> : IDrawStrategy where T : IPaint, new()
{
    private readonly T _adaptee = new T(); // 約束要求無參建構子
    
    public void Draw() => _adaptee.Paint();
}

// 使用
var grapher = new Grapher(new DrawAdapter<Triangle>());
grapher.SetShape(new DrawAdapter<Circle>());

C++/CLI (Generics) - 組合式


generic <typename T> where T : IPaint, gcnew()
ref class DrawAdapter : IDrawStrategy
{
    T _adaptee = gcnew T();
    public: virtual void Draw() { _adaptee->Paint(); }
};

VB.NET (Generics) - 組合式


Class DrawAdapter(Of T As {IPaint, New})
    Implements IDrawStrategy
    Private _adaptee As New T()
    Public Sub Draw() Implements IDrawStrategy.Draw
        _adaptee.Paint()
    End Sub
End Class

語言特性對比表

語言泛型種類適配方式關鍵語法
ISO C++Template私有繼承template<typename T> class Adapter : T
C++/CLITemplate + Generics繼承/組合皆可template<typename T> ref class / generic<typename T>
C#Generics僅組合where T : IPaint, new()
VB.NETGenerics僅組合Of T As {IPaint, New}

完整 C# 範例


public interface IDrawStrategy { void Draw(); }
public interface IPaint { void Paint(); }

public class Triangle : IPaint { public void Paint() => Console.WriteLine("Draw Triangle"); }
public class Circle : IPaint { public void Paint() => Console.WriteLine("Draw Circle"); }
public class Square : IPaint { public void Paint() => Console.WriteLine("Draw Square"); }

public class Grapher
{
    private IDrawStrategy _strategy;
    public Grapher(IDrawStrategy s = null) => _strategy = s;
    public void DrawShape() => _strategy?.Draw();
    public void SetShape(IDrawStrategy s) => _strategy = s;
}

public class DrawAdapter<T> : IDrawStrategy where T : IPaint, new()
{
    private readonly T _adaptee = new T();
    public void Draw() => _adaptee.Paint();
}

// Client
var g = new Grapher(new DrawAdapter<Triangle>());
g.DrawShape(); // Draw Triangle
g.SetShape(new DrawAdapter<Circle>());
g.DrawShape(); // Draw Circle

優缺點分析

優點缺點
消除類別爆炸:單一泛型適配器替代 N 個具體適配器 C#/VB 僅支援組合式,無法覆寫被適配類別虛擬方法
編譯期型別安全:約束確保 T 實作 IPaint 要求被適配類別有公用無參建構子 (new() 約束)
客戶端動態組合:執行期決定適配目標 無法適配無法實例化的類別 (抽象類、靜態類)
符合開放封閉原則:新增形狀無需修改適配器代碼 泛型參數化增加認知複雜度

結語

泛型化適配器模式展示了「參數化多態」解決「類別爆炸」的經典應用。C++ Template 支援繼承式適配更靈活;C#/VB Generics 雖限於組合式,但配合介面約束仍能優雅解決核心問題。選擇適配器實作方式時,優先考慮物件適配器 (組合) + 泛型參數化,兼顧彈性與型別安全。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved