一 模式背景
在很多时候,继承足以解决很多问题了,但是有的还不是更优秀的解决方案。比如有时候可能会遇到那种组合式的类,有2个维度可以变化,进行不同的组合,然后完成不同的功能。比如开发报表功能的时候,可选则的报表工具是一个维度,要构建什么类型的报表又是一个维度,我们可以通过不同的报表工具完成这些报表的产生。如图示:
如果我们定一个抽象基类ReportTools, 然后要实现以XML,CVS格式输出形成报表,我们使用JasperReport,则需要创建2个类:
JasperXMLReportTools 和 JasperCVSReportTools,代码如下:
public abstract class ReportTools {
public abstract String build();
public void writeTo(String path) throws IOException {
File file = new File(path);
String content = build();
FileUtils.write(file,content, Charset.defaultCharset());
}
}
public class JasperXMLReportTools extends ReportTools {
public String build() {
return "[Jasper]XML 内容";
}
@Override
public void writeTo(String path) throws IOException {
System.out.println("[Jasper]将内容以XML它输出到文件: "+path);
super.writeTo(path);
}
}
public class JasperCVSReportTools extends ReportTools {
public String build() {
return "[Jasper]CVS 内容";
}
@Override
public void writeTo(String path) throws IOException {
System.out.println("[Jasper]将内容以CVS它输出到: "+path);
super.writeTo(path);
}
}
如果此时,要新增报表工具JFreerReport,那么我们就必须要同时提供XML和CVS的实现,JFreeReportCVSReportTools和JFreeReportXMLReportTools。代码如下:
public class JFreeReportCVSReportTools extends ReportTools{
public String build() {
return "[JFreeReport]CVS 内容";
}
@Override
public void writeTo(String path) throws IOException {
System.out.println("[JFreeReport]将内容以CVS它输出到文件: "+path);
super.writeTo(path);
}
}
public class JFreeReportXMLReportTools extends ReportTools {
public String build() {
return "[JFreeReport]XML 内容";
}
@Override
public void writeTo(String path) throws IOException {
System.out.println("[JFreeReport]将内容以XML它输出到文件: "+path);
super.writeTo(path);
}
}
那么如果又有新需求,我们要新增新报表工具类OpenReport,那么此时是不是又要增加两个类,或者我们需要新增其他的格式的报表,比如PDF或者HTML,那么类的个数又要翻倍。
我们可以看到其实build只是构建不同格式的内容,而writeTo只是将构建的这些内容写入磁盘。所以相对于来说变化的就是build这个方法。那既然这样,那么针对有2个维度变化的需求,我们可以使用桥接模式,将他的抽象部分(build)与实现部分开,是抽象和实现可以独立的变化。z
二 桥接模式
2.1 什么是桥接,什么是桥接模式
桥接:原本不相通的东西通过桥连接起来。
桥接模式:将抽象和实现进行分离解耦,使得抽象和实现可以独自变化
2.2 为何需要桥接 以及 如何桥接
为了达到抽象和实现部分都可独立变化,所以抽象部分和实现部分开的,但是分来比意味着抽象部分不使用实现部分功能,那如何使用呢,很明显搭个桥就可以。
那如何桥接呢?我么只需要在抽象部分引入实现接口,然后就可以通过该接口调用实现部分具体的功能了。
三 代码实现
public interface Report {
abstract String build();
}
public class CVSReport implements Report {
public String build() {
return "CVS 内容";
}
}
public class XMLReport implements Report {
public String build() {
return "XML内容";
}
}
public abstract class ReportTools {
private Report report;
public ReportTools(Report report) {
this.report = report;
}
public void writeTo(String path) throws IOException {
File file = new File(path);
String content = this.report.build();
FileUtils.write(file,content, Charset.defaultCharset());
}
public void desc(){
System.out.println("报表工具类基类");
}
}
public class JasperReportTools extends ReportTools {
public JasperReportTools(Report report) {
super(report);
}
@Override
public void desc() {
System.out.println("Jasper报表工具类");
}
}
public class JFreeReportTools extends ReportTools {
public JFreeReportTools(Report report) {
super(report);
}
@Override
public void desc() {
System.out.println("JFreeReport报表工具类");
}
}