结构型模式--2.桥接模式【大海贼时代】

1. 组建海贼团

哥尔·D·罗杰是罗杰海贼团船长。他最终征服了伟大航路,完成了伟大航路的航行,被人们成为海贼王。后来得了绝症,得知自己命不久矣,主动自首并在东海罗格镇被处刑。临死前罗杰的一句话“想要我的宝藏吗?想要的话就全都给你!”
在这里插入图片描述

很多人为了梦想,为了罗杰留下的宝藏竞相出海,大海贼时代就此开启。

对于罗杰的行为,最不高兴的肯定是世界政府和海军了,世界政府是海贼中的最高权利机构,海军是世界政府的直属组织,他们以绝对的正义为名在全世界海洋执行维持治安工作。
在这里插入图片描述

现在海军的最高统帅也就是海军元帅是赤犬,假设现在赤犬想要将现在已知的所有的海贼团全部记录在册,那么肯定得写个程序,关于如何能够高效的记录和管理这些信息,隶属海军的程序猿们展开了讨论:

如果只记录海贼船的名字肯定的不完整的,这个海贼团内部还有一个完整的组织结构,每个海贼团有若干船员,每个船员有不同的分工,也就是他们的职责不同。

比如草帽海贼团目前一共十个人,分别是:船长、剑士、厨师、航海士、考古学家、船医、音乐家、船工、狙击手、舵手

方案1

因为每个船员都具有所属海贼团的一些特性,所以可以让每个船员都从对应的海贼团类派生,如下图,它描述的某一个海贼团中类和类之间的关系:
在这里插入图片描述

方案2

将海贼团的船员和海贼团之间的继承关系,改为聚合关系,如下图:
在这里插入图片描述

盖棺定论

上面的两种方案你觉得哪个更合理一些呢?很明显,是第二种。

  • 第一种解决方案

    1. 每个船员都是当前海贼团的子类,这样船员就继承了海贼团的属性,合情合理。
    2. 如果当前海贼团添加了一个成员就需要给当前海贼团类添加一个子类。拿路飞举个例子,他在德雷斯罗萨王国打败多弗朗明哥之后,组成了草帽大船团,小弟一下子扩充了5640人,难道要给草帽团添加五千多个子类吗?如果这样处理,海贼船和船员的耦合度就比较高了。
  • 第二种解决方案

    1. 海贼团之间是继承关系,但是此时的海贼团也只是一个抽象,因为组成海贼团的人已经被抽离了,船员已经和所属的海贼团没有了继承关系。
    2. 关于海贼世界的船员在船上对应不同的职责担任不同的职务,他们是一个团队,所以可以给船员抽象出一个团队类,用于管理船上的成员。
    3. 抽象的海贼团只有一个空壳子,所以要赋予其灵魂也就是给它添加船员,此时的海贼团和船员团队可以通过聚合的方式组合成为一个整体。
    4. 这种解决方案不仅适用于管理海贼团,用于管理海军的各个舰队也是没有问题的。

通过上述分析,肯定是使用第二种解决方案程序猿的工作量会更少一些,且更容易维护和扩展。第二种方式的原则就是将抽象部分和它的实现部分分离,使它们可以独立的变化,这种处理模式就是桥接模式

关于桥接模式的使用对应的应用场景也有很多,比如:

  1. 空调、电视机等和它们对应的遥控器
    • 空调、电视机是抽象,遥控器是实现
  2. 手机品牌和手机软件
    • 手机品牌是抽象,手机软件是实现
  3. 跨平台的GUI在不同平台上运行
    • 程序的GUI层是抽象,操作系统的API是实现

2. 路飞出海

年幼的路飞误食了红发香克斯的橡胶果实(人人果实·幻兽种·尼卡形态),受到香克斯的影响决定出海,他要做的第一件事儿就是找一艘船并找一些伙伴一起去冒险,下面我们通过桥接模式来记录下草帽团的信息。

2.1 伙伴

不论是哪艘船上的船员肯定都是有一些个人的身份信息,为了将这些信息记录下来,先定一个存储数据的结构体:

// 人员信息
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;  // 备注
};

在上面已经提到了,关于团队的成员组成可以是海贼,也可以是海军,所以可以先定义一个团队的抽象类:

// 抽象船员
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;
};

在上面的抽象类中可以添加addMember(Person* p)和显示show()当前团队成员的信息。不同的团队他们的目标是不一样的,所以需要在子类中重写这个纯虚函数executeTask()

当路飞一行人到达东海罗格镇的时候,就开始被当时还是海军大佐的斯摩格追捕(现在是中将),接下来基于上面的基类将路飞和斯摩格团队对应的类定义出来:

路飞

class CaoMaoTeam : public AbstractTeam
{
public:using AbstractTeam::AbstractTeam;void executeTask() override{cout << "在海上冒险,找到 ONE PIECE 成为海贼王!" << endl;}
};

在子类CaoMaoTeam中必须重写父类的纯虚函数executeTask(),这样才能创建这个子类的实例对象。

斯摩格

class SmokerTeam : public AbstractTeam
{
public:using AbstractTeam::AbstractTeam;void executeTask() override{cout << "为了正义, 先将草帽一伙一网打尽!!!" << endl;}
};

在子类SmokerTeam中必须重写父类的纯虚函数executeTask(),这样才能创建这个子类的实例对象,斯摩格和路飞的立场不同,所以他们通过这个函数干的事情是不一样的。

2.2 海上交通工具

不论是海军还是海贼在大海上航行都需要船,虽然他们驾驶的船只不同,但是有很多属性还是一致的,所以我们可以先定义一个船的抽象类:

// 船的抽象类
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;
};

在这个抽象类中提供了一个纯虚函数用来描述船的特点feature(),在不同的子类中都需要重写这个虚函数。

对于一个海贼团或者一支海军部队来说,光有船是不完整的,船只是这个团队的抽象,如果想要让它鲜活起来就必要要有由人组成的团队,也就是抽象的具体实现。所以,在这个抽象类中包含了一个团队对象,船和团队二者之间的关系可以看做是聚合关系。

梅利号

路飞来到东海的西罗布村,得到梅利号,这是草帽海贼团的第一艘船,下面把梅利号对应的类定义出来:

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;}
};

2.3 你追我跑

在上面的讲解中,我们已经把要出海冒险的抽象部分(海贼船/海军军舰)和实现部分(海贼团团队/海军部队)分别定义出来了,最后需要将它们合二为一,使他们成为一个有灵魂的整体。

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;
}

程序输出的结果为:

前进·梅利号 -- 船首为羊头, 在司法岛化身船精灵舍己救下了草帽一伙!
草帽海贼团:
【Name: 路飞, Job: 船长, Ability: 橡胶果实能力者, MoneyReward: 30亿贝里, BeiZhu: 爱吃肉】
【Name: 娜美, Job: 航海士, Ability: 天候棒+宙斯, MoneyReward: 3亿6600万贝里, BeiZhu: 喜欢钱】
【Name: 山治, Job: 厨师, Ability: 隐形黑, MoneyReward: 10亿3200万贝里, BeiZhu: 好色】
【Name: 索隆, Job: 剑士, Ability: 三刀流, MoneyReward: 11亿1100万贝里, BeiZhu: 路痴】
在海上冒险,找到 ONE PIECE 成为海贼王!
=====================================
无敌海军号 -- 船底由海楼石建造, 可以穿过无风带的巨大炮舰!
斯摩格的海军部队:
【Name: 达斯琪, Job: 大佐, Ability: 一刀流, MoneyReward: , BeiZhu: 近视】
【Name: 斯摩格, Job: 中将, Ability: 冒烟果实能力者, MoneyReward: , BeiZhu: 爱吃烟熏鸡肉】
为了正义, 先将草帽一伙一网打尽!!!
================== 资源释放 ==================
路飞被析构...
娜美被析构...
山治被析构...
索隆被析构...
达斯琪被析构...
斯摩格被析构...

这样,我们就通过桥接模式完成了对于海贼或者海军的管理。

3. 结构图

最后根据上面的代码将其对应的桥接模式的UML类图画出来(学会桥接模式之后,应该先画类图在写程序。)
在这里插入图片描述

上面已经多次提到,桥接模式就是就将抽象和实现分离开来,在上图中描述二者之间的聚合关系的那条线就可以看做是一座桥梁,把两个独立的对象关联到了一起。在某些业务场景下抽象部分或者实现部分可能是没有子类的,这在桥接模式中是被允许的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/306382.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

期货量化交易软件:MQL5 中的范畴论 (第 15 部分)函子与图论

概述 在上一篇文章中&#xff0c;我们目睹了前期文章中涵盖的概念&#xff08;如线性序&#xff09;如何视作范畴&#xff0c;以及为什么它们的“态射”在与其它范畴相关时即构成函子。在本文中&#xff0c;我们赫兹量化软件将阐述来自前期文章中的概括&#xff0c;即通过查看…

【示例】MySQL-SQL语句优化

前言 本文主要讲述不同SQL语句的优化策略。 SQL | DML语句 insert语句 插入数据的时候&#xff0c;改为批量插入 插入数据的时候&#xff0c;按照主键顺序插入 大批量插入数据的时候&#xff08;百万&#xff09;&#xff0c;用load指令&#xff0c;从本地文件载入&#x…

实现鼠标在页面点击出现焦点及大十字星

近段时间&#xff0c;在完成项目进度情况显示时候&#xff0c;用户在操作鼠标时候&#xff0c;显示当鼠标所在位置对应时间如下图所示 代码实现步骤如下&#xff1a; 1.首先引用 jquery.1.7.js 2.再次引用raphael.js 3.然后引用graphics.js 4.最后引用mfocus.js 其中mfocu…

【UE Niagara】让粒子发出声音

步骤 首先新建一个Niagara发射器&#xff0c;使用Empty模板。打开后先添加一个“Spawn Burst Instantaneous”模块&#xff0c;设置发射数量为3 可以添加一个“Shape Location”使得每个粒子的初始位置不同 添加一个“Play Audio”模块&#xff0c;然后设置一个播放的音效 对N…

一个比 Celery 轻量好用的异步任务工具

文章目录 1、RQ安装2、RQ基本概念2.1、Queue2.2、Job2.3、Worker 3、RQ 高级用法3.1、自定义任务失败处理3.2、任务依赖关系3.3、定时任务 4、RQ web 界面5、查看任务结果6、RQ 与 celery 对比7、总结 Python RQ&#xff08;Redis Queue&#xff09;是一个轻量级的异步任务队列…

电脑文件名乱码,数据恢复有高招!

在日常使用电脑的过程中&#xff0c;突然遭遇文件名乱码的情况&#xff0c;确实让人头疼不已。原本井井有条的文件目录&#xff0c;一下子变得杂乱无章&#xff0c;文件名变成了一堆无意义的乱码字符。这种情况不仅影响了文件的正常使用&#xff0c;还可能导致重要数据的丢失。…

当努力成为日常,你准备好“戒瘾”了吗

不知道从什么时候开始&#xff0c;我们的朋友圈里充斥着各种“努力打卡”、“奋斗不息”的标语。大家仿佛一夜之间都变成了“卷王”&#xff0c;不是在努力就是在努力的路上…… 卷王争霸 努力成瘾的序幕 在每个看似充满正能量的背后&#xff0c;却隐藏着一个不容忽视的现象—…

java快速构建飞书API消息推送、消息加急等功能

文章目录 飞书机器人自定义机器人自定义应用机器人 自定义应用发送消息普通文本 text富文本 post图片 image文件 file语音 audio视频 media消息卡片 interactive分享群名片 share_chat分享个人名片 share_user 批量发送消息消息加急发送应用内加急发送短信加急 发送电话加急spr…

论文复现:nn.L1Loss()

nn.L1Loss() 是 PyTorch 中的一个损失函数&#xff0c;属于 torch.nn 模块的一部分。它计算预测值和真实值之间差的绝对值的平均值&#xff0c;也就是 L1 距离&#xff08;或曼哈顿距离&#xff09;。这个损失函数常用于回归任务&#xff0c;特别是当你希望减少异常值对总体损失…

核心api实操-Activiti7从入门到专家(5)

背景 上一节已经搭建了&#xff0c;具体的开发环境&#xff0c;数据库&#xff0c;并且找了一个可以用bpmnjs流程设计器&#xff0c;这一些&#xff0c;我们对核心api做个基础的实操&#xff0c;有个感性的认知&#xff0c;另外对数据库和基本数据流动有个理解。 部署 模板部…

深度学习pytorch实战第P2周:CIFAR10彩色图片识别

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](https://mtyjkh.blog.csdn.net/)** 零、引言&#xff08;温故而知新&#xff…

智能合约平台开发指南

随着区块链技术的普及&#xff0c;智能合约平台已经成为了这个领域的一个重要趋势。智能合约可以自动化执行合同条款&#xff0c;大大减少了执行和监督合同条款所需的成本和时间。那么&#xff0c;如何开发一个智能合约平台呢&#xff1f;以下是一些关键步骤。 一、选择合适的区…

MySQL学习笔记2——基础操作

基础操作 一、增删改查1、添加数据2、删除数据3、修改数据4、查询语句 二、主键三、外键和连接1、外键2、连接 一、增删改查 1、添加数据 INSERT INTO 表名[(字段名[,字段名]…)] VALUES (值的列表); --[]表示里面的内容可选添加数据分为插入数据记录和插入查询结果 插入数据…

AI+BI,欢迎数据分析进入大模型时代

过去一年大模型应用集中爆发&#xff0c;中关村科金作为领先的对话式AI技术解决方案提供商&#xff0c;基于各个行业真实的业务痛点&#xff0c;围绕营销、服务与运营场景&#xff0c;创新打造和升级了知识助手、投顾助手、智能陪练等大模型应用&#xff0c;全面赋能客户经理展…

【INNODB引擎篇】深奥探究Innodb存储引擎

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 目录 1.InnoDB引擎 1.1 逻辑存储结构 1.2 架构 1.2.1 概述 1.2.2 内存结构 1.2.3 磁盘结构 1.2.4 后台线程 1.3 事务原理 1.3.1 事务基础 1.3.2 redo log 1.…

鸿蒙TypeScript学习第12天【Map对象】

1、TypeScript Map 对象 Map 对象保存键值对&#xff0c;并且能够记住键的原始插入顺序。 任何值(对象或者原始值) 都可以作为一个键或一个值。 Map 是 ES6 中引入的一种新的数据结构&#xff0c;可以参考gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md 2、创…

【架构-九】数据库反规范化设计

什么是反规范化设计&#xff1f; 反规范化是指为了提高数据库的性能或满足特定需求而向数据库中增加冗余数据的过程。与数据库规范化设计正好相反&#xff0c;反规范化的目的是减少查询的复杂度&#xff0c;加快数据检索的速度。主要的反规范化手段如下&#xff1a; 优点&am…

YOLOv8打印模型结构配置信息并查看网络模型详细参数:参数量、计算量(GFLOPS)

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

Python3.7编程之病毒

基础篇 什么是病毒 病毒&#xff0c;指的是一些通过非法手段获取系统的一些权限&#xff0c;然后进行破坏或者盗取。 病毒分为两类&#xff1a; 1、破坏型 这类病毒往往会将系统弄的乱七八糟&#xff0c;比如把你的U盘删光&#xff0c;把你的系统背景调成黑客图片&#xff0c…

python 的join函数

join函数是一个对字符串处理的函数 字符串.join(str)的含义是把字符串加入到str的每一个间隙里面 如 str1234 ,.join(str) #打印的结果为 1,2,3,4