Java设计模式(十)之结构型模式:桥接模式
桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯或者使用,桥接模式的作用就是为被分离了的抽象部分和实现部分搭桥。在现实生活中也有很多这样的例子,一个物品在搭配不同的配件时会产生不同的动作和结果,例如一辆赛车搭配的是硬胎或者是软胎就能够在干燥的马路上行驶,而如果要在下雨的路面行驶,就需要搭配雨胎了,这种根据行驶的路面不同,需要搭配不同的轮胎的变化的情况,我们从软件设计的角度来分析,就是一个系统由于自身的逻辑,会有两个或多个维度的变化,有时还会形成一种树状的关系,而为了应对这种变化,我们就可以使用桥接模式来进行系统的解耦。
桥接模式,作用是将一个系统的抽象部分和实现部分分离,使它们都可以独立地进行变化,对应到上面就是赛车的种类可以相对变化,轮胎的种类可以相对变化,形成一种交叉的关系,最后的结果就是一种赛车对应一种轮胎就能够成功产生一种结果和行为。
一、定义:
桥接模式,就是将抽象与他的实现部分分离,这样抽象化与实现化解耦,使他们可以独立的变化。将抽象部分与实现部分分离,使他们都可以独立地进行变化。为了达到让抽象部分和实现部分独立变化的目的,抽象部分会拥有实现部分的接口对象,有了实现部分的接口对象之后,就能够通过这个接口来调用具体实现部分的功能。桥接在程序上就体现成了抽象部分拥有实现部分的接口对象,维护桥接就是维护这个关系,也就是说,桥接模式中的桥接是一个单方向的关系,只能够抽象部分去使用实现部分的对象,而不能反过来。
UML结构类图:
桥接模式分为四个角色:
(1)Abstraction(抽象部分):该类保持一个对实现部分对象的引用,抽象部分中的方法需要调用实现部分的对象来实现,该类一般为抽象类;
(2)RefinedAbstraction(抽象部分的具体实现):该类一般对抽象部分的方法进行完善和扩展;
(3)Implementor(实现部分):可以为接口或者是抽象类,其方法不一定要与抽象部分中的一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分基本操作的业务方法;
(4)ConcreteImplementorA 和 ConcreteImplementorB (实现部分的具体实现):完善实现部分中定义的具体逻辑。
二、代码实现:
Implementor 接口类:
public interface Implementor {
void operationImpl();
}
接口实现类:
public class ConcreteImplementorA implements Implementor{
@Override
public void operationImpl() {
//具体实现
}
}
public class ConcreteImplementorB implements Implementor{
@Override
public void operationImpl() {
//具体实现
}
}
抽象类:
public abstract class Abstraction {
private Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public void operation() {
implementor.operationImpl();
}
}
抽象类的具体实现:
public class RefinedAbstraction extends Abstraction{
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
public void refinedOperation() {
//对 Abstraction 中的 operation 方法进行扩展
}
}
看了这段通用代码之后,桥接模式的结构应该就很清楚了,需要注意的一点是 RefinedAbstraction 类根据实际情况是可以有多个的。
当然上面的 uml 类图和通用代码只是最常用的实现方式而已,在实际使用中可能会有其他的情况,比如 Implementor 只有一个类的情况,虽然这时候可以不去创建 Implementor 接口,精简类的层次,但是我建议还是需要抽象出实现部分的接口。
三、数据库中的桥接模式:
像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,然后使用桥接模式创建一个连接数据库的驱动,然后对每一个数据库提供各自的实现.对于使用某一个数据库的时候只需要切换一下就行.。我们来看看关系图:
数据库接口 :
public interface Driver {
public void connect();
}
Mysql数据库实现类:
public class MysqlDriver implements Driver {
@Override
public void connect() {
System.out.println("连接Mysql数据库");
}
}
SqlServer数据库实现类:
public class SqlServerDriver implements Driver {
@Override
public void connect() {
System.out.println("连接SQLServer数据库");
}
}
桥接类(抽象类):
public abstract class Bridge {
private Driver driver;
public void connect(){
driver.connect();
}
public void setDriver(Driver driverTemp){
this.driver = driverTemp;
}
public Driver getDriver(){
return this.driver;
}
}
桥接类(实现类):
public class MyBridge extends Bridge {
}
测试类:
public class BridgeTest {
public static void main(String[] args) {
Bridge mysqlBridge = new MyBridge();
Driver mysqlDriver = new MysqlDriver();
mysqlBridge.setDriver(mysqlDriver);
mysqlBridge.connect();
Driver sqlServerDriver = new SqlServerDriver();
mysqlBridge.setDriver(sqlServerDriver);
mysqlBridge.connect();
}
}
运行结果:
连接Mysql数据库
连接SQLServer数据库
四、桥接模式小结:
1、优点:
(1)分离抽象接口及其实现部分.提高了比继承更好的解决方案;
(2)桥接模式提高了系统的可拓展性,在两个变化维度中任意扩展一个维度,都不需要修改原来的系统,符合“开闭原则”;
(3)实现细节对客户不透明,可以隐藏实现细节。
2、缺点:
桥接模式的引入会增加系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行编程。
3、桥接模式适用于以下的情形:
(1)如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,可以通过桥接模式使他们在抽象层建立一个关联关系;
(2)那些不希望使用继承或因为多层次继承导致系统类的个数极具增加的系统;
(3)一个类存在两个独立变化的维度,而这两个维度都需要进行扩展。
原博客链接:
https://blog.****.net/self_study/article/details/51622243
https://blog.****.net/yeguxin/article/details/77337838