介绍
桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式
实现
myclass.h
//
// Created by yuwp on 2024/1/12.
//
#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H
#include <iostream>
class Implementor { // 实现抽象类,例如颜料
public:
virtual void operationImpl() = 0;
};
class Abstract { // 抽象类,例如毛笔
public:
virtual void operation() = 0;
protected:
Implementor *m_imp;
};
class RefinedAbstraction : public Abstract { // 扩充抽象类,例如大号毛笔
public:
RefinedAbstraction(Implementor *imp);
~RefinedAbstraction();
void operation() override;
};
class ConcreteImplementorA : public Implementor { // 具体实现类,例如红色颜料
public:
void operationImpl() override;
};
#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//
#include "myclass.h"
RefinedAbstraction::RefinedAbstraction(Implementor *imp) {
m_imp = imp;
}
RefinedAbstraction::~RefinedAbstraction() {
}
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
#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
//
// 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
//
// 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
#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;
}