《设计模式的艺术》笔记 - 桥接模式

介绍

桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式

实现

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>

class Abstract {    // 抽象类,例如毛笔
public:
    virtual void operation() = 0;
};

class Implementor { // 实现抽象类,例如颜料
public:
    virtual void operationImpl() = 0;
};

class RefinedAbstraction : public Abstract {    // 扩充抽象类,例如大号毛笔
public:
    RefinedAbstraction(Implementor *imp);
    ~RefinedAbstraction();
    void operation() override;

protected:
    Implementor *m_imp;
};

class ConcreteImplementorA : public Implementor {   // 具体实现类,例如红色颜料
public:
    void operationImpl() override;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

RefinedAbstraction::RefinedAbstraction(Implementor *imp) {
    m_imp = imp;
}

RefinedAbstraction::~RefinedAbstraction() {
    if (m_imp) {
        delete m_imp;
    }
}

void RefinedAbstraction::operation() {
    if (m_imp) {
        m_imp->operationImpl();
    }
    std::cout << "RefinedAbstraction::operation()" << std::endl;
}

void ConcreteImplementorA::operationImpl() {
    std::cout << "ConcreteImplementorA::operationImpl()" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Implementor *imp = new ConcreteImplementorA();
    Abstract *ab = new RefinedAbstraction(imp);
    ab->operation();

    return 0;
}

总结

优点

  1. 分离抽象接口及其实现部分。桥接模式使用"对象间的关联关系"解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化(即抽象和实现不再在同一个继承层次结构中,而是"子类化"它们,使它们各自都具有自己的子类,以便任意组合子类,从而获得多维度组合对象)

  2. 在很多情况下,桥接模式可以取代多层继承方案。多层继承方案违背了单一职责原则,复用性较差,且类的个数非常多。桥接模式是比多层继承方案更好的解决方法,它极大地减少了子类的个数。

  3. 桥接模式提高了系统的可扩展性。在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合开闭原则。

缺点

  1. 桥接模式的使用会增加系统的理解与设计难度。由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。

  2. 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。

适用场景

  1. 如果一个系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。

  2. 抽象部分和实现部分可以以继承的方式独立扩展而互不影响,在程序运行时可以动态地将一个抽象类子类的对象和一个实现类子类的对象进行组合,即系统需要对抽象类角色和实现类角色进行动态耦合。

  3. 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。

  4. 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

练习

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>

class FileFormat { // 实现抽象类
public:
    virtual void toFile(std::string data, std::string file) = 0;
};

class Database {    // 抽象类
public:
    virtual void trans() = 0;

protected:
    FileFormat *m_fileFormat;
};

class MysqlDatabase : public Database {    // 扩充抽象类
public:
    MysqlDatabase(FileFormat *fileFormat);
    void trans() override;

};

class RedisDatabase : public Database {
public:
    RedisDatabase(FileFormat *fileFormat);
    void trans() override;

protected:
    FileFormat *m_fileFormat;
};

class TXTFileFormat : public FileFormat {   // 具体实现类,例如红色颜料
public:
    void toFile(std::string data, std::string file) override;
};

class XMLFileFormat : public FileFormat {
public:
    void toFile(std::string data, std::string file) override;
};

class PDFFileFormat : public FileFormat {
public:
    void toFile(std::string data, std::string file) override;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

MysqlDatabase::MysqlDatabase(FileFormat *fileFormat) {
    m_fileFormat = fileFormat;
}

void MysqlDatabase::trans() {
    std::string data = "mysql";
    if (m_fileFormat) {
        m_fileFormat->toFile(data, "mysql");
    }
}

RedisDatabase::RedisDatabase(FileFormat *fileFormat) {
    m_fileFormat = fileFormat;
}

void RedisDatabase::trans() {
    std::string data = "redis";
    if (m_fileFormat) {
        m_fileFormat->toFile(data, "redis");
    }
}

void TXTFileFormat::toFile(std::string data, std::string file) {
    std::cout << "\"" << data << "\"" << "转换为\"" << file << ".txt\"" << std::endl;
}

void XMLFileFormat::toFile(std::string data, std::string file) {
    std::cout << "\"" << data << "\"" << "转换为\"" << file << ".xml\"" << std::endl;
}

void PDFFileFormat::toFile(std::string data, std::string file) {
    std::cout << "\"" << data << "\"" << "转换为\"" << file << ".pdf\"" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    FileFormat *txtFormat = new TXTFileFormat();
    FileFormat *xmlFormat = new XMLFileFormat();
    FileFormat *pdfFormat = new PDFFileFormat();
    Database *database = new MysqlDatabase(txtFormat);
    database->trans();
    delete database;
    database = new MysqlDatabase(xmlFormat);
    database->trans();
    delete database;
    database = new MysqlDatabase(pdfFormat);
    database->trans();
    delete database;

    database = new RedisDatabase(txtFormat);
    database->trans();
    delete database;
    database = new RedisDatabase(xmlFormat);
    database->trans();
    delete database;
    database = new RedisDatabase(pdfFormat);
    database->trans();

    delete txtFormat;
    delete xmlFormat;
    delete pdfFormat;

    return 0;
}
相关推荐
幸运超级加倍~17 分钟前
软件设计师-上午题-16 算法(4-5分)
笔记·算法
王俊山IT37 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
Yawesh_best2 小时前
思源笔记轻松连接本地Ollama大语言模型,开启AI写作新体验!
笔记·语言模型·ai写作
CXDNW3 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙3 小时前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型
ssf-yasuo3 小时前
SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
论文阅读·笔记·prompt
ajsbxi4 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
TeYiToKu4 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
dsywws4 小时前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
wrx繁星点点4 小时前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式