说在前面的话:桥接模式(Bridge)会比较绕,所以我们打算换一种讲解方式,从一个例子从而引出桥接模式。
设计模式学到最后,看起来既像这个,又像那个,不要在意这心,设计模式的核心是提升代码的扩展性,如果达到了这点,又何必在于是什么设计模式呢。
一、场景问题
1.1 故事场景
经过多年爱情的经营,我和女朋友终于走到了婚姻的殿堂。
结婚是一件开心的事情,但事情也特别多和杂…. 这不…. 我女朋友又找我来了…
女朋友:亲爱的,你看下我整理了下名单。你给他们发送下信息。微信和手机短信就可以了。
我:这么多人的吗?小几万人?咱们的关系网有这么大的吗?
女朋友:你看我给分类了下:你的亲戚、我的亲戚;你的哥们、我的姐妹;你的朋友、我的朋友;你的…,我的…
我:这工作量不小呢,我的好好研究一下。
1.2 业务场景
上面的这个场景,在我们的实际业务中就会碰到。比如:给要过期的企业(企业购买了年套餐),发送一条续费的消息,针对到期时间可能还会有不同的,比如:到期前30天发送微信消息,到期前15天发送短信消息,到期前7天发送加急消息或者直接电话通知等。
二、消息发送1.0:只有消息发送方式
2.1 设计
根据我女朋友的要求就是能够使用微信和手机短信发送消息咯。
由于发送消息会有两种不同的实现方式(微信和手机短信),为了让外部能统一操作,因此,把消息设计成接口,然后由两个不同的实现类,分别实现微信发送消息方式和手机短信发送消息的方式。
根据我初步的设想,我想应该能满足我女朋友的要求,于是我就按照我的设想设计了一下(我们把当前发送消息的方式定义为普通消息):
2.2 编码实现
我们1个接口,两个实现类,这个还是很简单的,不多说:
2.2.1 发送消息的接口
发送消息的方式的接口Message:
package com.kfit.bridge.message.v1;/** * 发送消息的方式 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public interface Message { /** * 所有的消息类型都需要有发送消息的方法 * @param toUser : 消息要发送给谁 * @param message :发送消息的内容 */ void send(String toUser,String message);} 2.2.2 发送消息的具体实现
发送消息的方式的实现-微信发送消息CommonWeixinMessage:
package com.kfit.bridge.message.v1;/** * 发送消息的方式 - 微信发送消息:际项目中应该是微信公众号的消息 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public class CommonWeixinMessage implements Message { @Override public void send(String toUser, String message) { //调用微信的SDK进行发送消息 System.out.println("[微信消息] "+toUser+":"+message); }} 发送消息的方式的实现-手机短信发送消息CommonSMSMessage:
package com.kfit.bridge.message.v1;/** * 发送消息的方式 - 手机短信 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public class CommonSMSMessage implements Message { @Override public void send(String toUser, String message) { //调用短信平台SDK进行发送消息 System.out.println("[手机短信消息] "+toUser+":"+message); }} 2.2.3 发送消息
万事俱备,于是我就开始准备发送消息了:
package com.kfit.bridge.message.v1;/** * * 我来执行女朋友的的发送消息 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public class Me { public static void main(String[] args) { //初始化发送消息的方式 Message weixinMessage = new CommonWeixinMessage(); Message smsMessage = new CommonSMSMessage(); weixinMessage.send("鹏仔", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); smsMessage.send("鹏仔", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); weixinMessage.send("钟哥", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); smsMessage.send("钟哥", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); //... 其它人... }} 执行以下看下打印消息:
三、消息发送2.0:加入消息类型
消息发送之后,过了几天清闲的日子,刚躺着沙发上正要打开手机刷刷视频,女朋友的消息又来了。
女朋友:你在忙吗?
我:亲爱的,怎么了?有何事需要在下去办呐?
女朋友:你看都快临近婚礼了,好多人也没有回复呢?你要不要加急一下。
我:……
3.1 需求分析
我们这里先定义一下加急消息的概念:
② 加急消息会在消息上添加加急的标识;
② 加急会提供监控的方法,以便客户了解消息的处理进度。
在上面的情节中就是:我发完消息之后,需要让对方给我一个回执,也就是给我发送一条确认消息之类的,然后我在汇报给女朋友大人。
3.2 设计
从一开始的需求到现在的需求,其实整个结构已经改变了。
一开始就是一维的:发送消息的方式;现在已经转变为二维的:消息的类型。
发送消息的方式:就是微信、手机短信。
消息的类型:普通消息,加急消息。
我们这里先不管这些,我们先看看我们常规的一个思路是怎么样子的:我们会抽象出来一个加急的接口UrgencyMessage,在此接口中会有一个watch方法,然后根据此接口还会有两个具体的实现微信发送方式、手机短信发送方式。
3.3 编码
我们新增1个接口,两个实现类:
3.3.1 发送加急消息方式的接口
加急消息UrgencyMessage继承接口Message,新增要给watch方法:
package com.kfit.bridge.message.v2;/** * * * 消息的类型 - 加急消息 * * 一开始的方式我们可以认为是普通消息。 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public interface UrgencyMessage extends Message{ /** * 监控某消息的处理过程 * @param messageId : 消息id * @return */ Object watch(String messageId);} 3.3.2 发送加急消息方式的实现
发送加急消息方式的实现UrgencyWeixinMessage:
package com.kfit.bridge.message.v2;/** * 发送加急消息的方式 - 手机短信 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public class UrgencyWeixinMessage implements UrgencyMessage { @Override public void send(String toUser, String message) { message = "[加急]"+message; //调用短信平台SDK进行发送消息 System.out.println("[微信消息] "+toUser+":"+message); } @Override public Object watch(String messageId) { //获取相应的数据,返回监控结果 return "收到,一定会去参加的"; }} 发送加急消息方式的实现UrgencySMSMessage:
package com.kfit.bridge.message.v2;/** * 发送加急消息的方式 - 手机短信 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public class UrgencySMSMessage implements UrgencyMessage { @Override public void send(String toUser, String message) { message = "[加急]"+message; //调用短信平台SDK进行发送消息 System.out.println("[手机短信消息] "+toUser+":"+message); } @Override public Object watch(String messageId) { //获取相应的数据,返回监控结果 return "收到,一定会去参加的"; }} 3.3.3 发送消息
我们现在有监控的方法,就可以查看到消息的发送情况了:
/** * * 我来执行女朋友的的发送消息 * * @author 悟纤「公众号SpringBoot」 * @date 2020-11-27 * @slogan 大道至简 悟在天成 */public class Me { public static void main(String[] args) { //初始化发送消息的方式 UrgencyMessage weixinMessage = new UrgencyWeixinMessage(); UrgencyMessage smsMessage = new UrgencySMSMessage(); weixinMessage.send("鹏仔", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); System.out.println("获取反馈结果:"+weixinMessage.watch("1")); smsMessage.send("鹏仔", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); System.out.println("获取反馈结果:"+smsMessage.watch("2")); weixinMessage.send("钟哥", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); System.out.println("获取反馈结果:"+weixinMessage.watch("3")); smsMessage.send("钟哥", "2021年x月x日,我要结婚了,记得来参加我的婚礼"); System.out.println("获取反馈结果:"+smsMessage.watch("4")); //... 其它人... }} 查看下结果:
四、消息发送3.0:二维扩展问题
上面的设计感觉挺好的,没看出哪里有问题呀。系统问题的来源一般都是系统的升级产生的,我们接着衍化。
加急消息发出去之后,好日子又过了一阵子。感觉女朋友总是能感觉我到过的太潇洒了似的。
女朋友:你看你办的事情,怎么搞的,王某说过段时间在给答复,那现在到底是来还是来不来呢?
我:这个我也不知道呢。
女朋友:那现在都临近结婚日了,你赶紧催促催促问问呢。
我:… (结个婚太难了…)
女朋友:对了另外,有些朋友想要咱们的婚纱照,你用邮件给他们发一下。
我:… (当场想跪下了…)
4.1 加入特急消息的处理
现在消息类型就从普通消息->加急消息->特急消息了,对于特急消息我们需要有一个催促的方法(urge)。
这时候类图关系就变成这样子了:
4.2 加入邮件发送消息的方式
如果要添加一种新的发送消息的方式,比如邮件发送消息,是需要在每一种抽象的具体实现里面,都要添加邮件发送消息的处理。也就是说:发送普通消息、加急消息和特急消息的处理,都可以通过邮件来发送。这就意味着,需要添加三个实现。如下图所示:
4.3 出现的问题
通过继承来扩展的实现方式存在问题:
扩展消息的类型(普通/加急/特急)不太容易,不同类型的消息具有不同的业务,也就是有不同的实现,在这种情况下,每个类型的消息,需要实现所有不同的消息方式(微信/邮件/手机短信)。
如果要加入一种新的发送消息方式,那么会要求所有的消息类型,都要加入这种新的消息方式的实现。我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。 à悟空学院:https://t.cn/Rg3fKJD
SpringBoot视频:http://t.cn/A6ZagYTi
SpringBoot交流平台:https://t.cn/R3QDhU0
SpringSecurity5.0视频:http://t.cn/A6ZadMBe
ShardingJDBC分库分表:http://t.cn/A6ZarrqS
分布式事务解决方案:http://t.cn/A6ZaBnIr
JVM内存模型调优实战:http://t.cn/A6wWMVqG
Spring入门到精通:https://t.cn/A6bFcDh4
大话设计模式之爱你:https://dwz.cn/wqO0MAy7
|