c++常见设计模式之适配器模式

server/2025/1/22 4:05:24/

基础介绍

适配器模式作为c++中常见的设计模式模式之一,是一种结构型设计模式。那适配器模式用于解决什么问题呢?答案是将一个类的接口转换成客户期待的另一个接口。适配器让原本不兼容不能一起工作的类可以协同工作。

典型原理

应该如何理解适配器模式呢?假设目前已经存在一个类,该类提供了某个功能A,现在由于需求的需要,需要新设计一个类,该类需要使用到已有类的功能A,但是新的需求与老的类提供的接口不一致,这种情况下就需要使用到适配器模式了。

实现适配器模式继承+组合。通过这两种形式来实现适配器模式,涉及3个类:适配器类,新的接口类,已有的接口类。适配器类与新的接口类是继承关系;适配器类与已有的接口类是组合关系。具体的示例如下所示:

//新的支付接口
class ModernPayProcessor
{public:virtual void ProcessPay(double amount)=0;//纯虚函数 新的支付接口....
}//旧的支付接口
class oldPayProcessor
{public://老的支付接口void processLegacyPayment(int amount, std::string currency) {//具体的支付处理}}//适配器类
class Adaptor:public ModernPayProcessor
{private:oldPayProcessor* oldPaySystem;  //老的支付类public:Adaptor(oldPayProcessor* p):oldPaySystem(p);  //适配器类的构造函数void ProcessPay(double amount)  //必须实现这个纯虚函数,否则会编译报错{//转换数据类型,以实现旧的支付接口的调用int number = static_cast<int>(amout);oldPaySystem->processLegacyPayment(number, "USD");  //这个老接口与新接口相比,名称不一样,而且参数也不一样,非常典型。}
}//使用实例
int main()
{oldPayProcessor old;  //旧的支付对象Adaptor adaptor(&old);  //新的适配器类adaptor.ProcessPay(13.14);return 0;
}

通过上面的例子可以很清楚的看明白适配器模式是如何实现的,以及适配器模式的含义。

适配器模式的多种应用

适配模式除了上面的实现方式,还有很多复杂的应用。

多接口适配

上面的例子是一个旧类的接口的适配,适配器模式还支持多个旧类的接口适配,如下例所示:

// 多个旧接口
class LegacyPrinter {
public:void printDocument(const std::string& doc) {std::cout << "Legacy Printer: " << doc << std::endl;}
};class LegacyScanner {
public:std::string scanDocument() {return "Scanned content from legacy scanner";}
};// 新的多功能设备接口
class ModernOfficeDevice {
public:virtual void print(const std::string& doc) = 0;virtual std::string scan() = 0;virtual ~ModernOfficeDevice() = default;
};// 多功能适配器
class OfficeDeviceAdapter : public ModernOfficeDevice {
private:LegacyPrinter* printer;LegacyScanner* scanner;public:OfficeDeviceAdapter(LegacyPrinter* p, LegacyScanner* s) : printer(p), scanner(s) {}void print(const std::string& doc) override {printer->printDocument(doc);}std::string scan() override {return scanner->scanDocument();}
};

双向适配器

// 接口A
class InterfaceA {
public:virtual void operationA() = 0;virtual ~InterfaceA() = default;
};// 接口B
class InterfaceB {
public:virtual void operationB() = 0;virtual ~InterfaceB() = default;
};// 双向适配器
class BidirectionalAdapter : public InterfaceA, public InterfaceB {
private:InterfaceA* a;InterfaceB* b;public:BidirectionalAdapter(InterfaceA* a_ptr, InterfaceB* b_ptr) : a(a_ptr), b(b_ptr) {}// A -> B 适配void operationA() override {b->operationB();}// B -> A 适配void operationB() override {a->operationA();}
};

更加具体的例子:

#include <iostream>
#include <string>
#include <memory>// 国内支付系统接口
class DomesticPayment {
public:virtual void payInCNY(double amount) = 0;virtual double getBalanceInCNY() = 0;virtual ~DomesticPayment() = default;
};// 国际支付系统接口
class InternationalPayment {
public:virtual void payInUSD(double amount) = 0;virtual double getBalanceInUSD() = 0;virtual ~InternationalPayment() = default;
};// 具体的国内支付实现
class AliPay : public DomesticPayment {
private:double balance = 1000.0;  // 初始余额public:void payInCNY(double amount) override {std::cout << "使用支付宝支付 " << amount << " CNY" << std::endl;balance -= amount;}double getBalanceInCNY() override {return balance;}
};// 具体的国际支付实现
class PayPal : public InternationalPayment {
private:double balance = 150.0;  // 初始余额public:void payInUSD(double amount) override {std::cout << "Using PayPal to pay " << amount << " USD" << std::endl;balance -= amount;}double getBalanceInUSD() override {return balance;}
};// 双向支付适配器
class PaymentAdapter : public DomesticPayment, public InternationalPayment {
private:std::shared_ptr<DomesticPayment> domesticPayment;std::shared_ptr<InternationalPayment> internationalPayment;const double USD_TO_CNY_RATE = 7.2;  // 汇率public:PaymentAdapter(std::shared_ptr<DomesticPayment> domestic,std::shared_ptr<InternationalPayment> international) : domesticPayment(domestic), internationalPayment(international) {}// DomesticPayment 接口实现void payInCNY(double amount) override {std::cout << "适配器: 转换人民币支付请求" << std::endl;double usdAmount = amount / USD_TO_CNY_RATE;internationalPayment->payInUSD(usdAmount);}double getBalanceInCNY() override {double usdBalance = internationalPayment->getBalanceInUSD();return usdBalance * USD_TO_CNY_RATE;}// InternationalPayment 接口实现void payInUSD(double amount) override {std::cout << "Adapter: Converting USD payment request" << std::endl;double cnyAmount = amount * USD_TO_CNY_RATE;domesticPayment->payInCNY(cnyAmount);}double getBalanceInUSD() override {double cnyBalance = domesticPayment->getBalanceInCNY();return cnyBalance / USD_TO_CNY_RATE;}
};// 客户端代码
void testPaymentSystems() {// 创建支付系统实例auto alipay = std::make_shared<AliPay>();auto paypal = std::make_shared<PayPal>();// 创建适配器PaymentAdapter adapter(alipay, paypal);std::cout << "\n=== 测试人民币支付接口 ===\n";adapter.payInCNY(100.0);std::cout << "人民币余额: " << adapter.getBalanceInCNY() << " CNY\n";std::cout << "\n=== Testing USD payment interface ===\n";adapter.payInUSD(20.0);std::cout << "USD balance: " << adapter.getBalanceInUSD() << " USD\n";
}int main() {testPaymentSystems();return 0;
}

双向适配设计原则

// 保持接口清晰分离
class InterfaceA {virtual void methodA() = 0;
};class InterfaceB {virtual void methodB() = 0;
};class TwoWayAdapter : public InterfaceA, public InterfaceB {// 实现两个接口
};class TwoWayAdapter {
private:// 封装转换逻辑void convertAToB() {// 转换逻辑}void convertBToA() {// 转换逻辑}
};


http://www.ppmy.cn/server/160357.html

相关文章

【论文阅读】VCD-FL: Verifiable, collusion-resistant, and dynamic federated learning

VCD-FL: Verifiable, collusion-resistant, and dynamic federated learning -- VCD-FL:可验证可抵抗共谋攻击的动态联邦学习 来源背景介绍相关工作本文贡献预备知识 系统模型威胁模型具体实现初始化本地训练梯度加密承诺生成插值优化 密文聚合聚合结果验证梯度解密结果验证恶意…

为什么相关性不是因果关系?人工智能中的因果推理探秘

目录 一、背景 &#xff08;一&#xff09;聚焦当下人工智能 &#xff08;二&#xff09;基于关联框架的人工智能 &#xff08;三&#xff09;基于因果框架的人工智能 二、因果推理的基本理论 &#xff08;一&#xff09;因果推理基本范式&#xff1a;因果模型&#xff0…

CBAM-2018学习笔记

名称&#xff1a; Convolutional Block Attention Module (CBAM) 来源&#xff1a; CBAM: Convolutional Block Attention Module 相关工作&#xff1a; #ResNet #GoogleNet #ResNeXt #Network-engineering #Attention-mechanism 创新点&#xff1a; 贡献&#xff1a; 提…

牛客周赛76B:JAVA

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 给定一个长度为 nnn &#xff0c;仅包含小写字母的字符串 sss 。 请你构造出一个非空字符串 ttt &#xff0c;使得它在 sss 中作为子串出现的次数最多。 子串是指&#xff0c;从原…

Windows环境本地配置pyspark环境详细教程

目录 一、背景简记二、本地单机spark环境配置详细步骤第一步&#xff1a;python环境安装第二步&#xff1a;安装jdk及配置环境变量安装包下载安装环境变量配置 第三步&#xff1a;安装Spark安装包下载安装配置环境变量 第四步&#xff1a;安装hadoop安装包下载安装配置环境变量…

AI 时代的 Prompt 工程入门

引言 网络有句话流行的话—— “未来&#xff0c;淘汰你的不是AI&#xff0c;而是掌握了AI的人”。那我们应该怎么掌握AI&#xff1f;我自己的理解是学会面向AI提问&#xff0c;利用好AI工具为我们的工作提效和赋能。毕竟我们普通人不太可能直接去开发大模型&#xff0c;我们更…

.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上)

系列文章目录 1、.Net Core微服务入门系列&#xff08;一&#xff09;——项目搭建 2、.Net Core微服务入门全纪录&#xff08;二&#xff09;——Consul-服务注册与发现&#xff08;上&#xff09; 3、.Net Core微服务入门全纪录&#xff08;三&#xff09;——Consul-服务注…

【数据结构】AVL树

目录 一&#xff1a;什么是AVL树&#xff1f;1.1什么是平衡因子 二&#xff1a;AVL树的数据结构三&#xff1a;AVL的旋转3.1 简单左旋3.2 复杂左旋3.3 简单右旋3.4 复杂右旋总结 四&#xff1a;插入导致旋转的四种情况第一种 LL型第二种 RR型第三种 LR型解决时的特征有三种&…