美文网首页设计模式系列篇
设计模式系列篇(六)——桥接模式

设计模式系列篇(六)——桥接模式

作者: 复旦猿 | 来源:发表于2020-08-23 23:46 被阅读0次

    What

    桥接模式(Bridge Design Pattern),在GOF的《设计模式》一书中是这么定义的——“将抽象和实现解耦,让它们可以独立变化”;或者从另外一个角度来解释就是,一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。桥接模式理解起来确实比较困难,但它的实现确是比较简单的,我会在下面的章节中具体介绍它的实现方式。

    Why

    1. 如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
    2. “抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
    3. 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
    4. 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

    How

    上面这几点还是比较难理解的,我们接下来以一个实际案例来展开说明一下。现在,产品经理找到你,说有一个系统发送告警通知用户的需求需要我们来实现,具体需求如下:

    1. 告警有以下4种级别:次要、一般、紧急、重要;
    2. 通知有以下3种方式:短信、邮件、电话;
    3. 目前来说,告警级别的通知方式规则如下:
      次要、一般类告警通过邮件方式发送提醒
      重要告警通过短信方式发送提醒
      紧急告警需要通过电话发送提醒

    你拿到该需求后,进行了细致的分析:如果直接使用静态继承关系,即Notification接口和UnurgentEmailNotification类、UrgentMessageNotification类、 SeverePhoneNotification类来实现Notification接口的话,会导致如果以后产品经理心血来潮换一下告警类别和通知方式的规则,那岂不是要重新实现类。因此,这里的告警和通知是两个需要独立扩展的维度,那么桥接模式就可以闪亮登场了~
    针对 Notification 的代码,我们将不同渠道的发送逻辑剥离出来,形成独立的消息发送类(MsgSender 相关类)。其中,Notification 类相当于抽象,MsgSender 类相当于实现,两者可以独立开发,通过组合关系(也就是桥梁)任意组合在一起。所谓任意组合的意思就是,不同紧急程度的消息和发送渠道之间的对应关系,不是在代码中固定写死的,我们可以动态地去指定(比如,通过读取配置来获取对应关系)。
    具体实现如下:

    public abstract class Notification {
        protected MsgSender msgSender;
    
        public Notification(MsgSender msgSender) {
            this.msgSender = msgSender;
        }
    
        public abstract void notify(String msg);
    }
    
    
    public class TrivialNotification extends Notification {
    
        public TrivialNotification(MsgSender msgSender) {
            super(msgSender);
        }
    
        @Override
        public void notify(String msg) {
            msgSender.send(msg);
        }
    }
    
    // NormalNotification、SevereNotification和UrgentNotification类和TrivialNotification结构类似,因此省略
    
    public interface MsgSender {
        void send(String msg);
    }
    
    public class EmailMsgSender implements MsgSender {
    
        private List<String> emailList;
    
        public EmailMsgSender(List<String> emailList) {
            this.emailList = emailList;
        }
    
        @Override
        public void send(String msg) {
            // Omitting concrete logic
            for (String email : emailList) {
                System.out.println(String.format("Send [%s] to %s by email", msg, email));
            }
        }
    }
    
    public class MessageMsgSender implements MsgSender { 
        // 和EmailMsgSender结构一致,故省略
    }
    
    public class PhoneMsgSender implements MsgSender { 
        // 和EmailMsgSender结构一致,故省略
    }
    

    搞个测试类,看下效果:

    public class TestMain {
        public static void main(String[] args) {
            List<String> emailList = new ArrayList<>(2);
            emailList.add("test1@i-learning.com");
            emailList.add("test2@i-learning.com");
            MsgSender emailMsgSender = new EmailMsgSender(emailList);
            Notification normalNotification = new NormalNotification(emailMsgSender);
            normalNotification.notify("There is a normal event");
    
            Notification trivialNotification = new TrivialNotification(emailMsgSender);
            trivialNotification.notify("There is a trivial event");
    
            List<String> phoneList = new ArrayList<>(2);
            phoneList.add("189****1199");
            phoneList.add("190****2202");
            MsgSender messageMsgSender = new MessageMsgSender(phoneList);
            Notification severeNotification = new SevereNotification(messageMsgSender);
            severeNotification.notify("There is a severe event");
    
            MsgSender phoneMsgSender = new PhoneMsgSender(phoneList);
            Notification urgentNotification = new UrgentNotification(phoneMsgSender);
            urgentNotification.notify("There is an urgent event");
        }
    }
    

    结果如下:

    Send [There is a normal event] to test1@i-learning.com by email
    Send [There is a normal event] to test2@i-learning.com by email
    Send [There is a trivial event] to test1@i-learning.com by email
    Send [There is a trivial event] to test2@i-learning.com by email
    Send [There is a severe event] to 189****1199 by phone
    Send [There is a severe event] to 190****2202 by phone
    Send [There is an urgent event] to 189****1199 by phone
    Send [There is an urgent event] to 190****2202 by phone
    

    代码地址

    i-learning

    写在最后

    如果你觉得我写的文章帮到了你,欢迎点赞、评论、分享、赞赏哦,你们的鼓励是我不断创作的动力~

    相关文章

      网友评论

        本文标题:设计模式系列篇(六)——桥接模式

        本文链接:https://www.haomeiwen.com/subject/xrgwjktx.html