定义:
将抽象部分与它的实现部分分离,使它们都可以独立地变化。(这里的抽象部分和实现部分不是我们通常认为的父类与子类、接口与实现类的关系,而是组合关系。也就是说,实现部分是被抽象部分调用,以用来完成(实现)抽象部分的功能。)
组成角色:
1)抽象(Abstraction)角色:它定义了抽象类的接口而且维护着一个指向实现(Implementor)角色的引用。
2)精确抽象(RefinedAbstraction)角色:实现并扩充由抽象角色定义的接口。
3)实现(Implementor)角色:给出了实现类的接口,这里的接口与抽象角色中的接口可以不一致。
4)具体实现(ConcreteImplementor)角色:给出了实现角色定义接口的具体实现。
注:
用途:
系统设计中,总是充满了各种变数,这是防不慎防的。比如客户代表可能要求修改某个需求,增加某种功能等等。面对这样那样的变动,你只能去不停的修改设计和代码,并
且要开始新的一轮测试……。
那采取什么样的方式可以较好的解决变化带给系统的影响?你可以分析变化的种类,将不变的框架使用抽象类定义出来,然后再将变化的内容使用具体的子类来分别实现。这样面向客户的只是一个抽象类,这种方式可以较好的避免为抽象类中现有接口添加新的实现所带来的影响,缩小了变化带来的影响。但是这可能会造成子类数量的爆炸,并且在某些时候不是很灵活。
但是当你各个子类的行为经常发生变化,或者有一定的重复和组合关系时,我们不妨将这些行为提取出来,也采用接口的方式提供出来,然后以组合的方式将服务提供给原来的子类。这样就达到了前端和被使用的后端独立的变化,而且还达到了后端的重用。
其实这就是桥梁模式的诞生。
适用环境:
1)当你的系统中有多个地方要使用到类似的行为,或者是多个类似行为的组合时,可以考虑使用桥梁模式来提高重用,并减少因为行为的差异而产生的子类。
2)系统中某个类的行为可能会有几种不同的变化趋势,为了有效的将变化封装,可以考虑将类的行为抽取出来。
3)当然上面的情况也可以是这样,行为可能要被不同相似类使用,也可以考虑使用桥梁模式来实现。
优点:
桥梁模式使用了低耦合性的组合代替继承,使得它具备了不少好处
1)将可能变化的部分单独封装起来,使得变化产生的影响最小,不用编译不必要的第代码。
2)抽象部分和实现部分可以单独的变动,并且每一部分的扩充都不会破坏桥梁模式搭起来架子。
3)对于客户程序来说,你的实现细节是透明的。
将抽象部分与它的实现部分分离,使它们都可以独立地变化。(这里的抽象部分和实现部分不是我们通常认为的父类与子类、接口与实现类的关系,而是组合关系。也就是说,实现部分是被抽象部分调用,以用来完成(实现)抽象部分的功能。)
组成角色:
1)抽象(Abstraction)角色:它定义了抽象类的接口而且维护着一个指向实现(Implementor)角色的引用。
2)精确抽象(RefinedAbstraction)角色:实现并扩充由抽象角色定义的接口。
3)实现(Implementor)角色:给出了实现类的接口,这里的接口与抽象角色中的接口可以不一致。
4)具体实现(ConcreteImplementor)角色:给出了实现角色定义接口的具体实现。
注:
在《Thinking in Patterns with Java》一书中,作者将抽象部分叫做“front-end”(权且翻译为“前端”),而实现部分叫做“back-end”(后端)。这种叫法要比抽象实现什么的好理解多了。
类图:
代码:
/**
* 抽象部分(前端)的抽象角色
*/
public class Abstraction {
// 维护着一个指向实现(Implementor)角色的引用
private Implementation implementation;
public Abstraction(Implementation imp) {
implementation = imp;
}
//下面定义了前端(抽象部分)应该有的接口
public void findA() {
//使用了后端(实现部分)已有的接口,组合实现功能
implementation.serviceA();
implementation.serviceB();
}
public void findB() {
implementation.serviceB();
implementation.serviceC();
}
public void findC() {
implementation.serviceA();
implementation.serviceB();
implementation.serviceC();
}
protected Implementation getImplementation() {
return implementation;
}
}
/**
* 抽象部分(前端)的精确抽象角色
* 前端独立演变
*/
public class RefinedAbstractionA extends Abstraction {
public RefinedAbstractionA(Implementation imp) {
super(imp);
}
//使用抽象角色提供的方法组合起来完成某项功能
//这就是为什么叫精确抽象角色(修正抽象角色)
public void find1() {
findA();
findB();
}
public void find2() {
findC();
}
}
/**
* 另一个精确抽象角色,和上面一样的被我省略了
* 前端独立演变
*/
public class RefinedAbstractionB extends Abstraction {
public RefinedAbstractionB(Implementation imp) {
super(imp);
}
//使用抽象角色提供的方法组合起来完成某项功能
//这就是为什么叫精确抽象角色(修正抽象角色)
public void serviceA() {
findA();
findB();
}
public void serviceB() {
findC();
}
//这里是直接通过实现部分的方法来实现一定的功能
public void serviceE() {
getImplementation().serviceC();
}
}
/**
* 实现部分(后端)的实现角色
*/
public interface Implementation {
//这个接口只是定义了一定的接口
void serviceA();
void serviceB();
void serviceC();
}
/**
* 具体实现角色就是要将实现角色提供的接口实现
* 并完成一定的功能
* 后端独立演变
*/
public class ImplementationA implements Implementation{
@Override
public void serviceA() {}
@Override
public void serviceB() {}
@Override
public void serviceC() {}
}
用途:
系统设计中,总是充满了各种变数,这是防不慎防的。比如客户代表可能要求修改某个需求,增加某种功能等等。面对这样那样的变动,你只能去不停的修改设计和代码,并
且要开始新的一轮测试……。
那采取什么样的方式可以较好的解决变化带给系统的影响?你可以分析变化的种类,将不变的框架使用抽象类定义出来,然后再将变化的内容使用具体的子类来分别实现。这样面向客户的只是一个抽象类,这种方式可以较好的避免为抽象类中现有接口添加新的实现所带来的影响,缩小了变化带来的影响。但是这可能会造成子类数量的爆炸,并且在某些时候不是很灵活。
但是当你各个子类的行为经常发生变化,或者有一定的重复和组合关系时,我们不妨将这些行为提取出来,也采用接口的方式提供出来,然后以组合的方式将服务提供给原来的子类。这样就达到了前端和被使用的后端独立的变化,而且还达到了后端的重用。
其实这就是桥梁模式的诞生。
适用环境:
1)当你的系统中有多个地方要使用到类似的行为,或者是多个类似行为的组合时,可以考虑使用桥梁模式来提高重用,并减少因为行为的差异而产生的子类。
2)系统中某个类的行为可能会有几种不同的变化趋势,为了有效的将变化封装,可以考虑将类的行为抽取出来。
3)当然上面的情况也可以是这样,行为可能要被不同相似类使用,也可以考虑使用桥梁模式来实现。
优点:
桥梁模式使用了低耦合性的组合代替继承,使得它具备了不少好处
1)将可能变化的部分单独封装起来,使得变化产生的影响最小,不用编译不必要的第代码。
2)抽象部分和实现部分可以单独的变动,并且每一部分的扩充都不会破坏桥梁模式搭起来架子。
3)对于客户程序来说,你的实现细节是透明的。