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

目录

一、问题导入

二、结构解析

1.示例问题

[2.类适配器(Class Adapter)](#2.类适配器(Class Adapter))

[3.对象适配器(Object Adapter)](#3.对象适配器(Object Adapter))

[4.默认适配器(Default 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接口

cpp 复制代码
#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接口。

cpp 复制代码
#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 适配器只需重写新增方法即可)

cpp 复制代码
#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++ 中),只能适配特定的被适配者类,灵活性低于对象适配器;且目标接口通常需要是纯虚类(接口)才能保证适配的统一性"。)

相关推荐
在未来等你1 天前
AI Agent设计模式 Day 5:Reflexion模式:自我反思与持续改进
设计模式·llm·react·ai agent·plan-and-execute
程序员三藏1 天前
快速弄懂POM设计模式
自动化测试·软件测试·python·selenium·测试工具·设计模式·职场和发展
Lei_3359671 天前
[設計模式]設計模式的作用
设计模式
将编程培养成爱好1 天前
C++ 设计模式《统计辅助功能》
开发语言·c++·设计模式·访问者模式
乙己4071 天前
设计模式——桥接模式(bridge)
设计模式·桥接模式
WKP94182 天前
原型设计模式
java·设计模式
guangzan2 天前
常用设计模式:工厂方法模式
设计模式
桦说编程2 天前
Guava 迭代器增强类介绍
java·后端·设计模式
李宥小哥2 天前
创建型设计模式1
stm32·嵌入式硬件·设计模式