1、概述
將抽象部份與它的實現部份分離,使它們都可以獨立地變化。它是1種對象結構型模式,又稱為柄體(Handle and Body)模式。
2、適用處景
處理多維度變化。
業務場景:某功能為將數據庫中的數據轉換成多種文件格式,例如txt、xml、pdf等格式,同時需要支持多種不同類型的數據庫的讀取。即可使用橋接模式對其進行設計。
這里的維度有兩個 分別為:不同的文件格式 和 不同的數據庫類型。以下圖:
3、UML類圖
橋接模式通用結構圖:
針對上面的業務場景-橋接模式-示例結構圖:
4、參與者
①Abstraction(抽象類):用于定義抽象類的接口,它1般是抽象類而不是接口,其中定義了1個Implementor(實現類接口)類型的對象并可以保護該對象,它與Implementor之間具有關聯關系,它既可以包括抽象業務方法,也能夠包括具體業務方法。
②RefinedAbstraction(擴充抽象類):擴充由Abstraction定義的接口,通常情況下它不再是抽象類而是具體類,它實現了在Abstraction中聲明的抽象業務方法,在RefinedAbstraction中可以調用在Implementor中定義的業務方法。
③Implementor(實現類接口):定義實現類的接口,這個接口不1定要與Abstraction的接口完全1致,事實上這兩個接口可以完全不同,1般而言,Implementor接口僅提供基本操作,而Abstraction定義的接口可能會做更多更復雜的操作。Implementor接口對這些基本操作進行了聲明,而具體實現交給其子類。通過關聯關系,在Abstraction中不但具有自己的方法,還可以調用到Implementor中定義的方法,使用關聯關系來替換繼承關系。
④ConcreteImplementor(具體實現類):具體實現Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同實現,在程序運行時,ConcreteImplementor對象將替換其父類對象,提供給抽象類具體的業務操作方法。
5、用例學習<以適用處景里的業務場景作為代碼設計>
1、JDBC 驅動連接收理類:JdbcDriverManager.java
/**
* JDBC 驅動連接收理類
* @author lvzb.software@qq.com
*
*/
public class JdbcDriverManager {
public String connectAndReadOracle(){
// 摹擬連接Oracle數據庫的代碼
System.out.println("已成功連接到Oracle數據庫");
// 模式 省略 從數據庫中獲得內容的代碼
String content = "已成功從Oracle數據庫中讀取到了內容";
return content;
}
public String connectAndReadMySql(){
// 摹擬連接MySql數據庫的代碼
System.out.println("已成功連接到MySql數據庫");
// 模式 省略 從數據庫中獲得內容的代碼
String content = "已成功從MySql數據庫中讀取到了內容";
return content;
}
public String connectAndReadSqlServer(){
// 摹擬連接Sql Server數據庫的代碼
System.out.println("已成功連接到Sql Server數據庫");
// 模式 省略 從數據庫中獲得內容的代碼
String content = "已成功從Sql Server數據庫中讀取到了內容";
return content;
}
}
2、<角色:實現類接口> FileExportImpl.java
/**
* 獲得文件內容、連接數據庫來源接口
* @author lvzb.software@qq.com
*
*/
public interface FileExportImpl {
/**
* 讀取數據庫中的內容
* @param jdbcDriver
* @return
*/
public String readContent();
}
3、<角色:具體實現類> FileExportFromOracle.java
/**
* 從Oracle數據庫獲得內容
* @author lvzb.software@qq.com
*
*/
public class FileExportFromOracle implements FileExportImpl {
@Override
public String readContent() {
JdbcDriverManager jdbcDriver = new JdbcDriverManager();
return jdbcDriver.connectAndReadOracle();
}
}
4、<角色:具體實現類> FileExportFromMySql.java
/**
* 從MySql數據庫獲得內容
* @author lvzb.software@qq.com
*
*/
public class FileExportFromMySql implements FileExportImpl {
@Override
public String readContent() {
JdbcDriverManager jdbcDriver = new JdbcDriverManager();
return jdbcDriver.connectAndReadMySql();
}
}
5、<角色:具體實現類> FileExportFromSqlServer.java
/**
* 從Sql Server數據庫獲得內容
* @author lvzb.software@qq.com
*
*/
public class FileExportFromSqlServer implements FileExportImpl {
@Override
public String readContent() {
JdbcDriverManager jdbcDriver = new JdbcDriverManager();
return jdbcDriver.connectAndReadSqlServer();
}
}
6、<角色:抽象類> FileExportAbstraction.java
/**
* 文件格式導出 抽象類
* @author lvzb.software@qq.com
*
*/
public abstract class FileExportAbstraction {
protected FileExportImpl fileSouce;
public void setFileSource(FileExportImpl fileSouce){
this.fileSouce = fileSouce;
}
public abstract void exportFile();
}
7、<角色:擴充抽象類> TxtFileExport.java
/**
* Txt文件格式導出具體類
* @author lvzb.software@qq.com
*
*/
public class TxtFileExport extends FileExportAbstraction {
@Override
public void exportFile() {
String readContent = fileSouce.readContent();
System.out.println(readContent + ",將內容導出為.txt格式");
}
}
8、<角色:擴充抽象類> XmlFileExport.java
/**
* xml文件格式導出具體類
* @author lvzb.software@qq.com
*
*/
public class XmlFileExport extends FileExportAbstraction {
@Override
public void exportFile() {
String readContent = fileSouce.readContent();
System.out.println(readContent + ",將內容導出為.xml格式");
}
}
9、<角色:擴充抽象類> PdfFileExport.java
/**
* pdf文件格式導出具體類
* @author lvzb.software@qq.com
*
*/
public class PdfFileExport extends FileExportAbstraction {
@Override
public void exportFile() {
String readContent = fileSouce.readContent();
System.out.println(readContent + ",將內容導出為.pdf格式");
}
}
10、客戶端測試類: Client.java
public class Client {
public static void main(String[] args) {
FileExportImpl fileOracle = new FileExportFromOracle();
FileExportImpl fileMySql = new FileExportFromMySql();
FileExportImpl fileSqlServer = new FileExportFromSqlServer();
FileExportAbstraction fileTxtExport = new TxtFileExport();
FileExportAbstraction fileXmlExport = new XmlFileExport();
FileExportAbstraction filePdfExport = new PdfFileExport();
// 如果我們要從Oracle中導出xml格式的數據
fileXmlExport.setFileSource(fileOracle);
fileXmlExport.exportFile();
System.out.println("--------------------
");
// 如果我們要從Oracle中導出txt格式的數據
fileTxtExport.setFileSource(fileOracle);
fileTxtExport.exportFile();
System.out.println("--------------------
");
// 如果我們要從MySql中導出pdf格式的數據
filePdfExport.setFileSource(fileMySql);
filePdfExport.exportFile();
}
}
11、履行結果 以下:
已成功連接到Oracle數據庫
已成功從Oracle數據庫中讀取到了內容,將內容導出為.xml格式
--------------------
已成功連接到Oracle數據庫
已成功從Oracle數據庫中讀取到了內容,將內容導出為.txt格式
--------------------
已成功連接到MySql數據庫
已成功從MySql數據庫中讀取到了內容,將內容導出為.pdf格式
12、后續系統擴大
①、現如果需求要求新增加1種文件輸入格式 如:html格式
則只需新寫1個FileExportAbstraction抽象類的子類 用以輸出html格式便可,而不需要修改其他任何類、不需要修改另外一維度的代碼。
②、現如果需求要求新增加1類型數據庫類型 如:Sybase
則只需新寫1個FileExportImpl接口的實現類、用以從Sybase數據庫中獲得內容、并修改JdbcDriverManager.java類、添加對Sybase數據庫的連接和訪問。
因而可知 在兩個變化維度中任意擴大1個維度,都不需要修改原有系統、提高了系統的擴大性和可保護性。
6、其他
主要優點:
(1)分離抽象接口及其實現部份。橋接模式使用“對象間的關聯關系”解耦了抽象和實現之間固有的綁定關系,使得抽象和實現可以沿著各自的維度來變化。所謂抽象和實現沿著各自維度的變化,也就是說抽象和實現不再在同1個繼承層次結構中,而是“子類化”它們,使它們各自都具有自己的子類,以便任何組合子類,從而取得多維度組合對象。
(2)在很多情況下,橋接模式可以取代多層繼承方案,多層繼承方案背背了“單1職責原則”,復用性較差,且類的個數非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少了子類的個數。
(3)橋接模式提高了系統的可擴大性,在兩個變化維度中任意擴大1個維度,都不需要修改原有系統,符合“開閉原則”。