设计模式之桥接模式
桥接模式定义:
桥接模式(Bridge)是一种结构型设计模式。Bridge模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
实现指的是抽象类和它的派生类用来实现自己的对象。
桥接模式核心意图就是把实现独立出来,让它们各自变化,使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。
为什么要优先使用合成/聚合原则?
1.对象的继承关系是在编译时就定义好了的。所以无法在执行时改变从父类继承的实现。子类的实现与它的父类有很紧密的依赖关系。以至于父类实现的不论什么变化必定会导致子类发生变化。当你须要复用子类时。假设继承下来的实现不适合解决新的问题。则父类必须重写或被其它更适合的类替换。
这样的依赖关系限制了灵活性并终于限制了复用性。
2.优先使用合成/聚合原则有助于你保持每一个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,而且不太可能增长为不可控制的庞然大物。
盲目使用继承会造成麻烦,本质原因是什么?
继承是一种强耦合的结构。父类变,子类就必需要变。所以,我们在用继承时,一定要在是“is-a”的关系时再考虑使用,而不是不论什么时候都去使用。
优点:
1.实现了抽象和实现部分的分离
桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
2.更好的可扩展性
由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。
3.可动态的切换实现
由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。
4.实现细节对客户端透明,可以对用户隐藏实现细节。
缺点:
1.桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
2.桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。
使用场景:
1.如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2.抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
3.一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
4.虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
5.对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用
实现系统可能由多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。
在发现需要多角度去分类实现对象,而只用继承会造成大量类的增加,不能满足开放-封闭原则时,就应该要考虑适用桥接模式了。
下面以我们的Jdbc为例子,介绍一下桥接模式具体代码实现
Driver类:
public interface Driver {
//连接数据库
void connectSql();
}
Mysql类
public class MysqlDriver implements Driver {
private static Logger log = Logger.getLogger(MysqlDriver.class.toString());
@Override
public void connectSql() {
log.info("使用Mysql数据库");
}
}
Oracle类
public class OracleDriver implements Driver {
private static Logger log = Logger.getLogger(OracleDriver.class.toString());
@Override
public void connectSql() {
log.info("使用Oracle数据库");
}
}
连接方法
public abstract class DriverMath {
private Driver driver;
//连接方法
public void connect(){
this.driver.connectSql();
}
public Driver getDriver(){
return driver;
}
public void setDriver(Driver driver){
this.driver = driver;
}
}
MyDriver 类:
public class MyDriver extends DriverMath {
//获取数据库连接
public void connect(){
getDriver().connectSql();
}
}
测试类:
public class Test {
public static void main(String[] args) {
DriverMath driver = new MyDriver();
//设置Mysql连接
driver.setDriver(new MysqlDriver());
driver.connect();
//Oracle连接
driver.setDriver(new OracleDriver());
driver.connect();
}
}