设计模式详解(七)——桥接模式

    科技2024-07-30  62

    一、场景问题

    某系统需要实现消息推送的需求。其中消息的类型包含普通、紧急、严重三种类型,消息的发送渠道又可以分为邮件、短信等方式。请设计出一套合理的消息推送的程序。

    二、解决方案

    1、传统解决方案

    1.1、设计思路

    消息类型分为三种,消息的发送渠道又分为两种,两个不同维度可以分为2*3=6种类型。

    消息类型普通邮件消息普通短信消息紧急邮件消息紧急短信消息严重邮件消息严重短信消息

    1.2、代码实现

    顶层消息接口

    public interface Message { /** * 发送消息 * @param content 消息内容 * @param toUser 消息发送对象 **/ void send(String content, String toUser); }

    6种消息类型

    普通邮件消息

    public class CommonMailMessage implements Message { @Override public void send(String content, String toUser) { System.out.println("发送普通邮件消息给" + toUser + ",消息内容:" + content); } }

    普通短信消息

    public class CommonSmsMessage implements Message { @Override public void send(String content, String toUser) { System.out.println("发送普通短信消息给" + toUser + ",消息内容:" + content); } }

    紧急邮件消息

    public class UrgentMailMessage implements Message { @Override public void send(String content, String toUser) { System.out.println("发送紧急邮件消息给" + toUser + ",消息内容:" + content); } }

    紧急短信消息

    public class UrgentSmsMessage implements Message { @Override public void send(String content, String toUser) { System.out.println("发送紧急短信消息给" + toUser + ",消息内容:" + content); } }

    严重邮件消息

    public class SeriousMailMessage implements Message { @Override public void send(String content, String toUser) { System.out.println("发送严重邮件消息给" + toUser + ",消息内容:" + content); } }

    严重短信消息

    public class SeriousSmsMessage implements Message { @Override public void send(String content, String toUser) { System.out.println("发送严重短信消息给" + toUser + ",消息内容:" + content); } }

    客户端测试

    public static void main(String[] args) { Message message = new UrgentMailMessage(); message.send("1号服务器宕机了!", "贤子磊"); Message message2 = new CommonSmsMessage(); message2.send("明天一起吃饭哈。", "贤子磊"); }

    输出

    发送紧急邮件消息给贤子磊,消息内容:1号服务器宕机了! 发送普通短信消息给贤子磊,消息内容:明天一起吃饭哈。

    1.3、弊端分析

    这样设计看似是蛮不错的设计方案,但是存在极大地问题

    如果后续消息的发送途径新增了其他形式,消息的类型也扩展了其余形式,则类的数量成倍地增长,导致系统过于臃肿,难以维护。如果消息的发送方式各式各样,很难使用统一的动作来定义消息的发送,扩展性极差。

    2、桥接模式方案

    既然消息的定义维度存在多种,那么我们可以通过组合的方式来实现。这就引出了桥接模式。

    2.1、代码实现

    我们将消息分为发送渠道和等级类型两种组合,两种组合互不干扰,通过组合的方式进行桥接。这里由于只有两个维度,为了简单起见,我们将等级类型整合到消息的主干上,发送渠道作为组件组合到主干上。

    定义发送渠道抽象接口及实现

    渠道接口

    public interface Channel { String getDescription(); }

    接口实现

    邮件渠道

    public class MailChannel implements Channel{ @Override public String getDescription() { return "邮件"; } }

    短信渠道

    public class SmsChannel implements Channel{ @Override public String getDescription() { return "短信"; } }

    定义消息主干抽象类及等级类型的实现

    消息主干抽象类

    public abstract class AbstractMessage { /** * 消息的发送渠道 */ protected Channel channel; /** * 消息的类型 */ protected String level; /** * 发送消息 * @param content 消息内容 * @param toUser 消息发送对象 * @author xianzilei **/ public abstract void send(String content, String toUser); }

    等级类型的实现

    普通消息

    public class CommonMessage extends AbstractMessage { public CommonMessage(Channel channel) { super.channel = channel; super.level = "普通"; } @Override public void send(String content, String toUser) { System.out.println("发送" + level + channel.getDescription() + "消息给" + toUser + ",消息内容:" + content); } }

    紧急消息

    public class UrgentMessage extends AbstractMessage { public UrgentMessage(Channel channel) { super.channel = channel; super.level = "紧急"; } @Override public void send(String content, String toUser) { System.out.println("发送" + level + channel.getDescription() + "消息给" + toUser + ",消息内容:" + content); } }

    严重消息

    public class SeriousMessage extends AbstractMessage { public SeriousMessage(Channel channel) { super.channel = channel; super.level = "严重"; } @Override public void send(String content, String toUser) { System.out.println("发送" + level + channel.getDescription() + "消息给" + toUser + ",消息内容:" + content); } }

    客户端测试

    public static void main(String[] args) { Channel channel = new SmsChannel(); AbstractMessage message = new SeriousMessage(channel); message.send("数据库服务器宕机了!", "贤子磊"); }

    输出

    发送严重短信消息给贤子磊,消息内容:数据库服务器宕机了!

    三、模式剖析

    1、模式定义

    桥接模式(Bridge Pattern):将抽象与实现分离,使它们可以独立变化。

    2、模式结构

    桥接模式一般包含如下角色

    Abstraction:抽象化角色

    一般为抽象类,并包含一个对实现化对象的引用

    abstract class Abstraction { //实现化对象的引用 protected Implementor imple; protected Abstraction(Implementor imple) { this.imple=imple; } public abstract void Operation(); }

    Refined Abstraction:扩展抽象化角色

    是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法

    class RefinedAbstraction extends Abstraction { protected RefinedAbstraction(Implementor imple) { super(imple); } public void Operation() { System.out.println("扩展抽象化(Refined Abstraction)角色被访问" ); imple.OperationImpl(); } }

    Implementor:实现化角色

    定义实现化角色的接口,供扩展抽象化角色调用

    interface Implementor { public void OperationImpl(); }

    Concrete Implementor:具体实现化角色

    给出实现化角色接口的具体实现

    class ConcreteImplementorA implements Implementor { public void OperationImpl() { System.out.println("具体实现化(Concrete Implementor)角色被访问" ); } }

    3、模式结构图

    4、优缺点

    优点 分离了抽象与实现部分,极大地提高系统的灵活性和扩展性。有助于对系统进行分层,从而更好地结构化系统;同时也使得抽象和实现部分可以分别独立地扩展,减少耦合性。分离抽象后,可以实现动态选择具体的实现。利用反射等手段可以轻松动态切换。大大减少子类的个数,只需要定义不同的变化维度的结构,通过组合的方式就可以实现功能。 缺点 由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,这增加了系统的理解与设计难度

    5、使用场景

    如果希望将抽象部分和实现部分分离,可以尝试使用桥接模式。采用继承方式会导致产生很多子类的时候,可以使用桥接模式+组合的方式分离不同维度来减少子类的数目。
    Processed: 0.009, SQL: 8