设计模式之桥接模式
桥接模式是一种实用的结构型设计模式,如果系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展。桥接模式,将抽象部分与它的实现部分分离,使它们都可以独立地变化。
桥接模式结构图
Abstraction(抽象类),RefinedAbstraction(扩充抽象类),Implementor(实现类接口)和ConcreteImplementor(具体实现类)。
Abstraction(抽象类):用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个Implementor(实际抽象类)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它可以包含抽象的业务方法,还可以包含具体的业务方法。使用关联关系代替继承关系。
RefinedAbstraction(扩充抽象类):扩充Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中定义的抽象业务方法,在RefinedAbstraction中可以调用Implementor中定义的业务方法。
Implementor(实现类接口):定义实现类的接口,这个另外的一个维度,这个接口不一定要与Abstraction的接口完全一致,这两个接口可以完全不同。一般,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多的更复杂的操作。
ConcreteImplementor(具体实现类):实现Implementor接口并且具体实现它,在不同的ConcreteImplementor中提供基本操作的不同实现。
桥接模式示例
在某个系统中的报表处理模块中,可以将报表显示和数据采集分开,报表可以有多重显示方式也可以有多种数据采集方式,例如可以从文本数据中读取数据,也可以从数据库中读取数据,还可以从Excel文件中获取数据。报表显示的方式,有折线图,柱状图,饼图各种显示方式。在这个报表处理模块中,明显的有数据采集方式和报表显示方式两个维度,非常的适合使用桥接模式。
Abstraction(抽象类),报表显示方式的抽象类:
/*Abstraction 报表显示的抽象类*/
public abstract class AbstractionReportDisplay {
protected DataCollectionImplementor implementor;
/*设置另外的一个维度,数据收集*/
public void setImplementor(DataCollectionImplementor implementor) {
this.implementor = implementor;
}
/*显示报告*/
protected abstract void displayReport();
}
RefinedAbstraction(扩充抽象类),扩充抽象类有折线图类(LineChartReport)和柱形图(BarGraphReport):
/*RefinedAbstraction 扩充抽象类 柱状图显示*/
public class BarGraphReport extends AbstractionReportDisplay {
@Override
protected void displayReport() {
implementor.collectData();
System.out.println("柱状图显示数据...");
}
}
/*RefinedAbstraction 扩充抽象类 折线图显示*/
public class LineChartReport extends AbstractionReportDisplay {
@Override
protected void displayReport() {
implementor.collectData();
System.out.println("折线图显示数据...");
}
}
Implementor(实现类接口),定义实现类的接口,定义了一个名为collectData()
的方法,用于采集数据:
/*Implementor 实现类抽线接口 数据采集接口定义*/
public interface DataCollectionImplementor {
/*数据采集方法*/
void collectData();
}
ConcreteImplementor(具体实现类),具体实现类主要实现了Implementor定义的collectData()
的方法,是采集数据的具体实现,包括从数据库中采集和从文本中采集两种实现:
/*ConcreteImplementor 具体实现类 从数据库中数据采集实现*/
public class DbDataCollection implements DataCollectionImplementor{
@Override
public void collectData() {
System.out.println("从数据库中读取数据...");
}
}
/*ConcreteImplementor 具体实现类 从文本中数据采集实现*/
public class TextDataCollection implements DataCollectionImplementor{
@Override
public void collectData() {
System.out.println("从文本文件中读取数据...");
}
}
客户类,也就是测试类实现如下:
/*客户类,测试类*/
public class Client {
public static void main(String[] args) {
/*1.折线图*/
AbstractionReportDisplay abstractionReportDisplay = new LineChartReport();
/*2.从数据库里读取数据*/
DataCollectionImplementor implementorA = new DbDataCollection();
/*3.从文本文件读取数据*/
DataCollectionImplementor implementorB = new TextDataCollection();
//从数据库中读取数据,以折线图显示
abstractionReportDisplay.setImplementor(implementorA);
abstractionReportDisplay.displayReport();
System.out.println("-------------------------------------------------");
//切换为从文本文件中读取数据,以折线图显示
abstractionReportDisplay.setImplementor(implementorB);
abstractionReportDisplay.displayReport();
System.out.println("-------------------------------------------------");
//切换为柱形图,以柱形图显示从数据库中读取的数据
abstractionReportDisplay = new BarGraphReport();
abstractionReportDisplay.setImplementor(implementorA);
abstractionReportDisplay.displayReport();
}
}
测试程序执行结果:
什么场景下使用桥接模式
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,那么就可以使用桥接模式;一个类存在两个独立变化的维度,且这两个维度都需要进行拓展,就可以采用桥接模式;如果不希望使用继承或者因多层继承导致系统的类急剧增加的情况下也可以采用桥接模式。
桥接模式优缺点
优点:
-
分离抽象接口及其实现部分。
-
桥接模式类似于多继承方案,但是多继承违背了类的单一职责原则,复用性较差,使用器哦啊接模式显然是更好的解决方法。
-
提高系统的可扩充性库,在两个维度中任意扩展一个维度,都不需要修改原有系统。
缺点:
- 增加系统的理解和设计难度,由于觉和关联关系建立在抽象层,要求开放者针对抽象进行设计和编程。