无桥接模式之消息发送 :桥接模式

627 阅读9分钟

无桥接模式之消息发送 :桥接模式

说在前面的话:桥接模式(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 出现的问题

通过继承来扩展的实现方式存在问题:

扩展消息的类型(普通/加急/特急)不太容易,不同类型的消息具有不同的业务,也就是有不同的实现,在这种情况下,每个类型的消息,需要实现所有不同的消息方式(微信/邮件/手机短信)。

如果要加入一种新的发送消息方式,那么会要求所有的消息类型,都要加入这种新的消息方式的实现。