深入理解C#结构型设计模式:类适配器与对象适配器

news/2025/2/9 6:34:57 标签: c#, 设计模式, 算法

一、设计模式的基本概念

设计模式是软件开发过程中针对反复出现的问题总结出来的通用解决方案。结构型设计模式主要关注如何将类或对象进行组合,以实现新的功能或满足特定的需求。适配器模式就是结构型设计模式中的一种,它允许将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

二、类适配器模式

(一)实现原理

类适配器模式通过继承来实现接口的适配。它创建一个新的类,该类继承自需要适配的类,并实现目标接口。通过这种方式,新类可以同时拥有原类的功能和目标接口的方法。

(二)原理代码示例

// Portal 类,代表需要适配的类
public class Portal
{
    private readonly string _msg;

    public Portal(string msg)
    {
        _msg = msg;
    }

    public void Input()
    {
        Console.WriteLine(_msg + " --> 18v。");
    }
}

// IOutput 接口,代表目标接口
interface IOutput
{
    void Output();
}

// Adapter 类,适配器类
class Adapter : Portal, IOutput
{
    public Adapter(string msg) : base(msg)
    {
    }

    public void Output()
    {
        Input();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IOutput adapter = new Adapter("220v");
        adapter.Output(); 
    }
}
实际项目案例:旧支付系统与新接口适配

假设一个电商系统中,有一个旧的支付系统类 OldPaymentSystem,它有一个 ProcessPaymentOld 方法用于处理支付。现在系统要升级,引入了一个新的支付接口 INewPayment,包含 ProcessPayment 方法。为了让旧的支付系统能够适配新的接口,可以使用类适配器模式。

// 旧的支付系统类
public class OldPaymentSystem
{
    public void ProcessPaymentOld(decimal amount)
    {
        Console.WriteLine($"Processing payment of {amount} using old system.");
    }
}

// 新的支付接口
public interface INewPayment
{
    void ProcessPayment(decimal amount);
}

// 类适配器
public class PaymentAdapter : OldPaymentSystem, INewPayment
{
    public void ProcessPayment(decimal amount)
    {
        ProcessPaymentOld(amount);
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        INewPayment payment = new PaymentAdapter();
        payment.ProcessPayment(100.0m);
    }
}

在这个案例中,PaymentAdapter 类继承了 OldPaymentSystem 类并实现了 INewPayment 接口,将旧系统的支付方法适配到了新的接口上,使得旧系统可以无缝融入新的支付流程。

 

(三)优缺点分析

  • 优点
    • 实现简单:通过继承和接口实现,代码结构相对清晰,易于理解和维护。
    • 可以重写基类方法:适配器类可以重写基类的方法,从而提供更灵活的适配方式。
  • 缺点
    • 耦合度高:适配器类与被适配的类之间通过继承建立了紧密的联系,当被适配类的实现发生变化时,可能会影响到适配器类。
    • 只能适配一个类:由于 C# 等语言不支持多重继承,适配器类只能继承一个基类,因此只能适配一个类。

三、对象适配器模式

(一)实现原理

对象适配器模式通过组合来实现接口的适配。它创建一个新的类,该类持有需要适配的类的实例,并实现目标接口。在目标接口的方法中,调用适配类实例的相应方法。

(二)原理代码示例

// Portal 类,代表需要适配的类
public class Portal
{
    private readonly string _msg;

    public Portal(string msg)
    {
        _msg = msg;
    }

    public void Input()
    {
        Console.WriteLine(_msg + " --> 18v");
    }
}

// Export 类,抽象类,代表目标接口
public abstract class Export
{
    public abstract void Output();
}

// Adapter 类,适配器类
public class Adapter : Export
{
    private readonly Portal _portal;

    public Adapter(string msg)
    {
        _portal = new Portal(msg);
    }

    public override void Output()
    {
        _portal.Input();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Export adapter = new Adapter("220v");
        adapter.Output(); 
    }
}
实际项目案例:多格式文件读取器适配

假设一个文件处理系统,有多种不同格式的文件读取器,如 TxtFileReader 用于读取文本文件,CsvFileReader 用于读取 CSV 文件。现在系统需要一个统一的文件读取接口 IFileReader,可以使用对象适配器模式来实现。

// 文本文件读取器
public class TxtFileReader
{
    public void ReadTxtFile(string filePath)
    {
        Console.WriteLine($"Reading TXT file: {filePath}");
    }
}

// CSV 文件读取器
public class CsvFileReader
{
    public void ReadCsvFile(string filePath)
    {
        Console.WriteLine($"Reading CSV file: {filePath}");
    }
}

// 统一的文件读取接口
public interface IFileReader
{
    void ReadFile(string filePath);
}

// 对象适配器
public class FileReaderAdapter : IFileReader
{
    private readonly TxtFileReader _txtReader;
    private readonly CsvFileReader _csvReader;

    public FileReaderAdapter()
    {
        _txtReader = new TxtFileReader();
        _csvReader = new CsvFileReader();
    }

    public void ReadFile(string filePath)
    {
        if (filePath.EndsWith(".txt"))
        {
            _txtReader.ReadTxtFile(filePath);
        }
        else if (filePath.EndsWith(".csv"))
        {
            _csvReader.ReadCsvFile(filePath);
        }
        else
        {
            Console.WriteLine("Unsupported file format.");
        }
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        IFileReader reader = new FileReaderAdapter();
        reader.ReadFile("example.txt");
        reader.ReadFile("example.csv");
    }
}

在这个案例中,FileReaderAdapter 类实现了 IFileReader 接口,并持有 TxtFileReader 和 CsvFileReader 对象的引用。在 ReadFile 方法中,根据文件的扩展名选择调用不同的读取器方法,实现了对多种文件读取器的适配。

(三)优缺点分析

  • 优点
    • 低耦合度:适配器类与被适配的类之间通过组合的方式关联,降低了类之间的耦合度。当被适配类的实现发生变化时,只要其接口不变,适配器类就不需要修改。
    • 灵活性高:可以在运行时动态地改变适配器类所适配的对象,只需要修改持有对象的引用即可。
    • 可适配多个类:可以通过修改适配器类,使其能够适配多个不同的类,只要这些类都有类似的功能。
  • 缺点
    • 代码复杂度增加:相对于类适配器模式,对象适配器模式需要创建额外的对象并进行组合,增加了代码的复杂度。
    • 调用开销:由于需要通过对象引用调用方法,会存在一定的调用开销。

四、两种模式的选择

在实际开发中,选择类适配器模式还是对象适配器模式需要根据具体的情况来决定。如果需要适配的类较少,且希望实现简单,那么类适配器模式可能是一个不错的选择。如果需要适配的类较多,或者希望降低类之间的耦合度,提高代码的灵活性,那么对象适配器模式更为合适。


http://www.niftyadmin.cn/n/5845723.html

相关文章

1.6 学习测试用例(Test)分为几步?

文章目录 前言一、什么是UVM中的测试用例(Test)?二、如何理解UVM中的测试用例?三、如何使用UVM中的测试用例?四、实操代码示例4.1代码结构4.2 代码实现4.2.1 a. 测试用例类的定义和实现4.2.2 b. 测试环境的构建和配置4…

论文阅读--LlaVA

数据 使用GPT-4,根据现有的图片对数据(image-pair data)收集指令跟随数据。作者团队收集了158,000个独特的语言-图像指令遵循样本,其中包括58,000个对话样本、23,000个详细描述样本和77,000个复杂推理样本 以图像描述为例&#x…

【4】思科 SD-WAN 的控制平面

1. 概述 在 SD-WAN 架构中,控制平面(Control Plane)负责管理数据平面的流量转发决策,并确保网络设备能够高效地进行路径选择和策略执行。思科 SD-WAN 的控制平面主要由 vSmart 控制器 组成,它负责维护全网的路由、策略和安全控制。 控制平面与数据平面分离,使得网络可以…

基于logback+fastjson实现日志脱敏

一、需求背景 日常工作中,必不可免的会将一些敏感信息,如用户名、密码、手机号、身份证号、银行账号等等打印出来,但往往为了安全,这些信息都需要进行脱敏。脱敏实际就是用一些特殊字符来替换部分值。 JSON 和 JSONObject Fastj…

nodejs - vue 视频切片上传,本地正常,线上环境导致磁盘爆满bug

nodejs 视频切片上传,本地正常,线上环境导致磁盘爆满bug 原因: 然后在每隔一分钟执行du -sh ls ,发现文件变得越来越大,即文件下的mp4文件越来越大 最后导致磁盘直接爆满 排查原因 1、尝试将m3u8文件夹下的所有视…

Rust语言的嵌入式系统

Rust语言在嵌入式系统中的应用 引言 在现代科技快速发展的背景下,嵌入式系统作为重要的组成部分,广泛应用于工业自动化、消费电子、智能家居、汽车电子等多个领域。随着设备的智能化和网络化,开发者对嵌入式系统的安全性和可靠性提出了更高…

【学术投稿-第五届消费电子与计算机工程国际学术会议】HTML核心元素详解:超链接、列表、表格与实用技巧

基本信息 大会官网:www.iccece.org 线下召开时间:2025年2月28-3月2日 目录 前言 一、超链接:连接万物的桥梁 1. 基础语法 2. 高级应用 3.代码案例​编辑 4. 注意事项 二、列表:结构化内容的利器 1. 有序列表(O…

2025考研查分时间,公布!

年关将至,截止目前,已有6个省市公布2025考研初试成绩查询时间。 综合往年情况来看,查分时间一般在2月底。去年各省市的考研初试的查分时间集中安排在2月26日,但2025年考研初试时间较往年提前2天,在目前已经公布查分时…