定义

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

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

我们来思考一下

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

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

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

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

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

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

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

UML

优点

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

缺点

  1. 增加了复杂度;

应用场景

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

示例

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

Java

 public class Main
{
public static void main(String[] args)
{
//创建具体的实现对象
MessageImplementor impl = new MessageSMS();
//创建一个普通消息对象
AbstractMessage m = new CommonMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
//创建一个紧急消息对象
m = new UrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
//创建一个特急消息对象
m = new SpecialUrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李"); //把实现方式切换成手机短消息,然后再实现一遍
impl = new MessageMobile();
m = new CommonMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new UrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
m = new SpecialUrgencyMessage(impl);
m.sendMessage("请喝一杯茶", "小李");
} /**
* 消息发送方式的接口
*/
public static interface MessageImplementor
{
void send(String message,String toUser);
} /**
* 消息抽象类
*/
public static abstract class AbstractMessage
{
protected MessageImplementor impl; public AbstractMessage(MessageImplementor impl)
{
this.impl = impl;
} public void sendMessage(String message,String toUser)
{
this.impl.send(message, toUser);
}
} /**
* 站内发送消息实现类
*/
public static class MessageSMS implements MessageImplementor
{
public void send(String message, String toUser)
{
System.out.println("使用站内短消息的方式,发送消息'" + message + "'给" + toUser);
}
} /**
* 电子邮件发送消息实现类
*/
public static class MessageEmail implements MessageImplementor
{
public void send(String message, String toUser)
{
System.out.println("使用Email的方式,发送消息'" + message + "'给" + toUser);
}
} /**
* 普通消息类
*/
public static class CommonMessage extends AbstractMessage
{
public CommonMessage(MessageImplementor impl)
{
super(impl);
} public void sendMessage(String message, String toUser)
{
//对于普通消息,什么都不干,直接调父类的方法,把消息发送出去就可以了
super.sendMessage(message, toUser);
}
} /**
* 加急消息类
*/
public static class UrgencyMessage extends AbstractMessage
{
public UrgencyMessage(MessageImplementor impl)
{
super(impl);
} public void sendMessage(String message, String toUser)
{
message = "加急:" + message;
super.sendMessage(message, toUser);
} public Object watch(String messageId)
{
//获取相应的数据,组织成监控的数据对象,然后返回
return null;
}
} /**
* 短信发送消息实现类
*/
public static class MessageMobile implements MessageImplementor
{
public void send(String message, String toUser)
{
System.out.println("使用手机短消息的方式,发送消息'"+message+"'给"+toUser);
}
} /**
* 特急消息类
*/
public static class SpecialUrgencyMessage extends AbstractMessage
{
public SpecialUrgencyMessage(MessageImplementor impl)
{
super(impl);
} public void hurry(String messageId)
{
//执行催促的业务,发出催促的信息
} public void sendMessage(String message, String toUser)
{
message = "特急:"+message;
super.sendMessage(message, toUser);
//还需要增加一条待催促的信息
}
}
}

结构类模式(二):桥接(Bridge)的更多相关文章

  1. 设计模式之结构类模式大PK

                                      结构类模式大PK 结构类模式包括适配器模式.桥梁模式.组合模式.装饰模式.门面模式.享元模式和代理模式.之所以称其为结构类模式,是因 ...

  2. 设计模式之结构类模式PK

    结构类模式包括: 适配器模式 桥梁模式 组合模式 装饰模式 门面模式 享元模式 代理模式 结构类模式着重于如何建立一个软件结构 为什么叫结构类模式呢? 因为他们都是通过组合类或对象产生更大结构以适应更 ...

  3. 桥接模式二(Bridge)

    昨天写到了桥接模式的代码实现,今天我们就继续来讲完桥接模式.      有认真看的会发现,昨天的代码实现只是两个维度的变化:哪么有人可能就会问了哪如果我要加多一个维度呢?我要具体到企业的哪个部门,哪我 ...

  4. 结构型模式(二) 桥接模式(Bridge)

    一.动机(Motivation) 在很多游戏场景中,会有这样的情况:[装备]本身会有的自己固有的逻辑,比如枪支,会有型号的问题,同时现在很多的游戏又在不同的介质平台上运行和使用,这样就使得游戏的[装备 ...

  5. 结构类模式(三):组合(Composite)

    定义 将对象组合成树形结构以表示“部分整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客 ...

  6. 结构类模式(四):装饰(Decorator)

    定义 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 特点 装饰对象和真实对象有相同的接口.这样客户端对象就能以 ...

  7. 结构类模式(七):代理(Proxy)

    定义 为其他对象提供一种代理以控制对这个对象的访问. 代理模式也叫做委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应 ...

  8. 结构类模式(六):享元(Flyweight)

    定义 运用共享技术有效的支持大量细粒度的对象. 两个状态 内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的. 外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保 ...

  9. 结构类模式(五):外观(Facade)

    定义 为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用. UML 优点 对客户屏蔽了其子系统组件,因而减少了客户处理对象的数目,并使得子系统实用起来更方便. ...

随机推荐

  1. 850 USB 烧录模式

    /************************************************************************* * 850 USB 烧录模式 * 说明: * 本文 ...

  2. struts2自定义声明校验器

    1 //新建一个validators.xml在src根资源下,会覆盖default.xml的validators,所以你懂得 //接着,若使用声明式校验,则要把配置文件xxxAction-valida ...

  3. poj 1986 Distance Queries

    好像是模板题  当作练习题 不错:  要求任意两点之间的距离.可以假设一个根节点,然后所有点到根节点的距离,然后求出任意两点多公共祖先:  距离就变成了 dis[u]+dis[v] - 2*dis[ ...

  4. 把十进制数(long型)分别以二进制和十六进制形式输出,不能使用printf系列。

    编程实现:把十进制数(long型)分别以二进制和十六进制形式输出,不能使用printf系列. 实现了unsigned long型的转换. // 十进制转换为二进制,十进制数的每1bit转换为二进制的1 ...

  5. 【原创】搭建Nginx(负载均衡)+Redis(Session共享)+Tomcat集群

    为什么移除首页?哪里不符合要求?倒是回我邮件啊! 一.环境搭建 Linux下Vagrant搭建Tomcat7.Java7 二.Nginx的安装配置与测试 *虚拟机下转至root sudo -i 1)下 ...

  6. 如何自定义一个优雅的ContentProvider

    最近在code review的时候发现很多人的provider定义的不是很好,写的很粗糙 以至于代码健壮性不够好,可读性也不强 但是你既然写了content provider 就是要给别人调用的,如果 ...

  7. RDoc

    RDoc - Ruby Documentation System home github.com/rdoc/rdoc rdoc docs.seattlerb.org/rdoc bugs github. ...

  8. source 命令

    作用: 当我修改了/etc/profile文件,我想让它立刻生效,而不用重新登录:这时就想到用source命令,如:source /etc/profile 介绍:source命令也称为“点命令”,也就 ...

  9. c# is和as的区别

    关于类型的判断和转换有is和as这2个操作符.具体区别和用法如下is就是处于对类型的判断.返回true和false.如果一个对象是某个类型或是其父类型的话就返回为true,否则的话就会返回为false ...

  10. hdu 2476(第一道区间dp)

    题意:就是给定两个字符串,第一个是初始串,第二个是目标串,问你把初始串变到目标串最少需要多少串! 分析:此题分两步,第一步是假设开始的初始串是空串,然后就进行区间dp,dp[i][j]代表把区间[i, ...