一 模式背景
在很多時候,繼承足以解決很多問題了,但是有的還不是更優秀的解決方案。比如有時候可能會遇到那種組合式的類,有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報表工具類");
}
}