• 结构类模式(二):桥接(Bridge)


    定义

    将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化。

    在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。

    我们来思考一下

    如果我们需要做一个发送消息的系统,发送方式有站内消息和邮件两种,发送类型有普通和加急两种,我想大家都会很自然的想到下面的做法:

    //消息接口
    IMessage
    //普通类型消息
    CommonMessageSMS//站内发送
    CommonMessageEmail//邮件发送
    //加急类型消息
    UrgentMessageSMS//站内发送
    UrgentMessageEmail//邮件发送

    好了,现在我们需要增加短信的发送方式和特级的发送类型,那么我们会发现这里出现了两个不同维度的变化,由于这两个维度相互关联,那么我们需要添加5个类才能完成需求,如下:

    //为普通和加急类型的消息添加短信发送方式
    CommonMessageMobile//短信发送
    UrgentMessageMobile//短信发送
    //添加特急类型的消息
    SpecialUrgencyMessageSMS//站内发送
    SpecialUrgencyMessageEmail//邮件发送
    SpecialUrgencyMessageMobile//短信发送

    现在我们发现,如果使用这种方式编写,当两个维度发生变化时,会导致类的数量暴增。如果使用桥接模式则可以缓解这个问题。

    使用桥接模式时,我们将消息类型和发生方式脱耦,首先,我们将两个维度分开,我们需要一个消息类,该类只需要关注消息的类型即可,在抽象出一个消息发送类,该类只关注消息的发送方式;

    消息类持有一个消息发送类的引用,通过改变传入的消息发送类达到动态的设定消息的发送方式。简单的说就是将继承改为聚合。

    UML

    优点

    1. 将实现予以解耦,让它和界面之间不再永久绑定;
    2. 抽象和实现可以独立扩展,不会影响到对方;
    3. 对于“具体的抽象类”所做的改变,不会影响到客户。

    缺点

    1. 增加了复杂度;

    应用场景

    1. 适合使用在需要跨越多个平台的图形和窗口上;
    2. 当需要用不同的方式改变接口和实现时,你会发现桥接模式很好用。

    示例

    我们使用桥接模式来实现一下上面的需求。

    Java

      1 public class Main
      2 {
      3     public static void main(String[] args)
      4     {
      5         //创建具体的实现对象
      6         MessageImplementor impl = new MessageSMS();
      7         //创建一个普通消息对象
      8         AbstractMessage m = new CommonMessage(impl);
      9         m.sendMessage("请喝一杯茶", "小李");
     10         //创建一个紧急消息对象
     11         m = new UrgencyMessage(impl);
     12         m.sendMessage("请喝一杯茶", "小李");
     13         //创建一个特急消息对象
     14         m = new SpecialUrgencyMessage(impl);
     15         m.sendMessage("请喝一杯茶", "小李");
     16         
     17         //把实现方式切换成手机短消息,然后再实现一遍
     18         impl = new MessageMobile();
     19         m = new CommonMessage(impl);
     20         m.sendMessage("请喝一杯茶", "小李");
     21         m = new UrgencyMessage(impl);
     22         m.sendMessage("请喝一杯茶", "小李");
     23         m = new SpecialUrgencyMessage(impl);
     24         m.sendMessage("请喝一杯茶", "小李");
     25     }
     26 
     27     /**
     28      * 消息发送方式的接口
     29      */
     30     public static interface MessageImplementor
     31     {
     32         void send(String message,String toUser);
     33     }
     34 
     35     /**
     36      * 消息抽象类
     37      */
     38     public static abstract class AbstractMessage
     39     {
     40         protected MessageImplementor impl;
     41         
     42         public AbstractMessage(MessageImplementor impl)
     43         {
     44             this.impl = impl;
     45         }
     46         
     47         public void sendMessage(String message,String toUser)
     48         {
     49             this.impl.send(message, toUser);
     50         }
     51     }
     52 
     53     /**
     54      * 站内发送消息实现类
     55      */
     56     public static class MessageSMS implements MessageImplementor
     57     {
     58         public void send(String message, String toUser)
     59         {
     60             System.out.println("使用站内短消息的方式,发送消息'" + message + "'给" + toUser);
     61         }
     62     }
     63 
     64     /**
     65      * 电子邮件发送消息实现类
     66      */
     67     public static class MessageEmail implements MessageImplementor
     68     {
     69         public void send(String message, String toUser)
     70         {
     71             System.out.println("使用Email的方式,发送消息'" + message + "'给" + toUser);
     72         }
     73     }
     74 
     75     /**
     76      * 普通消息类
     77      */
     78     public static class CommonMessage extends AbstractMessage
     79     {
     80         public CommonMessage(MessageImplementor impl)
     81         {
     82             super(impl);
     83         }
     84         
     85         public void sendMessage(String message, String toUser)
     86         {
     87             //对于普通消息,什么都不干,直接调父类的方法,把消息发送出去就可以了
     88             super.sendMessage(message, toUser);
     89         }
     90     }
     91 
     92     /**
     93      * 加急消息类
     94      */
     95     public static class UrgencyMessage extends AbstractMessage
     96     {
     97         public UrgencyMessage(MessageImplementor impl)
     98         {
     99             super(impl);
    100         }
    101         
    102         public void sendMessage(String message, String toUser)
    103         {
    104             message = "加急:" + message;
    105             super.sendMessage(message, toUser);
    106         }
    107         
    108         public Object watch(String messageId)
    109         {
    110             //获取相应的数据,组织成监控的数据对象,然后返回
    111             return null;
    112         }
    113     }
    114 
    115     /**
    116      * 短信发送消息实现类
    117      */
    118     public static class MessageMobile implements MessageImplementor
    119     {
    120         public void send(String message, String toUser)
    121         {
    122             System.out.println("使用手机短消息的方式,发送消息'"+message+"'给"+toUser);
    123         }
    124     }
    125 
    126     /**
    127      * 特急消息类
    128      */
    129     public static class SpecialUrgencyMessage extends AbstractMessage
    130     {
    131         public SpecialUrgencyMessage(MessageImplementor impl)
    132         {
    133             super(impl);
    134         }
    135         
    136         public void hurry(String messageId)
    137         {
    138             //执行催促的业务,发出催促的信息
    139         }
    140         
    141         public void sendMessage(String message, String toUser)
    142         {
    143             message = "特急:"+message;
    144             super.sendMessage(message, toUser);
    145             //还需要增加一条待催促的信息
    146         }
    147     }
    148 }
    View Code
  • 相关阅读:
    【JSOI 2008】 最大数
    【Usaco2008 Dec】Patting Heads
    【AHOI 2005】 约数研究
    【HAOI2007】反素数
    BZOJ3676 APIO2014回文串(manacher+后缀自动机)
    Luogu3804 【模板】后缀自动机(后缀自动机)
    后缀自动机学习笔记
    Codeforces ECR47F Dominant Indices(线段树合并)
    BZOJ1127 POI2008KUP(悬线法)
    BZOJ4652 NOI2016循环之美(莫比乌斯反演+杜教筛)
  • 原文地址:https://www.cnblogs.com/hammerc/p/4743784.html
Copyright © 2020-2023  润新知