结构型设计模式——桥接模式

文章目录

桥接模式

桥接模式(Bridge Pattern)是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合**"单一职责原则"**。

桥接模式是软件工程中使用的一种设计模式,旨在 "将抽象与其实现分离,以便两者可以独立变化"。

桥接模式又被称为柄体模式(Handle And Body Pattern),桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效控制了系统中类的个数。

结构

在桥接模式结构图中包含如下几个角色:

  • Abstraction(抽象类):用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与mpementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。
  • AbstractionImpl(抽象类扩充):扩充由Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在AbstractionImpl中可以调用在Implementor中定义的业务方法。
  • Implementor(实现类接口):定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在Abstraction中不仅拥有自己的方法,还可以调用到Implementor中定义的方法,使用关联关系来替代继承关系。
  • ConcreteImplementor(具体实现类):具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法。

桥接模式是一个非常有用的模式,在桥接模式中体现了很多面向对象设计原则的思想,包括"**单一职责原则"、"开闭原则"、"组合复用原则"、"里氏代换原则"、"依赖倒转原则"**等。桥接模式通常会于开发前期进行设计, 使你能够将程序的各个部分独立开来以便开发。 另一方面, 适配器模式通常在已有程序中使用, 让相互不兼容的类能很好地合作。

实现

cpp 复制代码
// 人员信息
struct Person
{
    Person(string name, string job, string ability, string reward, string biezhu=string())
    {
        this->name = name;
        this->job = job;
        this->ability = ability;
        this->reward = reward;
        this->beiZhu = biezhu;
    }
    ~Person()
    {
        cout << name << "被析构..." << endl;
    }
    string name;    // 名字
    string job;     // 职责
    string ability; // 能力
    string reward;  // 赏金
    string beiZhu;  // 备注
};
cpp 复制代码
// 抽象船员
class AbstractTeam
{
public:
    AbstractTeam(string name) : m_teamName(name){}
    string getTeamName()
    {
        return m_teamName;
    }
    void addMember(Person* p)
    {
        m_infoMap.insert(make_pair(p->name, p));
    }
    void show()
    {
        cout << m_teamName << ": " << endl;
        for (const auto& item : m_infoMap)
        {
            cout << "【Name: " << item.second->name
                << ", Job: " << item.second->job
                << ", Ability: " << item.second->ability
                << ", MoneyReward: " << item.second->reward
                << ", BeiZhu: " << item.second->beiZhu 
                << "】" << endl;
        }
    }
    virtual void executeTask() = 0;   // 执行任务
    virtual ~AbstractTeam()
    {
        for (const auto& item : m_infoMap)
        {
            delete item.second;
        }
    }
    
protected:
    string m_teamName = string();
    map<string, Person*> m_infoMap;
};


作者: 苏丙榅
链接: https://subingwen.cn/design-patterns/bridge/#2-1-%E4%BC%99%E4%BC%B4
来源: 爱编程的大丙
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
cpp 复制代码
class CaoMaoTeam : public AbstractTeam
{
public:
    using AbstractTeam::AbstractTeam;
    void executeTask() override
    {
        cout << "在海上冒险,找到 ONE PIECE 成为海贼王!" << endl;
    }
};

class SmokerTeam : public AbstractTeam
{
public:
    using AbstractTeam::AbstractTeam;
    void executeTask() override
    {
        cout << "为了正义, 先将草帽一伙一网打尽!!!" << endl;
    }
};
cpp 复制代码
// 船的抽象类
class AbstractShip
{
public:
    AbstractShip(AbstractTeam* team) : m_team(team) {}
    void showTeam()
    {
        m_team->show();
        m_team->executeTask();
    }
    virtual string getName() = 0;
    virtual void feature() = 0;
    virtual ~AbstractShip() {}
protected:
    AbstractTeam* m_team = nullptr;
};
cpp 复制代码
class Merry : public AbstractShip
{
public:
    using AbstractShip::AbstractShip;
    string getName() override
    {
        return string("前进·梅利号");
    }
    void feature() override
    {
        cout << getName() 
            << " -- 船首为羊头, 在司法岛化身船精灵舍己救下了草帽一伙!" << endl;
    }
};

class HaiJunShip : public AbstractShip
{
public:
    using AbstractShip::AbstractShip;
    string getName() override
    {
        return string("无敌海军号");
    }
    void feature() override
    {
        cout << getName() << " -- 船底由海楼石建造, 可以穿过无风带的巨大炮舰!" << endl;
    }
};
cpp 复制代码
int main()
{
    // 草帽海贼团
    CaoMaoTeam* caomao = new CaoMaoTeam("草帽海贼团");
    Person* luffy = new Person("路飞", "船长", "橡胶果实能力者", "30亿贝里", "爱吃肉");
    Person* zoro = new Person("索隆", "剑士", "三刀流", "11亿1100万贝里", "路痴");
    Person* sanji = new Person("山治", "厨师", "隐形黑", "10亿3200万贝里", "好色");
    Person* nami = new Person("娜美", "航海士", "天候棒+宙斯", "3亿6600万贝里", "喜欢钱");
    caomao->addMember(luffy);
    caomao->addMember(zoro);
    caomao->addMember(sanji);
    caomao->addMember(nami);
    Merry* sunny = new Merry(caomao);
    sunny->feature();
    sunny->showTeam();

    // 斯摩格的船队
    SmokerTeam* team = new SmokerTeam("斯摩格的海军部队");
    Person* smoker = new Person("斯摩格", "中将", "冒烟果实能力者", "", "爱吃烟熏鸡肉");
    Person* dasiqi = new Person("达斯琪", "大佐", "一刀流", "", "近视");
    team->addMember(smoker);
    team->addMember(dasiqi);
    HaiJunShip* ship = new HaiJunShip(team);
    ship->feature();
    ship->showTeam();

    delete caomao;
    delete sunny;
    delete team;
    delete ship;

    return 0;
}

特点

要优点

  • 分离抽象接口及其实现部分。桥接模式使用"对象间的关联关系"解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
  • 桥接模式可以取代多层继承方案,多层继承方案违背了"单一职责原则",复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
  • 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合"开闭原则"。

主要缺点

  • 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
  • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。

适用环境

  • 想要拆分或重组一个具有多重功能的庞杂类(例如能与多个数据库服务器进行交互的类)
  • 希望在几个独立维度上扩展一个类
  • 需要在运行时切换不同实现方法
相关推荐
翎沣1 小时前
C++11异常处理机制
java·c++·算法
云深麋鹿2 小时前
C++ | AVLTree
开发语言·c++
Qt程序员2 小时前
从协议到实战:HTTP 反向代理
linux·c++·websocket·nginx·http·反向代理·正向代理
Hua-Jay2 小时前
OpenCV联合C++/Qt 学习笔记(十六)----图像细化、轮廓检测、轮廓信息统计及轮廓外接多边形
c++·笔记·qt·opencv·学习·计算机视觉
无限进步_2 小时前
【C++】深入底层:自己动手实现一个哈希表
开发语言·数据结构·c++·算法·链表·散列表·visual studio
paeamecium2 小时前
【PAT甲级真题】- General Palindromic Number(20)
数据结构·c++·算法·pat考试·pat
minji...2 小时前
Linux 网络基础之UDP协议(四)传输层协议 UDP,再谈端口号,UDP 特点
linux·服务器·开发语言·网络·c++·tcp/ip·udp
艾莉丝努力练剑2 小时前
【Linux网络】Linux 网络编程:应用层自定义协议与序列化(1)初识
linux·运维·服务器·网络·c++·udp·tcp
南境十里·墨染春水2 小时前
C++ 日志 4—— 多线程安全与异步日志优化
数据库·c++·安全