我所理解的设计模式(C++实现)——适配器模式(Adapter Pattern)

2023-11-01

解决的问题:

适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作。比如说我的hp笔记本,美国产品,人家美国的电压是110V的,而我们中国的电压是220V,要在中国能使用,必须找个变压器转一下电压才可以。这个变压器就是个适配器。

适配器模式有类适配器和对象适配器两种模式,我们将分别讨论。


类适配器:

由图中可以看出,Adaptee类没有Request方法,而客户期待这个方法。为了使客户能够使用Adaptee类,提供一个中间环节,即类Adapter类,Adapter类实现了Target接口,并继承自AdapteeAdapter类的Request方法重新封装了AdapteeSpecificRequest方法,实现了适配的目的。

因为AdapterAdaptee是继承的关系,所以这决定了这个适配器模式是类的。

该适配器模式所涉及的角色包括:

目标(Target)角色:这是客户所期待的接口。因为C#不支持多继承,所以Target必须是接口,不可以是类。
源(Adaptee)角色:需要适配的类。
适配器(Adapter)角色:把源接口转换成目标接口。这一角色必须是类

    简单实现:

#include<iostream>
using namespace std;

// "ITarget"
class Target
{
public:
	// Methods
	virtual void Request(){};
};

// "Adaptee"
class Adaptee
{
public:
	// Methods
	void SpecificRequest()
	{
		cout<<"Called SpecificRequest()"<<endl;
	}
};

// "Adapter"
class Adapter : public Adaptee, public Target
{
public:
	// Implements ITarget interface
	void Request()
	{
		// Possibly do some data manipulation
		// and then call SpecificRequest  
		this->SpecificRequest();
	}
};


int main()
{
	// Create adapter and place a request
	Target *t = new Adapter();
	t->Request();

	return 0;
}

对象适配器:

从图中可以看出:客户端需要调用Request方法,而Adaptee没有该方法,为了使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而将客户端与Adaptee衔接起来。由于AdapterAdaptee是委派关系,这决定了这个适配器模式是对象的。

该适配器模式所涉及的角色包括:

目标(Target)角色:这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
源(Adaptee)角色:需要适配的类。
适配器(Adapter)角色:通过在内部包装(Wrap)一个Adaptee对象,把源接口转换成目标接口。

简单实现:

#include<iostream>
using namespace std;

// "ITarget"
class Target
{
public:
	// Methods
	virtual void Request(){};
};

// "Adaptee"
class Adaptee
{
public:
	// Methods
	void SpecificRequest()
	{
		cout<<"Called SpecificRequest()"<<endl;
	}
};

// "Adapter"
class Adapter : public Target
{
private:
	Adaptee *adaptee;

public:
	Adapter()
	{
		adaptee = new Adaptee();
	}

	// Implements ITarget interface
	void Request()
	{
		// Possibly do some data manipulation
		// and then call SpecificRequest  
		adaptee->SpecificRequest();
	}
};


int main()
{
	// Create adapter and place a request
	Target *t = new Adapter();
	t->Request();

	return 0;
}

缺省适配器:

缺省适配器模式是一种特殊的适配器模式,但这个适配器是由一个抽象类实现的,并且在抽象类中要实现目标接口中所规定的所有方法,但很多方法的实现都是平庸的实现,也就是说,这些方法都是空方法。而具体的子类都要继承此抽象类。 

简单实现:

#include<iostream>
using namespace std;


class Target { 
public:
	virtual void f1(){}; 
	virtual void f2(){}; 
	virtual void f3(){};   
};

class DefaultAdapter : public Target 
{ 
public:
    void f1() { 
    } 

    void f2() { 
    } 

    void f3() { 
    } 
};

class MyInteresting :public DefaultAdapter
{ 
public:
     void f3(){       
		cout<<"呵呵,我就对f3()方法感兴趣,别的不管了!"<<endl;
    } 
};

int main()
{
	// Create adapter and place a request
	Target *t = new MyInteresting();
	t->f3();

	return 0;
}


实现要点:

1.Adapter模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况,在遗留代码复用、类库迁移等方面非常有用

2Adapter模式有对象适配器和类适配器两种形式的实现结构,但是类适配器采用多继承的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用对象组合的方式,更符合松耦合精神。

3Adapter模式的实现可以非常的灵活,不必拘泥于GOF23中定义的两种结构。例如,完全可以将Adapter模式中的现存对象作为新的接口方法参数,来达到适配的目的。

4Adapter模式本身要求我们尽可能地使用面向接口的编程风格,这样才能在后期很方便的适配


使用场景:

在以下各种情况下使用适配器模式:

1.系统需要使用现有的类,而此类的接口不符合系统的需要。

2.想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。这些源类不一定有很复杂的接口。

3.(对对象适配器而言)在设计里,需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。


LCL_data原创于CSDN.NET【http://blog.csdn.net/lcl_data/article/details/8780140


参考资料:

1.http://www.cnblogs.com/zhenyulu/articles/39386.html

2.http://www.cnblogs.com/Terrylee/archive/2006/02/18/333000.html


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我所理解的设计模式(C++实现)——适配器模式(Adapter Pattern) 的相关文章

  • 如何从字符串中提取子字符串直到遇到第二个空格?

    我有一个像这样的字符串 o1 1232 5467 1232 5467 1232 5467 1232 5467 1232 5467 1232 5467 如何仅提取 o1 1232 5467 要提取的字符数并不总是相同 因此 我只想提取直到遇到
  • 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争

    我有以下逻辑 public void InQueueTable DataTable Table int incomingRows Table Rows Count if incomingRows gt RowsThreshold async
  • 无法继承形状

    为什么我不能使用继承 a 的类Shapes class http msdn microsoft com en us library ms604615 28v vs 90 29 我需要延长Rectangle具有一些方法的类 但我想以与使用相同
  • 在 C++ 代码中转换字符串

    我正在学习 C 并开发一个项目来练习 但现在我想在代码中转换一个变量 字符串 就像这样 用户有一个包含 C 代码的文件 但我希望我的程序读取该文件并插入将其写入代码中 如下所示 include
  • 在 Mono 中反序列化 JSON 数据

    使用 Monodroid 时 是否有一种简单的方法可以将简单的 JSON 字符串反序列化为 NET 对象 System Json 只提供序列化 不提供反序列化 我尝试过的各种第三方库都会导致 Mono Monodroid 出现问题 谢谢 f
  • 如何修复错误:“检测到无法访问的代码”

    我有以下代码 private string GetAnswer private int CountLeapYears DateTime startDate return count String answer GetAnswer Respo
  • MVC 5 中具有 ASP.NET Identity 的 Autofac 不会验证 OWIN 管道中的安全标记

    我在 MVC 5 中设置了 AutoFac 来与 ASP NET Identity 一起使用 表面上一切似乎都工作正常 即用户可以创建帐户并登录 但后来我发现 当安全标记更改时 用户不会注销 通过在 AspNetUsers 表中进行暴力破解
  • 为什么这个 makefile 在“make clean”上执行目标

    这是我当前的 makefile CXX g CXXFLAGS Wall O3 LDFLAGS TARGET testcpp SRCS main cpp object cpp foo cpp OBJS SRCS cpp o DEPS SRCS
  • JavaScript 错误:MVC2 视图中的条件编译已关闭

    我试图在 MVC2 视图页面中单击时调用 JavaScript 函数 a href Select a JavaScript 函数 function SelectBenefit id code alert id alert code 这里 b
  • C# 根据当前日期传递日期时间值

    我正在尝试根据 sql server 中的两个日期获取记录 Select from table where CreatedDate between StartDate and EndDate我通过了5 12 2010 and 5 12 20
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 如何在多线程应用程序中安全地填充数据并 Refresh() DataGridView?

    我的应用程序有一个 DataGridView 对象和一个 MousePos 类型的列表 MousePos 是一个自定义类 它保存鼠标 X Y 坐标 类型为 Point 和该位置的运行计数 我有一个线程 System Timers Timer
  • MySQL 连接器 C++ 64 位在 Visual Studio 2012 中从源代码构建

    我正在尝试建立mySQL 连接器 C 从源头在视觉工作室2012为了64 bit建筑学 我知道这取决于一些boost头文件和C 连接器 跑步CMake生成一个项目文件 但该项目文件无法编译 因为有一大堆非常令人困惑的错误 这些错误可能与包含
  • SQLAPI++ 的免费替代品? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有任何免费 也许是开源 的替代品SQLAPI http www sqlapi com 这个库看起来
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 以编程方式创建 Blob 存储容器

    我有一个要求 即在创建公司时 在我的 storageaccount 中创建关联的 blob 存储容器 并将容器名称设置为传入的字符串变量 我已尝试以下操作 public void AddCompanyStorage string subDo
  • Xamarin Forms Binding - 访问父属性

    我无法访问页面的 ViewModel 属性以便将其绑定到 IsVisible 属性 如果我不设置 BindingContext 我只能绑定它 有没有办法可以在设置 BindingContext 的同时访问页面的 viewmodel root
  • 调用 .ToArray() 时出现 ArgumentException

    我有一个经常被清除的列表 代码完全是这样的 VisitorAgent toPersist List
  • C++ 指针引用混淆

    struct leaf int data leaf l leaf r struct leaf p void tree findparent int n int found leaf parent 这是 BST 的一段代码 我想问一下 为什么
  • 如何为有时异步的操作创建和实现接口

    假设我有数百个类 它们使用 计算 方法实现公共接口 一些类将执行异步 例如读取文件 而实现相同接口的其他类将执行同步代码 例如将两个数字相加 为了维护和性能 对此进行编码的好方法是什么 到目前为止我读到的帖子总是建议将异步 等待方法冒泡给调

随机推荐

  • UE4 全局变量的应用(蓝图)

    4 20 1 创建全局变量 命名为MyGameInstance 2 创建一个变量 命名为MyB 3 在项目设置中 搜索GameInstence 并选中创建的全局变量 4 在蓝图里调用全局变量 5 成功打印
  • Tmux使用教程

    Tmux 是一款可以管理会话和分屏的终端复用器 在远程 SSH 断开后可以继续执行任务 重新连接后再继续会话 也能够将进程放到后台运行 需要时重新接管 为了防止 SSH 因网络断开造成的进程运行中断 推荐把所有需要长期运行的训练等任务都使用
  • 提升效率之如何打印出漂亮的带颜色的日志(输出高亮)

    花里胡哨的日志 1 花里胡哨的shell打印 2 c语言日志的彩色输出 日志系统对于一个软件的维护是很重要的 对于直接在本地打印的信息 可能包含非常多 如何才能快速发现自己想要打印的东西呢 带上颜色的输出 绝对是很好的选择 使用c c 的输
  • 二、网络编程之协议及协议格式详解

    引言 在网络编程中 我经常听人提起过协议 标准协议 协议族 TCP协议 传输层协议 诸如此类的协议概念 这些种类繁多的名词听着让人感觉头晕 所以今天继续学习和总结协议的相关知识 在前面一篇文章 网络编程之基础知识详解 中已经简单介绍过协议
  • vue3中使用echart多个图表,并且可以随着屏幕大小自适应布局

    一 在项目中安装echarts npm install echarts save 二 引入echarts 1 因为多个地方需要使用到这个echart图表 所以将这个echarts写在自定义组件中 子组件 chart vue div clas
  • Linux进程控制编程实验_02

    任务1 编写一个进程创建实验程序task51 c 创建如图所示的进程族亲结构 其中p1是程序启动时由加载程序创建第一个进程 各进程的输出信息分别如下 p1 I am father process p11 当前时间是 lt 年 月 日 时 分
  • Eclipse CDT c++支持C++11

    最近要在Linux 环境下面写一些代码 需要支持C 11 可是CDT 不认识C 11的特性 看了很多网上的配置资料 各种版本下面还是不一样 Eclipse 16 04 CDT 9 4 GCC 5 4 首先创建一个C project 写点C
  • mysql知识系列:用命令行远程登录Mysql

    参考 命令行登录Mysql 远程登录Mysql的方法 总结 mysql uxxx pxxx hxxx xxx xxx xxx P3306 xxx 为替换的内容
  • Python 基础合集8:类的继承和多态

    一 前言 本小节主要梳理类的继承和多态 继承包含三种形式 单继承 多层继承 多重继承 环境说明 Python 3 6 windows11 64位 二 继承 基础语法如下 class B A 表示的含义就是B 继承A A 是B 的父类 cla
  • 把数据插入到数据库的两种方法

    把表单中的数据插入到数据库中有两种方法 1 直接使用sql语句的 优点 速度快 不耗资源 缺点 不能传递太长的字段内容 字段比较多时不易排错 推荐有经验的编程者优先考虑 具体操作 假设表单中有以下字段 username password s
  • 阿里云免费试用服务器,怎么申请

    免费试用也要分个人用户和企业用户 个人用户选择比较少 目前只有下面这个配置 免费试用3个月 企业用户有4款机型 一 参与对象 满足以下全部条件的阿里云用户 1 阿里云注册会员用户 可以联系我注册账号 这样试用以后如果要新购也可以有优惠 2
  • 微信小程序调用天气信息

    在微信小程序中调用天气信息 下面是示例代码 wx request url example php 仅为示例 并非真实的接口地址 data x y header content type application json 默认值 succes
  • jdk和tomcat的关系

    1 什么是jvm 我们从操作系统的层面来理解 jvm其实就是操作系统中的一个进程 既然是一个进程 那么我们很容易的可以通过任务管理器来查看 假设此时我们启动myeclipse myeclipse其实就是用java语言编写的一个软件 他的运行
  • Java定时任务调度工具详解之Quartz篇(中级)一:浅谈JobExecutionContext&JobDatai&浅谈Trigger

    概要 OpenSymphony提供的强大的开源任务调度框架 官网 http www quartz scheduler org 纯java实现 精细控制排程 特点 强大的调度功能 灵活的应用方式 分布式和集群能力 主要用到的设计模式 Buil
  • 微信小程序+java后台+云服务器开发学习记录

    仅作为个人学习记录 1 使用了iview辅助开发 2 开发后台时 访问jsp和servlet突然404 检查以后发现8080端口被以前没清理干净的java程序占用了 到任务管理器里把java exe干掉以后重启idea一切恢复正常 困扰了我
  • 100流明相当于多少w_lx和瓦数换算(1lx等于多少w)

    你好 别想太多了 这个没得换算的所谓能换算的 都是已知光效的灯 就是每瓦多少流明的 然后再通过受照面积换算 希望对你有所帮助 望采纳 白炽灯的瓦数 光照强度 10W 65lm 15W 101lm 25W 198lm 40W 340lm 60
  • 身边那些百万年薪的程序员朋友

    大家好 我是寂小桦 争取每周在这里给大家分享自己作为独立开发者经历以及身边程序员朋友的趣事 百万年薪是个永远说不烂的话题 就在最近的一年 仿佛雨后春笋一般 身边开始涌现出很多年薪百万的程序员朋友 清一色集中在腾讯阿里京东头条这些公司 其中一
  • 数字电路的时钟(3)-- 抖动

    引言 抖动是时钟信号边沿事件的时间点集合相对于其理想值的离散时序变量 时钟信号中的抖动通常是由系统中的噪声或其他干扰导致的 具体因素包括热噪声 电源变化 负载条件 器件噪声以及相邻电路耦合的干扰等 抖动类型 时钟信号抖动定义有多种主要是 周
  • IDEA的Junit安装(添加jar包)

    1 安装junit插件 1 打开IDEA 点击文件 选择设置 setting 2 选择Plugins gt 点击Browse repositories 3 在搜索框中搜索Junit gt 找到Junit Generator V2 0点击 g
  • 我所理解的设计模式(C++实现)——适配器模式(Adapter Pattern)

    解决的问题 适配器模式把一个类的接口变换成客户端所期待的另一种接口 从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作 比如说我的hp笔记本 美国产品 人家美国的电压是110V的 而我们中国的电压是220V 要在中国能使用 必须找个