桥接模式——抽象与实现之间的桥梁

  桥接模式是一个相对来说比较难以理解的设计模式,它主要的思想是将抽象和实现两个维度进行分离,使其能够在各自的体系中单独的变化,然后用桥接的方式,将两者联系在一起。在使用桥接模式的时候,我们首先要分清楚抽象和实现的两个维度,然后才能做连个体系的桥接。
  这里我们先举个发送消息的例子,代码实现在后面进行举例。发送消息有这样一个场景,可以发送普通的email消息,也可以发送普通的微信消息,同时email和微信消息还可以加急发送,在后续的业务发展中,有可能还会增加新的手机短信消息,也会增加特急的发送消息。在这个业务场景中,我们仔细研究会发现,发送消息的方式是一个维度,其中包括了email、微信和手机短信;另外,发送消息的紧急程度是另外一个维度,其中包括了普通消息、加急消息和特急消息,这两个维度的相互交叉,最终确定了发送什么样的消息。在发送方式和紧急程度这两个维度上,我们进一步分析会发现,发送方式是具体的实现,而发送的紧急程度可以理解为一种抽象的发送模式,在此基础上,就将两个维度进行了细分,然后用一个桥接的方式进行组合,就能做到两个维度的轻松的扩展。
  下面我们就来探讨一下具体的实现:

桥接模式结构详解

1. 桥接模式的类图如下:

桥接模式——抽象与实现之间的桥梁_第1张图片

2. 桥接模式中类详解

  • Abstraction: 抽象部分的接口。这个对象通常是一个抽象类,因为在桥接模式中,两个维度要进行连接,将实现部分抽象成接口,就要将抽象部分抽象成一个抽象类,这样可以在抽象类中规定好需要持有的实现的基础接口,用来规范整体的结构。同时在这个抽象对象中,会定义好具体业务实现的基础实现方法。
  • RefinedAbstraction:扩展的抽象部分的对象。在这些对象中,定义和实际业务相关的方法,这些方法的实现通常会调用在Abstraction中和持有的接口中的方法来实现具体的逻辑。
  • Implementor:实现部分的顶层接口。通常这个接口中的方法和Abstraction中的具体业务方法逻辑上一致。
  • ConcreteImplementorAConcreteImplementorB:具体的业务实现。

发送消息的示例代码

前文中已经对发送消息的场景进行了解释,这里我们实现具体的代码示例:

1. 首先我们定义一个发送消息的实现顶层接口MessageImplementor,并实现email和微信两个具体的发送消息的实现类

/**
 * 消息实现的顶层接口
 * @author :
 */
public interface MessageImplementor {
    /**
     * 发送消息
     * @param message :消息体
     * @param user : 发送用户
     */
    void send(String message,String user);
}

/**
 * email发送消息
 */
public class MessageEmail implements MessageImplementor {
    @Override
    public void send(String message, String user) {
        System.out.println("用Email发送消息 :" + message + " 给用户:" + user);
    }
}
/**
 * 微信发送消息
 */
public class MessageWechat implements MessageImplementor {
    @Override
    public void send(String message, String user) {
        System.out.println("用微信发送消息 :" + message + " 给用户:" + user);
    }
}

2. 接下来我们定义抽象的实现部分顶层抽象类AbstractMessage和其子类普通消息和加急消息实现类

/**
 * 抽象消息类
 */
public abstract class AbstractMessage {

    private MessageImplementor implementor;

    public AbstractMessage(MessageImplementor implementor) {
        this.implementor = implementor;
    }

    public void send(String message, String user) {
        this.implementor.send(message, user);
    }
}
/**
 * 普通消息
 */
public class CommonMessage extends AbstractMessage{
    public CommonMessage(MessageImplementor implementor) {
        super(implementor);
    }
}
/**
 * 加急消息
 */
public class UrgencyMessage extends AbstractMessage {
    public UrgencyMessage(MessageImplementor implementor) {
        super(implementor);
    }

    @Override
    public void send(String message, String user) {
        message = "[加急]" + message;
        super.send(message, user);
    }
}

3. 新建一个测试类,分别测试发送普通消息和加急消息

public class Client {


    @Test
    public void testCommonMessage() {
        System.out.println("-----------------发送【普通】的【email消息】-------------------------");
        AbstractMessage commonMessage = new CommonMessage(new MessageEmail());
        commonMessage.send("hello world!", "all people");
        System.out.println("-----------------发送【普通】的【微信消息】-------------------------");
        commonMessage = new CommonMessage(new MessageWechat());
        commonMessage.send("hello world!", "all people");
    }

    @Test
    public void testUrgencyMessage() {
        System.out.println("-----------------发送【加急】的【email消息】-------------------------");
        AbstractMessage urgencyMessage = new UrgencyMessage(new MessageEmail());
        urgencyMessage.send("hello world!", "all people");
        System.out.println("-----------------发送【加急】的【微信消息】-------------------------");
        urgencyMessage = new UrgencyMessage(new MessageWechat());
        urgencyMessage.send("hello world!", "all people");
    }
}

测试结果如下:

-----------------发送【普通】的【email消息】-------------------------
用Email发送消息 :hello world! 给用户:all people
-----------------发送【普通】的【微信消息】-------------------------
用微信发送消息 :hello world! 给用户:all people
-----------------发送【加急】的【email消息】-------------------------
用Email发送消息 :[加急]hello world! 给用户:all people
-----------------发送【加急】的【微信消息】-------------------------
用微信发送消息 :[加急]hello world! 给用户:all people

4. 此时,如果业务需要新增特急消息和手机短息发送的方式,我们可以直接新建两个对象,分别加入各自的体系

/**
 * 特急消息
 */
public class SpecialUrgencyMessage extends AbstractMessage {
    public SpecialUrgencyMessage(MessageImplementor implementor) {
        super(implementor);
    }

    @Override
    public void send(String message, String user) {
        message = "[特急]" + message;
        super.send(message, user);
    }
}
/**
 * 手机短信发送消息
 *
 * @author :
 */
public class MessageMobile implements MessageImplementor {
    @Override
    public void send(String message, String user) {
        System.out.println("用手机短信发送消息 :" + message + " 给用户:" + user);
    }
}

编写一个测试方法,测试发送特急的手机消息

public class Client {

    @Test
    public void testSpecialUrgencyMobileMessage() {
        System.out.println("-----------------发送【特急】的【手机消息】-------------------------");
        AbstractMessage specialMessage = new SpecialUrgencyMessage(new MessageMobile());
        specialMessage.send("hello world!", "all people");
    }
}

测试结果如下:

-----------------发送【特急】的【手机消息】-------------------------
用手机短信发送消息 :[特急]hello world! 给用户:all people

5. 发送消息示例类图

桥接模式——抽象与实现之间的桥梁_第2张图片

总结

  • 桥接模式和抽象工厂模式的对比
      桥接模式和抽象工厂模式都会涉及到两个维度的概念,但是桥接模式是结构型模式,它是为了解决具体业务中实现和抽象两个维度进行分离;而抽象工厂是创建型模式,它解决的主要是产品族的创建问题,分离产品和创建工厂两个维度,是为了将有相关关联的产品族用同一个创建类创建出来,就不会出现混乱的情况。
  • 桥接模式的重点是分离抽象和实现两个部分,具体的桥接在代码上就是一个组合。很多人比较看重具体的代码实现,看着代码实现就是一个组合,就感觉和其他的模式差不多,这个是学习设计模式的一个常见的误区。因为设计模式是思维层面的东西,它是为了解决特定问题的一种经验总结,具体到怎么实现,是和具体的语言特性相关的,java语言对象之间的连接要么就是继承,要么就是组合,所以才会在很多的设计模式(比如对象适配器、策略模式等)中,相互关联都是采用组合的方式。我们学习设计模式的重点应该放在如何去理解和举一反三设计思想上,而不是具体的实现上。

后记
  个人总结,欢迎转载、评论、批评指正

你可能感兴趣的:(设计模式,桥接模式,java,设计模式)