自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

設(shè)計模式系列—橋接模式

開發(fā) 前端
本篇和大家一起來學(xué)習(xí)橋接模式相關(guān)內(nèi)容。

本篇和大家一起來學(xué)習(xí)橋接模式相關(guān)內(nèi)容。

 模式定義
將抽象與實現(xiàn)分離,使它們可以獨立變化。它是用組合關(guān)系代替繼承關(guān)系來實現(xiàn),從而降低了抽象和實現(xiàn)這兩個可變維度的耦合度。

模式實現(xiàn)如下:

  1. package com.niuh.designpattern.bridge.v1; 
  2.  
  3. /** 
  4.  * 橋接模式 
  5.  */ 
  6. public class BridgePattern { 
  7.     public static void main(String[] args) { 
  8.  
  9.         Implementor imple=new ConcreteImplementorA(); 
  10.         Abstraction abs=new RefinedAbstraction(imple); 
  11.         abs.Operation(); 
  12.  
  13.     } 
  14.  
  15. //實現(xiàn)化角色 
  16. interface Implementor { 
  17.     void OperationImpl(); 
  18.  
  19. //具體實現(xiàn)化角色 
  20. class ConcreteImplementorA implements Implementor { 
  21.  
  22.     public void OperationImpl() { 
  23.         System.out.println("具體實現(xiàn)化(Concrete Implementor)角色被訪問"); 
  24.     } 
  25.  
  26. //抽象化角色 
  27. abstract class Abstraction { 
  28.     protected Implementor imple; 
  29.  
  30.     protected Abstraction(Implementor imple) { 
  31.         this.imple = imple; 
  32.     } 
  33.  
  34.     public abstract void Operation(); 
  35.  
  36. //擴展抽象化角色 
  37. class RefinedAbstraction extends Abstraction { 
  38.     protected RefinedAbstraction(Implementor imple) { 
  39.         super(imple); 
  40.     } 
  41.  
  42.     public void Operation() { 
  43.         System.out.println("擴展抽象化(Refined Abstraction)角色被訪問"); 
  44.         imple.OperationImpl(); 
  45.     } 

輸出結(jié)果如下:

  1. 擴展抽象化(Refined Abstraction)角色被訪問 
  2. 具體實現(xiàn)化(Concrete Implementor)角色被訪問 

解決的問題
在有多種可能會變化的情況下,用繼承會造成類爆炸問題,擴展起來不靈活。

模式組成
可以將抽象化部分與實現(xiàn)化部分分開,取消二者的繼承關(guān)系,改用組合關(guān)系。

實例說明
實例概況
某公司開發(fā)了一個財務(wù)管理系統(tǒng),其中有個報表生成器的工具模塊,客戶可以指定任意一種報表類型,如基本報表,往來報表,資金報表,資產(chǎn)報表等,并且可以指定不同 的報表樣式,如餅圖,柱狀圖等。系統(tǒng)設(shè)計人員針對這個報表生成器的結(jié)構(gòu)設(shè)計了如下圖所示的類圖。

后來在客戶使用過程中,客戶又希望增加一個新的報表和新的線形圖,開發(fā)人員這個時候發(fā)現(xiàn)維護起來非常麻煩,設(shè)計人員經(jīng)過仔細分析,發(fā)現(xiàn)存在嚴(yán)重的問題,因為新增加一個報表或者圖,需要增加很多子類。所以,系統(tǒng)分析師最終對這個模塊根據(jù)面向?qū)ο蟮脑O(shè)計原則對上面的方案進行了重構(gòu),重構(gòu)后的圖如下所示。

在本重構(gòu)方案中,將報表和圖形設(shè)計成兩個繼承結(jié)構(gòu),兩者都可以獨立變化,編程的時候可以只針對抽象類編碼,而在運行的時候再將具體的圖形子類對象注入到具體的 報表類中。這樣的話,系統(tǒng)就具有良好的可擴展性和可維護性,并且滿足了面向?qū)ο笤O(shè)計原則的開閉原則。

使用步驟
步驟1:定義實現(xiàn)化角色,報表接口

  1. interface IReport { 
  2.     void operationImpl(); 

步驟2:定義具體實現(xiàn)化角色(基本報表、往來報表、資金報表)

  1. class BasicReport implements IReport { 
  2.  
  3.     @Override 
  4.     public void operationImpl() { 
  5.         System.out.println("基本報表被訪問."); 
  6.     } 
  7.  
  8. class IntercourseReport implements IReport { 
  9.  
  10.     @Override 
  11.     public void operationImpl() { 
  12.         System.out.println("往來報表被訪問."); 
  13.     } 
  14.  
  15. class CapitalReport implements IReport { 
  16.  
  17.     @Override 
  18.     public void operationImpl() { 
  19.         System.out.println("資金報表被訪問."); 
  20.     } 

步驟3:定義抽象化角色,圖形

  1. abstract class AbstractionGraph { 
  2.     protected IReport iReport; 
  3.  
  4.     public AbstractionGraph(IReport iReport) { 
  5.         this.iReport = iReport; 
  6.     } 
  7.  
  8.     abstract void operation(); 

步驟4:定義擴展抽象化角色(柱狀圖、餅圖)

  1. class Barchart extends AbstractionGraph { 
  2.  
  3.     public Barchart(IReport iReport) { 
  4.         super(iReport); 
  5.     } 
  6.  
  7.     @Override 
  8.     void operation() { 
  9.         System.out.println("柱狀圖被訪問."); 
  10.         iReport.operationImpl(); 
  11.     } 
  12.  
  13. class Piechart extends AbstractionGraph { 
  14.  
  15.     public Piechart(IReport iReport) { 
  16.         super(iReport); 
  17.     } 
  18.  
  19.     @Override 
  20.     void operation() { 
  21.         System.out.println("餅圖被訪問."); 
  22.         iReport.operationImpl(); 
  23.     } 

步驟5:測試

  1. public class BridgePattern { 
  2.  
  3.     public static void main(String[] args) { 
  4.         //實現(xiàn)化和抽象化分離 
  5.  
  6.         // 基本報表 
  7.         IReport basicReport = new BasicReport(); 
  8.         // 往來報表 
  9.         IReport intercourseReport = new IntercourseReport(); 
  10.         // 資金報表 
  11.         IReport capitalReport = new CapitalReport(); 
  12.  
  13.         // 基本報表使用柱狀圖 
  14.         AbstractionGraph barchart = new Barchart(basicReport); 
  15.         barchart.operation(); 
  16.  
  17.         // 基本報表使用餅圖 
  18.         AbstractionGraph piechart = new Piechart(basicReport); 
  19.         piechart.operation(); 
  20.     } 
  21.  

輸出結(jié)果

  • 柱狀圖被訪問.
  • 基本報表被訪問.
  • 餅圖被訪問.
  • 基本報表被訪問.

優(yōu)點
橋接模式遵循了里氏替換原則和依賴倒置原則,最終實現(xiàn)了開閉原則,對修改關(guān)閉,對擴展開放。這里將橋接模式的優(yōu)缺點總結(jié)如下。

橋接(Bridge)模式的優(yōu)點:

  • 抽象與實現(xiàn)分離,擴展能力強
  • 符合開閉原則
  • 符合合成復(fù)用原則
  • 其實現(xiàn)細節(jié)對客戶透明

缺點
由于聚合關(guān)系建立在抽象層,要求開發(fā)者針對抽象化進行設(shè)計與編程,能正確地識別出系統(tǒng)中兩個獨立變化的維度,這增加了系統(tǒng)的理解與設(shè)計難度。

應(yīng)用場景
當(dāng)一個類內(nèi)部具備兩種或多種變化維度時,使用橋接模式可以解耦這些變化的維度,使高層代碼架構(gòu)穩(wěn)定。

橋接模式通常適用于以下場景:

  1. 當(dāng)一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展時;
  2. 當(dāng)一個系統(tǒng)不希望使用繼承或因為多層次繼承導(dǎo)致系統(tǒng)類的個數(shù)急劇增加時;
  3. 當(dāng)一個系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性時。

橋接模式的一個常見使用場景就是替換繼承。我們知道,繼承擁有很多優(yōu)點,比如,抽象、封裝、多態(tài)等,父類封裝共性,子類實現(xiàn)特性。繼承可以很好的實現(xiàn)代碼復(fù)用(封裝)的功能,但這也是繼承的一大缺點。

因為父類擁有的方法,子類也會繼承得到,無論子類需不需要,這說明繼承具備強侵入性(父類代碼侵入子類),同時會導(dǎo)致子類臃腫。因此,在設(shè)計模式中,有一個原則為優(yōu)先使用組合/聚合,而不是繼承。

橋接模式模式的擴展
在軟件開發(fā)中,有時橋接(Bridge)模式可與適配器模式聯(lián)合使用。當(dāng)橋接(Bridge)模式的實現(xiàn)化角色的接口與現(xiàn)有類的接口不一致時,可以在二者中間定義一個適配器將二者連接起來,其結(jié)構(gòu)圖如下:

源碼中的應(yīng)用

  1. JDBC驅(qū)動程序 
  2. ...... 

DriverManager類

DriverManager作為一個抽象化角色,聚合了實現(xiàn)化角色Connection,只不過與標(biāo)準(zhǔn)的橋梁模式不一樣的是,DriverManager類下面沒有子類。

  1. //  Worker method called by the public getConnection() methods. 
  2. private static Connection getConnection( 
  3.  String url, java.util.Properties info, Class<?> caller) throws SQLException { 
  4.         /* 
  5.          * When callerCl is null, we should check the application's 
  6.          * (which is invoking this class indirectly) 
  7.          * classloader, so that the JDBC driver class outside rt.jar 
  8.          * can be loaded from here. 
  9.          */ 
  10.         ClassLoader callerCL = caller != null ? caller.getClassLoader() : null
  11.         synchronized(DriverManager.class) { 
  12.             // synchronize loading of the correct classloader. 
  13.             if (callerCL == null) { 
  14.                 callerCL = Thread.currentThread().getContextClassLoader(); 
  15.             } 
  16.         } 
  17.  
  18.         if(url == null) { 
  19.             throw new SQLException("The url cannot be null""08001"); 
  20.         } 
  21.  
  22.         println("DriverManager.getConnection(\"" + url + "\")"); 
  23.  
  24.         // Walk through the loaded registeredDrivers attempting to make a connection
  25.         // Remember the first exception that gets raised so we can reraise it. 
  26.         SQLException reason = null
  27.  
  28.         for(DriverInfo aDriver : registeredDrivers) { 
  29.             // If the caller does not have permission to load the driver then 
  30.             // skip it. 
  31.             if(isDriverAllowed(aDriver.driver, callerCL)) { 
  32.                 try { 
  33.                     println("    trying " + aDriver.driver.getClass().getName()); 
  34.                     Connection con = aDriver.driver.connect(url, info); 
  35.                     if (con != null) { 
  36.                         // Success! 
  37.                         println("getConnection returning " + aDriver.driver.getClass().getName()); 
  38.                         return (con); 
  39.                     } 
  40.                 } catch (SQLException ex) { 
  41.                     if (reason == null) { 
  42.                         reason = ex; 
  43.                     } 
  44.                 } 
  45.  
  46.             } else { 
  47.                 println("    skipping: " + aDriver.getClass().getName()); 
  48.             } 
  49.  
  50.         } 
  51.  
  52.         // if we got here nobody could connect
  53.         if (reason != null)    { 
  54.             println("getConnection failed: " + reason); 
  55.             throw reason; 
  56.         } 
  57.  
  58.         println("getConnection: no suitable driver found for "+ url); 
  59.         throw new SQLException("No suitable driver found for "+ url, "08001"); 

PS:以上代碼提交在 Github :

https://github.com/Niuh-Study/niuh-designpatterns.git

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2022-01-14 09:22:22

設(shè)計模式橋接

2021-03-05 07:57:41

設(shè)計模式橋接

2015-11-12 09:32:03

Javascript設(shè)計模式

2024-04-12 12:10:18

Python設(shè)計模式開發(fā)

2022-05-11 08:17:15

Java字符串API

2022-01-12 13:33:25

工廠模式設(shè)計

2010-03-19 11:07:57

點對點無線橋接模式

2020-10-23 09:40:26

設(shè)計模式

2020-11-03 13:05:18

命令模式

2020-11-04 08:54:54

狀態(tài)模式

2021-06-09 08:53:34

設(shè)計模式策略模式工廠模式

2020-10-19 09:28:00

抽象工廠模式

2021-09-29 13:53:17

抽象工廠模式

2013-11-26 15:48:53

Android設(shè)計模式SDK

2021-03-02 08:50:31

設(shè)計單例模式

2020-10-21 14:29:15

原型模式

2020-11-09 08:20:33

解釋器模式

2020-10-20 13:33:00

建造者模式

2012-01-13 15:59:07

2020-11-05 09:38:07

中介者模式
點贊
收藏

51CTO技術(shù)棧公眾號