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

一、为何需要适配器模式(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();
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/244491.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DNSLog漏洞探测(七)之SQL注入漏洞实战

DNSLog漏洞探测(七)之SQL注入漏洞实战 在前面的文章之中,我们已经学习了XSS、RCE、XXE、SSRF漏洞中有关于DNSLog平台的使用。这些漏洞本身在执行时就有解析URL地址,发起网络请求的操作,所以只要我们把DNSLog平台获取的子域名地址发送到存在漏…

优化钢铁加工:RFID技术的革新应用

优化钢铁加工:RFID技术的革新应用 RFID是一种无线通信技术,通过将标签上的电子数据以无线电信号的形式传输,实现对物品的远程识别和跟踪。在钢铁加工领域,RFID技术的应用能够提高生产效率、降低成本并优化物流管理。本文将探讨RF…

DevOps 和人工智能 – 天作之合

如今,人工智能和机器学习无处不在,所以它们开始在 DevOps 领域崭露头角也毫不令人意外。人工智能和机器学习正在通过自动化任务改变 DevOps,并使各企业的软件开发生命周期更高效、更深刻和更安全。我们在 DevOps 趋势中简要讨论过这一问题&am…

【Hive】——DDL(DATABASE)

1 概述 2 创建数据库 create database if not exists test_database comment "this is my first db" with dbproperties (createdByAllen);3 描述数据库信息 describe 可以简写为desc extended 可以展示更多信息 describe database test_database; describe databa…

有意思!40小时工作制来了,996再见

​在中国,加班文化已经深入人心。工资越高加班越多,“996”已成为一些行业标签,月薪30k以上的职场人中超过86%经常加班。所以今天我就来说一下这40小时工作制到底是从何而来,感兴趣的往下看看吧! 40小时工…

【Hive_02】查询语法

1、基础语法2、基本查询(Select…From)2.1 全表和特定列查询2.2 列别名2.3 Limit语句2.4 Where语句2.5 关系运算函数2.6 逻辑运算函数2.7 聚合函数 3、分组3.1 Group By语句3.2 Having语句3.3 Join语句(1)等值与不等值Join&#x…

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 NLP 部分

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 NLP 部分 概述NLP 简介文本处理词嵌入上下文理解 文本数据加载to_device 函数构造数据加载样本数量 len获取样本 getitem 分词构造函数调用函数轮次嵌入 RobertaRoberta 创新点NSP (Next Sentence Prediction…

uniapp原生插件之安卓动态权限申请原生插件

插件介绍 安卓动态权限申请原生插件,集成了常用的权限申请,可以自定义权限申请 该插件为原生开发,如果您想使用UTS版本可以点击这里 插件地址 安卓动态权限申请原生插件,支持常用的权限申请,支持自定义权限申请 - DC…

CleanMyMac X2024中文版好不好用?有哪些特点

CleanMyMac X您的 Mac。极速如新。点按一下,即可优化调整整个 Mac畅享智能扫描 — 这款超级简单的工具用于优化您的 Mac。只需点按一下,即可运行所有任务,让您的 Mac 保持干净、快速并得到最佳防护。CleanMyMac 是一款功能强大的 Mac 清理程序…

【网络安全】Suspicious DNS Query(可疑的DNS查询)

文章目录 名词解释可能原因分析Action sinkhole在防火墙里面查询Suspicious DNS Query预防Suspicious DNS查询带来的风险推荐阅读 名词解释 “Suspicious DNS Query(可疑的DNS查询)”通常指的是在网络中检测到的可能具有风险或异常行为的DNS&#xff08…

【数据结构】栈和队列超详解!(Stack Queue)

文章目录 前言一、栈1、栈的基本概念2、栈的实现(数组实现)3、栈的基本操作3.1 栈的结构设计3.2 栈常见的基本函数接口 4、栈的实现4.1 初始化栈4.2 栈的销毁4.3 入栈4.4 出栈4.5 判空4.6 长度4.7 获取栈顶元素 完整代码Stack.hStack.cTest.c 二、队列1、…

点对点协议PPP

目录 一. PPP协议的特点1.1 PPP 协议应满足的需求1.2 PPP 协议的组成 二. PPP协议的帧格式2.1 PPP协议的透明传输2.1.1 同步传输2.1.2 异步传输 三. PPP协议的工作状态 \quad 一. PPP协议的特点 \quad \quad 用户到ISP的链路使用PPP协议 \quad \quad 1.1 PPP 协议应满足的需求 …

面试题:HashMap 为什么不能一边遍历一遍删除

文章目录 前言foreach 循环?HashMap 遍历集合并对集合元素进行 remove、put、add1、现象为什么会抛出这个异常呢?2、细究底层原理 前言 上面出现这样的原因是在使用 foreach 对 HashMap 进行遍历时,同时进行 put 赋值操作会有问题&#xff0c…

6-6 堆排序 分数 10

typedef int Datatype; typedef struct {Datatype* elem; int Length; }SqList; typedef SqList HeapType; void swap(int* a, int* b) {int tmp *a;*a *b;*b tmp; } //建大堆 //m: 结点个数 s: 待下调父结点下标 void HeapAdjust(HeapType H, int s, int m) {int child …

骨传导耳机和开放式耳机哪个对听力的损伤小一些?

先说结论,骨传导耳机对听力的损伤更小,并且更值得入手。 其实骨传导耳机也算开放式耳机的一种,开放式耳机中又包括了骨传导耳机和气传导耳机,与其说骨传导耳机和入耳式耳机,不如说是骨传导耳机和气传导耳机&#xff0…

代码随想Day36 | 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 这道题和前一天的射箭题目思想类似,用总区间个数-不重叠的区间个数等于需要去除的区间个数。首先对左边界排序,如果当前的左边界大于等于上一区间的右边界,则说明是一个不重叠的区间,否则,更新上一重…

基于Web的智慧城市实验室主页系统设计与实现论文

摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对实验室信息管理混乱,出错率高,信息安全性差&…

Layui实现自定义的table列悬停事件并气泡提示信息

1、概要 使用layui组件实现table的指定列悬停时提示信息&#xff0c;因为layui组件中没有鼠标悬停事件支持&#xff0c;所以需要结合js原生事件来实现这个功能&#xff0c;并结合layui的tips和列的templte属性气泡提示实现效果。 2、效果图 3、代码案例 <!DOCTYPE html&g…

Hdfs java API

1.在主机上启动hadoop sbin/start-all.sh 这里有一个小窍门&#xff0c;可以在本机上打开8088端口查看三台机器的连接状态&#xff0c;以及可以打开50070端口&#xff0c;查看hdfs文件状况。以我的主虚拟机为例&#xff0c;ip地址为192.168.198.200&#xff0c;所以可以采用下…

如何处理好面试中的“压力测试”?

作为一名求职者&#xff0c;在面试时有时遇到的是压力测试&#xff0c;有时则遇到的是一些无良企业单位&#xff0c;究竟如何把握忍耐的限度&#xff0c;才合格当一个能经受压力的员工&#xff0c;才能避免对无良单位的一味隐忍! 压力面试是指有意制造紧张&#xff0c;以了解求…