当前位置: 首页 > news >正文

【设计模式】适配器模式(Adapter)

目录

一、问题导入

二、结构解析

1.示例问题

2.类适配器(Class Adapter)

3.对象适配器(Object Adapter)

4.默认适配器(Default Adapter)

5.结构成分

三、优劣


前言:大家可能会发现有些地方我会使用删除线这并不是因为内容不重要。因为老师的课件并没有这样的拓展解释,而且其课件内容本身也并不一定完全正确,但是为了方便看课件复习的同学,就将课件以外的内容使用了删除线进行处理。此外,我个人认为老师的课件例子有些并不能完全体现对应设计模式的特点,所以会进行相应的修改。最后呢,对于只是为了应付课程的同学而言,代码部分可能并不是很重要,建议根据自身情况自行使用。有些地方如果存在错误,也希望大家能够指正,我会尽快修改。

Tips:对于这篇而言,三种适配器的实现方式老师并没有展开去讲

一、问题导入

在现实生活中,插座提供的是 220V 交流电,而手机充电需要的是 5V 左右的低压直流电,两者无法直接兼容。我们用的 “充电头” 会先把交流电转换成直流电,再把电压降到手机能接受的范围,最终实现安全充电。

这个帮不同设备 “搭桥” 的充电头,其实就是 “适配器” 的典型例子,而设计模式里的适配器模式解决的也是类似问题。

二、结构解析

1.示例问题

在游戏数值的设计当中,离不开一系列的配置信息。就比如经典的塔防游戏,防御塔的等级、攻击范围、攻击伤害等都是需要进行灵活的调整的,这些不能够在程序中写死,那么这些都将以文件格式给出。但是,策划可能提供给我们不同格式的文件,包含但不限于XML和JSON。那么作为程序的编写者,我们需要通过适配器模式,将这些不同格式的文件读入逻辑统一起来,让上层代码无需关心具体格式,只需调用统一的接口获取防御塔配置信息。

那么,我们接下来的核心目标就是定义一个统一的配置读取接口(ConfigReader),然后通过三种适配器模式,分别将XML读取器和JSON读取器适配到这个统一接口,使上层代码无需修改就能兼容不同格式。

这里有三种实现方式
(1)类适配器(Class Adapter)

(2)对象适配器(Object Adapter)

(3)默认适配器(Default Adapter)

2.类适配器(Class Adapter)

通过多继承分别实现两个类适配器(XML 适配器和 JSON 适配器),都遵循FileReader接口

#pragma once#include<iostream>namespace _ClassAdapterPattern
{ //文件读取(目标接口)class FileReader{public:FileReader() = default;~FileReader() = default;virtual int get_tower_level()const = 0;virtual int get_hit_range()const = 0;virtual int get_attack_power()const = 0;};//XML解析器和JSON解析器(被适配者)class XMLParser{public:XMLParser() = default;~XMLParser() = default;int get_tower_level()const{ return 1; }int get_hit_range()const{ return 1; }int get_attack_power()const{ return 1; };};class JSONParser{public:JSONParser() = default;~JSONParser() = default;int get_tower_level()const{ return 2; }int get_hit_range()const{ return 2; }int get_attack_power()const{ return 2; };};//提供XML适配器和JSON适配器(适配器,通过类继承实现)class XMLAdapter:public FileReader,public XMLParser{public:XMLAdapter() = default;~XMLAdapter() = default;int get_tower_level()const override{ return XMLParser::get_tower_level(); }int get_hit_range()const override{ return XMLParser::get_hit_range(); }int get_attack_power()const override{ return XMLParser::get_attack_power(); }};class JSONAdapter:public FileReader,public JSONParser{public:JSONAdapter() = default;~JSONAdapter() = default;int get_tower_level()const override{ return JSONParser::get_tower_level(); }int get_hit_range()const override{ return JSONParser::get_hit_range(); }int get_attack_power()const override{ return JSONParser::get_attack_power(); }};void print_tower_config(FileReader* reader){std::cout << "防御塔等级:	" << reader->get_tower_level() << std::endl;std::cout << "攻击范围:	" << reader->get_hit_range() << std::endl;std::cout << "攻击伤害:	" << reader->get_attack_power() << std::endl;}void test(){FileReader*xml_reader = new XMLAdapter();FileReader*json_reader = new JSONAdapter();print_tower_config(xml_reader);print_tower_config(json_reader);}}

3.对象适配器(Object Adapter)

通过 “实现接口 + 持有对象” 的方式,分别创建 XML 和 JSON 的对象适配器,共用FileReader接口。

#pragma once
#include<iostream>namespace _ObjectAdapterPattern
{//文件读取(目标接口)class FileReader{public:FileReader() = default;~FileReader() = default;virtual int get_tower_level()const = 0;virtual int get_hit_range()const = 0;virtual int get_attack_power()const = 0;};//XML解析器和JSON解析器(被适配者)class XMLParser{public:XMLParser() = default;~XMLParser() = default;int get_tower_level()const { return 1; }int get_hit_range()const { return 1; }int get_attack_power()const { return 1; };};class JSONParser{public:JSONParser() = default;~JSONParser() = default;int get_tower_level()const { return 2; }int get_hit_range()const { return 2; }int get_attack_power()const { return 2; };};//提供XML适配器和JSON适配器(适配器,通过包含对象实现)class XMLAdapter :public FileReader{private:XMLParser* xml_parser;public:XMLAdapter(XMLParser*parser){ xml_parser = parser;}~XMLAdapter() = default;int get_tower_level()const override { return xml_parser->get_tower_level(); }int get_hit_range()const override { return xml_parser->get_hit_range(); }int get_attack_power()const override { return xml_parser->get_attack_power(); }};class JSONAdapter :public FileReader{private:JSONParser* json_parser;public:JSONAdapter(JSONParser*parser){ json_parser = parser;}~JSONAdapter() = default;int get_tower_level()const override { return json_parser->get_tower_level(); }int get_hit_range()const override { return json_parser->get_hit_range(); }int get_attack_power()const override { return json_parser->get_attack_power(); }};void print_tower_config(FileReader* reader){std::cout << "防御塔等级:	" << reader->get_tower_level() << std::endl;std::cout << "攻击范围:	" << reader->get_hit_range() << std::endl;std::cout << "攻击伤害:	" << reader->get_attack_power() << std::endl;}void test(){XMLParser* xml_parser = new XMLParser();JSONParser* json_parser = new JSONParser();XMLAdapter* xml_adapter = new XMLAdapter(xml_parser);JSONAdapter* json_adapter = new JSONAdapter(json_parser);print_tower_config(xml_adapter);print_tower_config(json_adapter);}
}

4.默认适配器(Default Adapter)

当接口方法增多时,用默认适配器简化适配过程(当目标接口新增方法(如get_place_cost,XML 解析器因不支持该字段,无需修改适配器代码(直接复用默认适配器的 0 值),而 JSON 适配器只需重写新增方法即可)

#pragma once#include<iostream>namespace _DefaultAdapterPattern
{//文件读取(目标接口)class FileReader{public:FileReader() = default;~FileReader() = default;virtual int get_tower_level()const = 0;virtual int get_hit_range()const = 0;virtual int get_attack_power()const = 0;virtual int get_place_cost()const = 0;};//默认适配器class DefaultAdapter :public FileReader{public:DefaultAdapter() = default;~DefaultAdapter() = default;int get_tower_level()const override { return 0; }int get_hit_range()const override { return 0; }int get_attack_power()const override { return 0; }int get_place_cost()const override { return 0; }};//XML解析器和JSON解析器(被适配者)class XMLParser{public:XMLParser() = default;~XMLParser() = default;int get_tower_level()const { return 1; }int get_hit_range()const { return 1; }int get_attack_power()const { return 1; };};class JSONParser{public:JSONParser() = default;~JSONParser() = default;int get_tower_level()const { return 2; }int get_hit_range()const { return 2; }int get_attack_power()const { return 2; };int get_place_cost()const { return 20; };};//提供XML适配器和JSON适配器(适配器,通过包含对象实现)class XMLAdapter :public DefaultAdapter{private:XMLParser* xml_parser;public:XMLAdapter(XMLParser* parser) { xml_parser = parser; }~XMLAdapter() = default;int get_tower_level()const override { return xml_parser->get_tower_level(); }int get_hit_range()const override { return xml_parser->get_hit_range(); }int get_attack_power()const override { return xml_parser->get_attack_power(); }};class JSONAdapter :public DefaultAdapter{private:JSONParser* json_parser;public:JSONAdapter(JSONParser* parser) { json_parser = parser; }~JSONAdapter() = default;int get_tower_level()const override { return json_parser->get_tower_level(); }int get_hit_range()const override { return json_parser->get_hit_range(); }int get_attack_power()const override { return json_parser->get_attack_power(); }int get_place_cost()const override { return json_parser->get_place_cost(); }};void print_tower_config(DefaultAdapter* reader){std::cout << "防御塔等级:	" << reader->get_tower_level() << std::endl;std::cout << "攻击范围:	" << reader->get_hit_range() << std::endl;std::cout << "攻击伤害:	" << reader->get_attack_power() << std::endl;std::cout << "放置费用:	" << reader->get_place_cost() << std::endl;}void test(){XMLParser* xml_parser = new XMLParser();XMLAdapter* xml_adapter = new XMLAdapter(xml_parser);print_tower_config(xml_adapter);JSONParser* json_parser = new JSONParser();JSONAdapter* json_adapter = new JSONAdapter(json_parser);print_tower_config(json_adapter);}
}

5.结构成分

可以很清楚的看到,适配器模式主要由三部分构成:

(1)目标接口:比如文件读取FileReader

(2)源接口:比如XMLParser和JSONParser

(3)适配器:比如XMLAdapter和JSONAdapter

三、优劣

优势:

(1)可使任意两个不相关的类协作运行

        (适配器的核心价值就是通过转换接口,让原本因接口不兼容而无法协作的类(如XMLParserFileReader)能够协同工作)

(2)提升类的复用性

        (被适配者(如XMLParser)无需修改即可通过适配器复用在新场景中,避免重复开发。)

(3)增加类的透明性

        (对上层代码屏蔽适配细节,即客户端只需关注目标接口(FileReader),无需知道底层是 XML 还是 JSON 解析,降低认知成本。)

(4)灵活性好

        (更适用于对象适配器(通过组合可动态切换被适配者),类适配器因多继承耦合度高,灵活性稍弱。通过适配器隔离接口变化,降低系统修改成本。)

劣势:

(1)过度使用适配器会使系统变得非常混乱,难以从整体上把握

        (过多的适配器会增加系统层级和理解成本,建议在接口设计初期规划统一标准,减少适配需求)

(2)最多只能适配一个适配者类,且目标类必须使抽象类

(此描述不准确,存在两点问题:

        ①适配器可以适配多个被适配者(如通过组合多个解析器对象实现复杂适配),并非 “最多一个”;

       ② 目标类可以是接口(如FileReader是纯虚类,即接口),而非必须是 “抽象类”(抽象类可包含非纯虚方法)。更合适的表述是:“类适配器受限于多继承特性(如 C++ 中),只能适配特定的被适配者类,灵活性低于对象适配器;且目标接口通常需要是纯虚类(接口)才能保证适配的统一性”。)

http://www.dtcms.com/a/515574.html

相关文章:

  • docker安装中间件
  • 系统架构设计师备考第48天——机器人边缘计算
  • 门头沟高端网站建设阿里云服务器win系统建站教程
  • ui设计培训机构哪个比较好cpu优化软件
  • 计算机运算中的上溢、下溢是什么?
  • 别再滥用 new/delete
  • 自己做网站的视频做网站不实名认证可以吗
  • Vertical Semiconductor融资1100万美元
  • 坐标系旋转(四元数 + 欧拉角 + 轴角表示 +旋转矩阵)
  • 发刊词:开启你的高效决策之旅(专栏目录)
  • D触发器学习
  • 汶上云速网站建设wordpress多域名支持
  • C++(23):contains检查字符串是否包含子字符串
  • 23.UE-游戏逆向-寻找骨骼坐标
  • Python 图片转 PDF 详解:单张、多张及多图片格式转换
  • 深圳展示型网站建设佛山seo优化代理
  • AI研究-110 DeepSeek-OCR 原理剖析|上下文光学压缩、Gundam 动态分辨率与并发预期 附代码
  • Easyx图形库应用(mcu+lua vs plc+st)
  • 【计算机网络笔记】第一章 计算机网络导论
  • AI搜索驱动的品牌传播变革:品牌如何在“被搜索”转向“被理解”的浪潮中重构增长力
  • 秦皇岛网站建设哪家好医疗软件公司排名
  • 将 Flask 应用迁移到 AWS Lambda:服务监控电话告警系统实战
  • PyTorch入门
  • Redis的Hash数据结构底层实现
  • AWS Lambda 预置并发配置实战分析
  • Biu懂AI:使用LangChain将Astra MCP接入LLM
  • 做租号玩网站赚钱吗wordpress tag标签
  • 安全补丁还是自造DDoS?微软更新导致关键企业功能瘫痪
  • TorchRL 安装记录(亲测有效)
  • 网站建设教程资源wordpress有插件怎么用