桥接模式(Bridge Pattern),将抽象和实现解耦,让他们可以独立的变化。
只看上面的说明是没法明白桥接模式的,桥接模式也是设计模式中几个较难理解的模式之一。
再详细的说,上面的解释包含两个概念:抽象和实现。
抽象并不是抽象类或接口,是将易变的部分抽离之后的部分,也就是说原本这个抽象并不是抽象,而是带有具体实现的,的但这个具体实现又是存在多种演变的可能,所以将这一部分具体实现抽离,剩下的部分就称之为抽象,而被抽离出去的具体实现,我们就叫做实现。
比如我们Java中用到的JDBC连接数据库做CRUD操作。代码一般是这样的:
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/tt_db?user=test&password=password";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
String query = "select * from test";
ResultSet rs=stmt.executeQuery(query);
......
这里的Class.forName(“com.mysql.jdbc.Driver”)作用就是加载jdbc驱动,就是我们上面说的被抽出来的”实现”的角色,不同的数据库实现了不同的jdbc driver,我们使用哪种数据库,就加载哪种数据库的驱动就可以了。
而DriverManager就是抽象部分,为什么呢,因为在上面加载mysql驱动的时候,mysql将自己注册到了DriverManager中,mysql的源码如下:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
请看这一行:DriverManager.registerDriver(new Driver())
这里的new Driver()就是new的mysql的Driver,然后注册到了DriverManager中,DriverManager也就有了操作数据库的具体功能了。
所以在JDBC中DriverManager就相当于抽象,而各种数据库的驱动就相当于实现,这种实现是多种多样的,所以将其抽出来,各自实现各自演化,而DriverManager不必关心。
理解了上面的抽象和实现,再来看我们今天的例子。
我们今天就以灯泡和开关为例,来讲解桥接模式。
我们都知道,灯有多种多样,有普通的单色灯,也有可以变色的彩色灯;同样的,开关也有多种多样,有嵌在墙上的普通开关,也有遥控开关。
这里就引出了我们上面说的抽象和实现了。开关相当于抽象,灯相当于实现。我的开关可以控制各种各样的灯,而不应该将开关和灯绑死,比如灯坏了,换一个灯,你肯定不希望连墙上的没坏的开关也换掉。并且如果是绑死的效果,那代码就变成了开关和灯的代码写到一起了,这当然不是一个好的设计,所以这里我们就使用桥接模式来进行改造。
1、灯的抽象定义
package com.itzhimei.study.design.bridge;
/**
* @Auther: www.itzhimei.com
* @Description: 灯的抽象定义
*/
public interface ILight {
/**
* 灯照明
*/
void lighting();
/**
* 灯变色
*/
void changeColor();
/**
* 灯熄灭
*/
void goesOut();
}
2、普通单色灯
package com.itzhimei.study.design.bridge;
/**
* @Auther: www.itzhimei.com
* @Description: 普通单色灯
*/
public class NormalLight implements ILight {
@Override
public void lighting() {
System.out.println("NormalLight灯被打开了,开始照明...");
}
@Override
public void changeColor() {
System.out.println("NormalLight普通单色灯,没有变色功能...");
}
@Override
public void goesOut() {
System.out.println("NormalLight灯被关闭了...");
}
}
3、可以变换颜色的彩色灯
package com.itzhimei.study.design.bridge;
/**
* @Auther: www.itzhimei.com
* @Description: 可以变换颜色的彩色灯
*/
public class ColorLight implements ILight {
@Override
public void lighting() {
System.out.println("ColorLight灯被打开了,开始照明...");
}
@Override
public void changeColor() {
System.out.println("ColorLight灯变色了,红绿蓝变色中...");
}
@Override
public void goesOut() {
System.out.println("ColorLight灯关闭了...");
}
}
4、普通嵌在墙上的开关,开关即能控制普通灯,也能控制彩色灯
package com.itzhimei.study.design.bridge;
/**
* @Auther: www.itzhimei.com
* @Description: 普通嵌在墙上的开关
*/
public class NormalSwitch implements ISwitch {
ILight light;
public NormalSwitch(ILight light) {
this.light = light;
}
@Override
public void turnOn() {
light.lighting();
}
@Override
public void changeColor() {
light.changeColor();
}
@Override
public void turnOff() {
light.goesOut();
}
}
5、测试
package com.itzhimei.study.design.bridge;
/**
* @Auther: www.itzhimei.com
* @Description: 测试
*/
public class Client {
public static void main(String[] args) {
ILight normalLight = new NormalLight();
ILight colorLight = new ColorLight();
ISwitch normalSwitch1 = new NormalSwitch(normalLight);
normalSwitch1.turnOn();
normalSwitch1.changeColor();
normalSwitch1.turnOff();
ISwitch normalSwitch2 = new NormalSwitch(colorLight);
normalSwitch2.turnOn();
normalSwitch2.changeColor();
normalSwitch2.turnOff();
}
}
输出:
NormalLight灯被打开了,开始照明...
NormalLight普通单色灯,没有变色功能...
NormalLight灯被关闭了...
ColorLight灯被打开了,开始照明...
ColorLight灯变色了,红绿蓝变色中...
ColorLight灯关闭了...
我们测试代码中,使用的普通开关,控制了两种灯,而且开关不限于控制这两种灯,还可以扩展出各种灯,都能让开关控制,这就是前面说到的“实现”的单独扩展能力。
当然开关也是可以再扩展的,我们可以新建遥控开关来控制灯的开关和颜色,这就达到了抽象和实现的双重独立演变。
类关系图:
总结:
理解桥接模式,一定要理解其中的“抽象”和“实现”的概念和各自承担的职责。
桥接模式将实现,注入到了抽象中,让两种角色都可以各自演变,这是将类之间的依赖关系从继承改为了组合,从而达到了这样的效果。