C#设计模式--适配器模式(Adapter Pattern)

适配器模式是一种 结构型设计模式,它允许不兼容的接口协同工作。通过创建一个适配器类来解决不同接口之间的不兼容问题,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

使用方式及用途

  1. 接口转换:将一个类的接口转换成客户端期望的另一个接口。
  2. 类适配器:通过继承目标接口和被适配者类来实现。
  3. 对象适配器:通过组合被适配者类来实现。

适配器模式在实际开发中有很多应用场景,主要适用于以下情况:

• 接口不兼容:需要将一个类的接口转换成客户端期望的另一个接口。

• 多平台支持:需要支持多个平台或框架,每个平台的接口不同。

• 扩展性:需要在不修改现有代码的情况下,增加新的功能或支持新的接口。

实现方式

继承或依赖:推荐使用依赖关系,而不是继承,以保持灵活性

结构

适配器模式包含以下几个主要角色:

目标接口(Target):定义客户需要的接口。
适配者类(Adaptee):定义一个已经存在的接口,这个接口需要适配。
适配器类(Adapter):实现目标接口,并通过组合或继承的方式调用适配者类中的方法,从而实现目标接口。

开发过程中的实际案例

案例1: 数据库适配器

假设一个应用程序,需要支持多种数据库(如 MySQL 和 SQLite)。我们可以使用适配器模式来适配不同的数据库驱动。

示例代码

目标接口(Target)

csharp 复制代码
// 抽象数据库接口
public interface IDatabase
{
    void Connect(string connectionString);
    void ExecuteQuery(string query);
}

适配者类(Adaptee)

csharp 复制代码
// MySQL 数据库实现
public class MySQLDatabase
{
    public void ConnectToMySQL(string connectionString)
    {
        Console.WriteLine($"Connecting to MySQL database with connection string: {connectionString}");
    }

    public void ExecuteMySQLQuery(string query)
    {
        Console.WriteLine($"Executing query on MySQL: {query}");
    }
}

// SQLite 数据库实现
public class SQLiteDatabase
{
    public void ConnectToSQLite(string connectionString)
    {
        Console.WriteLine($"Connecting to SQLite database with connection string: {connectionString}");
    }

    public void ExecuteSQLiteQuery(string query)
    {
        Console.WriteLine($"Executing query on SQLite: {query}");
    }
}

适配器类(Adapter)

csharp 复制代码
// MySQL 数据库适配器
public class MySQLDatabaseAdapter : IDatabase
{
    private readonly MySQLDatabase _mysqlDatabase;

    public MySQLDatabaseAdapter(MySQLDatabase mysqlDatabase)
    {
        _mysqlDatabase = mysqlDatabase;
    }

    public void Connect(string connectionString)
    {
        _mysqlDatabase.ConnectToMySQL(connectionString);
    }

    public void ExecuteQuery(string query)
    {
        _mysqlDatabase.ExecuteMySQLQuery(query);
    }
}

// SQLite 数据库适配器
public class SQLiteDatabaseAdapter : IDatabase
{
    private readonly SQLiteDatabase _sqliteDatabase;

    public SQLiteDatabaseAdapter(SQLiteDatabase sqliteDatabase)
    {
        _sqliteDatabase = sqliteDatabase;
    }

    public void Connect(string connectionString)
    {
        _sqliteDatabase.ConnectToSQLite(connectionString);
    }

    public void ExecuteQuery(string query)
    {
        _sqliteDatabase.ExecuteSQLiteQuery(query);
    }
}

客户端代码

csharp 复制代码
//创建客户端端
public class DatabaseClient
{
    private IDatabase _database;

    public DatabaseClient(IDatabase database)
    {
        _database = database;
    }

    public void PerformOperations()
    {
        _database.Connect("connection_string");//数据库
        _database.ExecuteQuery("SELECT * FROM table");//随意一个表
    }
}

// 使用示例
public class Program
{
    public static void Main()
    {
        MySQLDatabase mysqlDatabase = new MySQLDatabase();
        IDatabase mysqlAdapter = new MySQLDatabaseAdapter(mysqlDatabase);
        DatabaseClient clientForMySQL = new DatabaseClient(mysqlAdapter);
        clientForMySQL.PerformOperations();

        SQLiteDatabase sqliteDatabase = new SQLiteDatabase();
        IDatabase sqliteAdapter = new SQLiteDatabaseAdapter(sqliteDatabase);
        DatabaseClient clientForSQLite = new DatabaseClient(sqliteAdapter);
        clientForSQLite.PerformOperations();
    }
}

类图:
IDatabase +void Connect(string connectionString) +void ExecuteQuery(string query) MySQLDatabase +void ConnectToMySQL(string connectionString) +void ExecuteMySQLQuery(string query) SQLiteDatabase +void ConnectToSQLite(string connectionString) +void ExecuteSQLiteQuery(string query) MySQLDatabaseAdapter -MySQLDatabase _mysqlDatabase +MySQLDatabaseAdapter(MySQLDatabase mysqlDatabase) +void Connect(string connectionString) +void ExecuteQuery(string query) SQLiteDatabaseAdapter -SQLiteDatabase _sqliteDatabase +SQLiteDatabaseAdapter(SQLiteDatabase sqliteDatabase) +void Connect(string connectionString) +void ExecuteQuery(string query) DatabaseClient -IDatabase _database +DatabaseClient(IDatabase database) +void PerformOperations() Program +static void Main()

案例2:UI 控件适配器

假设一个需要支持多个平台(如 Windows 和 macOS),每个平台的 UI 控件接口不同。使用适配器模式来适配不同的 UI 控件。

示例代码

目标接口(Target)

csharp 复制代码
// 抽象 UI 控件接口
public interface IButton
{
    void Render();
    void Click();
}

适配者类(Adaptee)

csharp 复制代码
// Windows 按钮实现
public class WindowsButtonControl
{
    public void RenderWindowsButton()
    {
        Console.WriteLine("Rendering Windows Button");
    }

    public void ClickWindowsButton()
    {
        Console.WriteLine("Windows Button clicked");
    }
}

// macOS 按钮实现
public class MacOSButtonControl
{
    public void RenderMacOSButton()
    {
        Console.WriteLine("Rendering macOS Button");
    }

    public void ClickMacOSButton()
    {
        Console.WriteLine("macOS Button clicked");
    }
}

适配器类(Adapter)

csharp 复制代码
// Windows 按钮适配器
public class WindowsButtonAdapter : IButton
{
    private readonly WindowsButtonControl _windowsButtonControl;

    public WindowsButtonAdapter(WindowsButtonControl windowsButtonControl)
    {
        _windowsButtonControl = windowsButtonControl;
    }

    public void Render()
    {
        _windowsButtonControl.RenderWindowsButton();
    }

    public void Click()
    {
        _windowsButtonControl.ClickWindowsButton();
    }
}

// macOS 按钮适配器
public class MacOSButtonAdapter : IButton
{
    private readonly MacOSButtonControl _macOSButtonControl;

    public MacOSButtonAdapter(MacOSButtonControl macOSButtonControl)
    {
        _macOSButtonControl = macOSButtonControl;
    }

    public void Render()
    {
        _macOSButtonControl.RenderMacOSButton();
    }

    public void Click()
    {
        _macOSButtonControl.ClickMacOSButton();
    }
}

客户端代码

csharp 复制代码
public class UIController
{
    private IButton _button;

    public UIController(IButton button)
    {
        _button = button;
    }

    public void ShowUI()
    {
        _button.Render();
        _button.Click();
    }
}

// 使用示例
public class Program
{
    public static void Main()
    {
        WindowsButtonControl windowsButtonControl = new WindowsButtonControl();
        IButton windowsButtonAdapter = new WindowsButtonAdapter(windowsButtonControl);
        UIController controllerForWindows = new UIController(windowsButtonAdapter);
        controllerForWindows.ShowUI();

        MacOSButtonControl macosButtonControl = new MacOSButtonControl();
        IButton macosButtonAdapter = new MacOSButtonAdapter(macosButtonControl);
        UIController controllerForMacOS = new UIController(macosButtonAdapter);
        controllerForMacOS.ShowUI();
    }
}

类图:

IButton +void Render() +void Click() WindowsButtonControl +void RenderWindowsButton() +void ClickWindowsButton() MacOSButtonControl +void RenderMacOSButton() +void ClickMacOSButton() WindowsButtonAdapter -WindowsButtonControl _windowsButtonControl +WindowsButtonAdapter(WindowsButtonControl windowsButtonControl) +void Render() +void Click() MacOSButtonAdapter -MacOSButtonControl _macOSButtonControl +MacOSButtonAdapter(MacOSButtonControl macOSButtonControl) +void Render() +void Click() UIController -IButton _button +UIController(IButton button) +void ShowUI() Program +static void Main()

案例3. 文件读写适配器

假设程序需要支持多种文件格式(如 CSV 和 JSON),也可以使用适配器模式来适配不同的文件读写操作。

示例代码
目标接口(Target)

csharp 复制代码
// 抽象日志记录接口
public interface ILogger
{
    void Log(string message);
}

适配者类(Adaptee)

csharp 复制代码
// NLog 实现
public class NLog
{
    public void LogWithNLog(string message)
    {
        Console.WriteLine($"Logging with NLog: {message}");
    }
}

// Serilog 实现
public class Serilog
{
    public void LogWithSerilog(string message)
    {
        Console.WriteLine($"Logging with Serilog: {message}");
    }
}

适配器类(Adapter)

csharp 复制代码
// NLog 适配器
public class NLogAdapter : ILogger
{
    private readonly NLog _nlog;

    public NLogAdapter(NLog nlog)
    {
        _nlog = nlog;
    }

    public void Log(string message)
    {
        _nlog.LogWithNLog(message);
    }
}

// Serilog 适配器
public class SerilogAdapter : ILogger
{
    private readonly Serilog _serilog;

    public SerilogAdapter(Serilog serilog)
    {
        _serilog = serilog;
    }

    public void Log(string message)
    {
        _serilog.LogWithSerilog(message);
    }
}

客户端代码

csharp 复制代码
public class LoggerClient
{
    private ILogger _logger;

    public LoggerClient(ILogger logger)
    {
        _logger = logger;
    }

    public void PerformLogging()
    {
        _logger.Log("This is a log message");
    }
}

// 使用示例
public class Program
{
    public static void Main()
    {
        NLog nlog = new NLog();
        ILogger nlogAdapter = new NLogAdapter(nlog);
        LoggerClient clientForNLog = new LoggerClient(nlogAdapter);
        clientForNLog.PerformLogging();

        Serilog serilog = new Serilog();
        ILogger serilogAdapter = new SerilogAdapter(serilog);
        LoggerClient clientForSerilog = new LoggerClient(serilogAdapter);
        clientForSerilog.PerformLogging();
    }
}

类图:

ILogger +void Log(string message) NLog +void LogWithNLog(string message) Serilog +void LogWithSerilog(string message) NLogAdapter -NLog _nlog +NLogAdapter(NLog nlog) +void Log(string message) SerilogAdapter -Serilog _serilog +SerilogAdapter(Serilog serilog) +void Log(string message) LoggerClient -ILogger _logger +LoggerClient(ILogger logger) +void PerformLogging() Program +static void Main()

优点

  1. 提高复用性:适配器模式可以使现有的类在新的环境中重用,而不需要修改原有类的代码。
  2. 增强灵活性:通过适配器,可以轻松地将不同的类集成在一起,即使它们的接口不兼容。
  3. 开放封闭原则:符合开放封闭原则,即对扩展开放,对修改封闭。可以通过添加新的适配器类来支持新的接口,而不需要修改现有代码。

缺点

  1. 增加复杂性:适配器模式会增加系统的复杂性,因为需要引入额外的适配器类。
  2. 性能开销:适配器模式可能会引入额外的性能开销,特别是在适配器类中进行大量转换和处理时。
  3. 维护成本:随着适配器数量的增加,维护这些适配器类的成本也会增加。

总结

适配器模式是一种非常实用的设计模式,特别适用于需要将不同接口的类集成在一起的场景。通过适配器模式,可以有效地解决接口不兼容的问题,提高代码的复用性和灵活性。然而,使用适配器模式也会增加系统的复杂性和维护成本,因此在实际开发中需要权衡利弊,合理使用。

相关推荐
hie988942 小时前
C#与KepOPC通讯
开发语言·c#
hweiyu003 小时前
C#学习教程(附电子书资料)
开发语言·学习·c#
xiaolin03333 小时前
【设计模式】- 行为型模式1
设计模式·状态模式·责任链模式·策略模式·命令模式·模板方法模式·行为型模式
沐土Arvin4 小时前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
bao_lanlan5 小时前
兰亭妙微:用系统化思维重构智能座舱 UI 体验
ui·设计模式·信息可视化·人机交互·交互·ux·外观模式
csdn_aspnet5 小时前
C# DataGridView 选中所有复选框
c#·winform·datagridview
总是难免6 小时前
设计模式 - 单例模式 - Tips
java·单例模式·设计模式
qq_297908017 小时前
c#车检车构客户管理系统软件车辆年审短信提醒软件
sqlserver·c#·开源软件
酷炫码神8 小时前
C#数组与集合
开发语言·c#
钢铁男儿8 小时前
C# 深入理解类(静态函数成员)
java·开发语言·c#