设计模式-桥接模式
定义
桥接模式(Bridge Pattern)也称为桥梁模式、接口(Interface)模式或柄体(Handle and Body)模式,是将抽象部分和它的具体实现部分分离,使它们都可以独立地变化.
通过组合的方式建立连个类之间的联系,而不是继承.但又类似于多重继承方案,但是多重继承方案往往违背了类的单一职责原则,其复用性比较差,桥接模式是比多重继承更好的替代方案.桥接模式的核心在于解耦抽象和实现.
属于结构型设计模式.
桥接模式类图UML从UML类图中我们可以看到,桥接模式主要包含4种角色:
1、抽象(Abstraction):该类持有一个对实现角色的引用,抽象角色中的方法需要实现角色来实现.抽象角色一般为抽象类(构造函数规定子类要传入一个实现对象);
2、修正抽象(RefinedAbstraction):Abstraction的具体实现,对Abstraction的方法进行完善和扩展;
3、实现(Implementor):确定实现维度的基本操作,提供给Abstraction使用.该类一般为接口或抽象类;
4、具体实现(ConcreteImplementor):Implementor的具体实现.
代码实例
举个例子,我们平时办公的时候经常通过发邮件消息、短信消息或者系统内消息和同事进行沟通.尤其是在走一些审批流程的时候,我们需要记录这些过程以备查.我们根据消息类别来划分的话,可以分为邮件消息、短信信息和系统内消息.但是,根据消息的紧急程度来划分的话,可以分为普通消息、紧急消息和特级消息.显然,整个消息系统可以划分为两个维度.
如果,我们用继承的话情况就复杂啦,而且也不利于扩展.邮件信息可以是普通的,也可以是紧急的;短信消息可以是普通的,也可以是紧急的.看代码:
创建IMessage接口担任桥接的角色 邮件信息实现类 手机短信实现类 桥接抽象消息类 具体实现普通消息 具体实现紧急消息 测试代码 运行结果上面的案例中,我们采用桥接模式解耦了“消息类型”和“消息紧急程度”这两个独立变化的维度.后续如果有更多的消息类型,不如微信、钉钉等,那么直接新建一个类继承IMessage即可;如果是紧急程度需要新增,那么同样只需新建一个类实现AbstractMessage类即可.UML图如下:
UML类图桥接模式在源码中的应用
大家非常熟悉的JDBC API,其中有一个Driver类就是桥接对象.我们都知道,我们在使用的时候通过Class.forName()方法可以动态加载各个数据库厂商实现的Driver类.具体客户端应用代码如下,
以MySQL的实现为例:
MySQL具体实现类首先,我们来看一下Driver接口的定义:
Driver接口Driver在JDBC中并没有做任何实现,具体的功能实现由各厂商完成,我们以MySQL的实现为例.
Mysql的实现当我们执行Class.forName("com.mysql.jdbc.Driver")方法的时候,就会执行com.mysql.jdbc.Driver这个类的静态块中的代码.而静态块中的代码只是调用了一下DriverManager的registerDriver()方法,然后将Driver对象注册到DriverManager中.我们可以继续跟进到DriverManager这个类中,来看相关代码:
DriverManager类在注册之前,将转过来的Driver对象,封装成一个DriverInfo对象.接下来继续执行客户端代码的第二步,调用DriverManager的getConnection()方法获取连接对象,我们跟进源码:
getConnection()方法在getConnection()方法中就又会调用各自厂商实现的Driver的connect()方法获得连接对象.这样的话,就巧妙的避开了使用继承,为不同的数据库提供了相同的接口.JDBC API中DriverManager就是桥,如下图所示:
JDBC API类图适用场景
1、在抽象和具体实现之间需要增加更多的灵活性的场景.
2、一个类存在两个(或多个)独立变化的维度,而这两个(或多个)纬度都需要独立进行扩展.
3、不希望适用继承,或因为多层继承导致系统类的个数剧增.
优点
1、分离抽象部分及其具体实现部分;
2、提高了系统的扩展性;
3、符合开闭原则;
4、符合合成复用原则.
缺点
1、增加了系统的理解和设计难度;
2、需要正确地识别系统中两个独立变化的纬度.
桥接相关的设计模式
1、桥接模式和组合模式
2、桥接模式和适配器模式
网友评论