设计模式(三)-结构型模式(1)-适配器模式

news/2024/7/5 2:34:44

一、为何需要适配器模式(Adapter)?

在软件设计中,某个模块里有很多公用的功能接口,其中有些公用接口需要用到不同的类当中时,会出现接口不兼容的问题。因为这些不同的类对这个相同任务的接口,都有各自代码逻辑的要求。于是每当客户对这个接口提出新需求,就会再创建一个类,再把所有方法实现一遍,就显得代码很臃肿。为了解决这个问题,只改写需要适配的某个功能,就用到了适配器模式。

比如在文件操作的模块中,都有获取文件属性、读写文件操作等共同的功能接口。在原需求里,已存在保存 txt 文件的功能。当客户有新需求时,需要扩展保存图片文件的功能。这就出现了一个问题:保存 txt 文件和保存图片虽然都是保存操作的任务,但是实现的代码逻辑并不相同。


       //保存txt文件
        public void SaveFile()
        {
            StreamWriter sw = new StreamWriter("test.txt");
            sw.Write("HelloWorld!");
            sw.Dispose();
        }

        //保存图片文件
        public void SaveFile()
        {
            //data 里随便写的数据,不要太认真
            byte[] data = { 11,22,33,44,55};
            MemoryStream ms = new MemoryStream(data);

            Image img = Image.FromStream(ms);
            img.Save("test.jpeg", ImageFormat.Jpeg);
            ms.Dispose();
        }

//保存任务相同:SaveFile。但是实现的代码逻辑不同

特点:
将一个类的接口转换成客户希望的另外一个接口,以解决接口不兼容的问题。(这里的接口不是指 C# 中的 interface,而是一个功能接口)

结构:
目标(Target):定义 Client 需要使用的功能接口。
被适配(Adaptee):定义一些在 Target 已经存在且需要适配的功能接口。
适配器(Adapter):主要负责将 Adaptee 功能接口转换为跟 Target 匹配的功能接口。
客户(Client):使用做了兼容处理的功能接口。

适合应用场景特点:

  • 这个接口具有相同的任务。(比如所有类型的文件共有读写保存的功能接口。)
  • 需要适配相同任务但工作方式不同的接口。(比如不同类型文件保存的方式不同。)

主要两种适配器模式:

  • (1)对象适配器模式
    (处理指定某些功能接口不兼容的问题;Target 派生给 Adapter,Adapter 包装一个需要 Adaptee 的类实例。注重对象组合关系)
  • (2)类适配器模式
    (处理指定某些功能接口不兼容的问题;Target 派生给 Adapter, Adaptee 也派生给 Adapter,特点为多重继承。注重类之间的继承关系)

注:==在工作中推荐使用对象适配器模式。==因为如果使用类适配器,类继承关系就会使得代码结构紧耦合,修改某个基类时就会影响子类。而对象适配不仅满足用户期待的需求,还能降低代码之间的耦合性。

对象适配模式:

请添加图片描述

类适配模式:

请添加图片描述

二、例子

需求:

在迭代版本中,客户希望在保存文本文件功能的基础上,还想要增加对一个图片文件进行保存的功能。并且在将来,可能还会扩展对其他类型文件进行保存的功能。

1、对象适配器模式:


    //目标类:接口、抽象类、具体类都可作为目标
    public class FileOperateTarget
    {
        //保存文本文件
        public virtual void Request()
        {
            Console.WriteLine("Save a string content as the txt,xml,ini...");
        }

        //其他所有要实现的方法
        //(比如获取文件属性的方法,设置默认打开方式的方法等,都是任何类型文件共有的方法)...

        //如果存在代码逻辑不同的方法,则可由适配器模式进行处理。
        //(比如在此例子中,保存文件的方法)
    }

    //被适配类:保存图片文件
    public class ImageFileAdaptee
    {
        public virtual void SpecificRequest()
        {
            Console.WriteLine("Save a Image content as the Img File.");
        }
    }

    //适配器类:主要负责将 Adaptee 类对象进行组合来适配共同方法。
    public class ImageFileAdapter : FileOperateTarget
    {
        //包装一个被适配类的对象(Adaptee 对象)
        private ImageFileAdaptee imageFileAdaptee = new ImageFileAdaptee();
        public override void Request()
        {
            //适配功能的转换工作,把源接口 Request 转换成目标接口 SpecificRequest
            imageFileAdaptee.SpecificRequest();
        }
    }

    //Client
    class Program
    {
        static void Main(string[] args)
        {
            FileOperateTarget target = new ImageFileAdapter();
            target.Request();
            Console.ReadLine();
        }
    }

2、类适配器模式:


    //目标接口:由于在C# 中类只支持单继承,而接口可支持多重继承。所以目标只能是接口 
    public interface IFileOperateTarget
    {
        void Request();
    }

    //被适配类:保存图片文件
    public class ImageFileAdaptee
    {
        public virtual void SpecificRequest()
        {
            Console.WriteLine("Save a Image content as the Img File.");
        }
    }

    //适配器类:主要继承 Adaptee 类 和 Target 类,实现目标接口的转换。
    public class ImageFileAdapter : ImageFileAdaptee, IFileOperateTarget
    {
        public void Request()
        {
            //适配功能的转换工作
            this.SpecificRequest();
        }
    }

    //Client
    class Program
    {
        static void Main(string[] args)
        {
            IFileOperateTarget target = new ImageFileAdapter();
            target.Request();
            Console.ReadLine();
        }
    }

三、缺省适配器模式

  • 特殊的适配器模式,不是主要的模式;一般缺少 Adaptee 结构。
  • 专门处理指定某些功能接口不兼容的问题,而其他所有功能接口都出于未处理状态,即空方法。

请添加图片描述

缺省适配器模式:

    //目标接口
    public interface IFileOperateTarget
    {

        void Request();
        //其他抽象方法...
        void ReadFile();
        void GetFileInfo();
    }
   
    //适配器类:实现接口中抽象方法为空方法
    public class DefaultAdapter : IFileOperateTarget
    {
        public virtual void Request() { }
        public virtual void ReadFile() { }
        public virtual void GetFileInfo() { }
    }

    //Client
    public class ClientImage : DefaultAdapter
    {
        //只使用这个功能
        public override void Request()
        {
            Console.WriteLine("Save a Image content as the Img File.");
        }

        
    }

    //Client:以后有新需求时,可扩展此功能的代码逻辑
    public class ClientWord : DefaultAdapter
    {
        public override void Request()
        {
            Console.WriteLine("Save a Word content as the Word File.");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ClientImage clientImage = new ClientImage();
            clientImage.Request();

            ClientWord clientWord = new ClientWord();
            clientWord.Request();

            Console.ReadLine();
        }
    }


http://lihuaxi.xjx100.cn/news/1889739.html

相关文章

App防止恶意截屏功能的方法:iOS、Android和鸿蒙系统的实现方案

防止应用被截图是一个比较常见的需求,主要是出于安全考虑。下面将分别为iOS(苹果系统)、Android(安卓系统)及HarmonyOS(鸿蒙系统)提供防止截屏的方法和示例代码。 在企业内部使用的应用中&…

curl+postman 在java开发中的使用(提高效率)

概念 curl 是一个常用的命令行工具,用于发送各种类型的 HTTP 请求,包括 GET、POST、PUT、DELETE 等。它也可以用来下载文件、上传文件、设置 cookie、发送 multipart/form-data 等等。 使用 调用post接口 实际中的接口: curl --location…

MySQL线上死锁案例分析

项目场景 项目开发中有两张表:c_bill(账单表),c_bill_detail(账单明细表),他们的表结构如下(这里只保留必要信息): CREATE TABLE c_bill_detail (id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 主…

C# 从代码入门 Mysql 数据库事务

在业务开发中,使用数据库事务是必不可少的。而开发中往往会使用各种 ORM 执行数据库操作,简化代码复杂度,不过,由于各种 ORM 的封装特性,开发者的使用方式也不一样,开发者想要了解 ORM 对事务做了什么处理是…

薅github的羊毛-用pages建自己的博客或静态资源站 - 1/2

注册帐号 准备邮箱注册帐号,在注册界面输入用户名、邮箱及密码完成注册。 添加图片注释,不超过 140 字(可选) 1. 在注册成过程中,会往邮箱发送验证码,请如实填写即可 2. 验证码没错的话,就代…

leetcode --15 三数之和 【双指针 C++】

原题链接:15. 三数之和 - 力扣(LeetCode) 题目解析: 题目中说的不可以包含重复的三元组,从示例1可以看出[-1,0,1] 和[0,1,-1]虽然三个数顺序不同但是元素重复了,所以只选取其中一个。而本题难点也在于去重…

用Go汇编实现一个快速排序算法

本代码全网首发&#xff0c;使用Go plan9 windows arm64汇编&#xff0c;实现基础版快速排序算法。 未引入随机因子的快速排序的普通Go代码长这样。 func QuickSort(arr []int) {if len(arr) < 1 {return}base, l, r : arr[0], 0, len(arr)-1for i : 1; i < r; {if arr…

【Axure RP9】元件应用(图文并茂)----含登入,个人简历案例

目录 : 一&#xff0c;元件基本介绍 1.1 元件概述 1.2 元件操作 1.3 快捷键大全 二&#xff0c;基本元件的应用 2.1 形状 2.2 图片 2.3 文本 2.4 线段原件 2.5 热区 2.5.1 热区应用 三, 表单型元件的应用 3.1 文本框 3.2 文本域 3.3 下拉列表 3.4 列表框 3.5 …