設計模式學習筆記(十六:橋接模式)

1.1概述

? ? 將抽象部分與它的實現部分分離,使他們都可以獨立地變化。這就是橋接模式的定義。

? ? 抽象類或接口中可以定義若干個抽象方法,習慣上將抽象方法稱作操作。抽象類或接口使程序的設計者忽略操作的細節,即不必考慮這些操作是如何實現的,當用戶程序面向抽象類或接口時,就不會依賴具體的實現,使系統具有很好的擴展性。但是,抽象類中的抽象方法總歸是需要子類去實現的,在大多數情況下抽象類的子類完全可以勝任這樣的工作,但是在某些情況下,子類可能會遇到一些難以處理的問題。

? 例如,電視臺系統中有一個抽象類CCTV,該類有一個抽象方法abstract void makeProgram()。現在為了滿足某些用戶看電視劇的需求,這里給出了CCTV類的子類:CCTV8,該類的實例調用makeProgram()方法制作電視劇節目,因此子類CCTV8必須實現父類的makeProgram()方法,比如使用該方法制作出若干幀影像。子類CCTV8makeProgram()方法在制作出第一幀影像后,比如在第一幀影像顯示“CCTV8”,馬上就發現以下兩個問題:

(1)從第2幀開始應當是電視劇中的影像,而這樣的影像不應當由CCTV8類的makeProgram()方法負責制作。

(2)如果CCTV8makeProgram()方法中強行給出了第2幀以后的各個影像,那么用戶使用CCTV8類的實例看到的電視劇是一個固定的電視劇,如果有其他用戶想看新的電視劇,系統就必須新增新的CCTV子類,這對電視臺系統是一個非常不合理的一種設計,因為CCTV類應當只有一個負責制作“電視劇”節目的子類:CCTV8,而不是多個,也就是說,不能因為一個新的用戶要看不同的電視劇,就要出現一個專門為該用戶制作“電視劇”節目的子類。

? 針對上述問題,應當將實現和抽象放在兩個不同的類層次中,從而使他們可獨立的改變,即將一個抽象類中抽象方法的重要實現部分交給另外一個抽象類的子類或實現另外一個接口的類。比如,對于上述問題,應當將makeProgram()方法的實現交給另外一個抽象類:Program,該類定義了制作影像的makeTVfilm()方法。

? 我們應當重新設計抽象類CCTV類,使該類包含Program的引用,這就可以使CCTV類的子類CCTV8在實現makeProgram()方法時,將該方法的重要實現部分交給Program類的makeTVfilm()方法,即委托給Program子類的實例調用makeTVfilm()方法。

? 我們稱CCTV類和Program類之間的關系是橋接關系,也即是說,CCTV類的子類CCTV8僅僅在CCTV類和Program類之間起到一個“橋接”的作用,具體類關系如下圖一所示:

?

圖一:電視節目與電視劇制作的橋接關系

?

?

1.2模式的結構

橋接模式包括以下四種角色:

(1)抽象(Abstration):是一個抽象類,該抽象類含有Implementor聲明的變量,即維護一個Implementor類型對象。

(2)實現者(Implementor):實現者角色是一個接口(抽象類),該接口(抽象類)中的方法不一定與Abstration類中方法一致。Implementor接口(抽象類)負責定義基本操作,而Abstration類負責定義基于這些基本操作的較高層次的操作。

(3)細化抽象(Refined Abstration):細化抽象是抽象角色的一個子類,該子類在重寫(覆蓋)抽象角色中的抽象方法時,在給出一些必要的操作后,將委托所維護Implementor類型對象調用相應的方法。

(4)具體實現者(Concrete Implementor):具體實現者是實現(擴展)Implementor接口(抽象類)的類。

橋接模式結構的類圖如下圖二所示:

?

圖二:橋接模式的類圖

?

1.3橋接模式的優點

(1)橋接模式分離實現與抽象,使抽象和實現可以獨立的擴展。當修改實現的代碼時,不影響抽象的代碼,反之也一樣。

(2)滿足開-閉原則。抽象和實現者處在同層次,使系統可獨立地擴展者兩個層次。增加新的具體實現者,不需要修改細化對象,反之增加新的細化對象也不需要修改具體實現。

?

1.4適合使用橋接模式的情景

1)不想讓抽象和某些重要的實現代碼是固定綁定關系,這部分實現可運行時動態決定。

2)抽象和實現者都可以繼承的方法獨立地擴充而互不影響,程序在運行期間可能需要動態的將一個抽象的子類的實例與一個實現者的子類的實例進行組合。

3)希望對實現者層次的代碼的修改對抽象層不產生影響,即抽象層的代碼不必重新編譯,反之亦然。

?

?

1.5橋接模式的使用

以下通過一個簡單的問題來描述怎樣使用橋接模式,這個簡單的問題是:計算建筑樓房的成本。

首先看一下本實例構建框架具體類和1.2模式的結構中類圖的對應關系,如下圖所示:

(1)抽象(Abstraction

本問題中,抽象角色是ArchitectureCose類,代碼如下:

package com.liuzhen.sixteen_bridge;public abstract class ArchitectureCose {BuildingDesign design;double unitPrice;public abstract double giveCost();
}

?

(2)實現者(Implementor

對于本問題,實現者是BuildingDesign接口,BuildingDesign接口的代碼如下:

package com.liuzhen.sixteen_bridge;public interface BuildingDesign {public double computerArea();
}

?

(3)細化抽象(Refined Abstraction

對于本問題,細化抽象角色是BuildingCose類,該類是ArchitectureCose類的子類。BuildingCose類在實現父類ArchitectureCose中的giveCose()方法時,需要根據建筑物的總面積和每平方米的造價給出整個建筑物的建造成本。但是,建筑物的建筑面積應當由建筑設計者提供,即建筑設計者負責計算建筑物的總面積,因此giveCose()的基本實現部分應當由一個和ArchitectureCose類同層次的BuildingDesign接口負責,即由實現BuildingDesign接口的類的實例負責面積的計算,而BuildingCose類負責定義基于這些基本操作的較高層次的操作,因此,BuildingCose類在實現giveCose()方法時將基于實現BuildingDesign接口的類的實例所給出建筑物面積來計算建造成本。BuildingCose類的代碼如下:

package com.liuzhen.sixteen_bridge;public class BuildingCose extends ArchitectureCose{BuildingCose(BuildingDesign design, double unitPrice){this.design = design;this.unitPrice = unitPrice;}public double giveCost(){double area = design.computerArea();return area*unitPrice;}
}

?

(4)具體實現者(Concrete Implementor

對于本問題,具體實現者是HouseDesign類的實例,HouseDesign類的代碼如下:

package com.liuzhen.sixteen_bridge;public class HouseDesign implements BuildingDesign{double width, length;int floorNumber;HouseDesign(double width, double length, int floorNumber){this.width = width;this.length = length;this.floorNumber = floorNumber;}public double computerArea(){return width*length*floorNumber;}
}

?

(5)具體使用

通過SixteenApplication類來具體實現上述相關類和接口,來實現橋接模式的運用,其代碼如下:

package com.liuzhen.sixteen_bridge;public class SixteenApplication {public static void main(String[] args){double width = 63, height = 30;int floorNumber = 8;double unitPrice = 6867.38;BuildingDesign design = new HouseDesign(width, height, floorNumber);System.out.println("寬:"+width+"米,高:"+height+"米,層數為:"+floorNumber);ArchitectureCose cost = new BuildingCose(design,unitPrice);double price = cost.giveCost();System.out.println("每平方米造價:"+unitPrice+"元,商業樓的建設成本:"+price);}
}

?

運行結果:

寬:63.0米,高:30.0米,層數為:8
每平方米造價:6867.38元,商業樓的建設成本:1.0383478560000001E8

?

?

參考資料:

? ? ??1.Java設計模式/耿祥義,張躍平著.——北京:清華大學出版社,2009.5

轉載于:https://www.cnblogs.com/liuzhen1995/p/6034311.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372082.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372082.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372082.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Request的getParameter和getAttribute方法的差別

HttpServletRequest.getParameter("modelName");能取到想要的modelObject嗎?經過測試之后。發現是不能的。后來想想。其它道理挺簡單的,當兩個Web組件之間為轉發關系時,轉發源會將要共享request范圍內的數據先用setAttribute將數據…

Spring Social入門–第2部分

幾周前,我寫了一篇文章,展示了我認為可以使用Spring Social編寫的最簡單的應用程序。 該應用程序讀取并顯示了Twitter用戶的公共數據,并被編寫為Spring Social和社交編碼領域的介紹。 但是,讓您的應用程序顯示用戶的公共數據只是故…

linux靜默刪除文件夾,Linux常用命令10 - unzip

zip 是最廣泛使用的歸檔文件, 除了linux,windows也是非常的廣泛。,支持無損數據壓縮。 zip 文件是包含一個或多個壓縮文件或目錄的數據容器。接下來,我將解釋如何使用 unzip 命令通過命令行解壓縮 Linux 系統中的文件。 還有與之對應就是 zip…

Git學習筆記(一) 安裝及版本庫介紹

安裝Git 最早Git是在Linux上開發的,很長一段時間內,Git也只能在Linux和Unix系統上跑。不過,慢慢地有人把它移植到了Windows上。現在,Git可以在Linux、Unix、Mac和Windows這幾大平臺上正常運行了。 在Linux上安裝Git 首先&#xff…

python基礎:迭代器、生成器(yield)詳細解讀

1. 迭代器 迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,知道所有的元素被訪問完結束。迭代器只能往前不會后退,不過這也沒什么,因為人們很少在迭代途中往后退。 1.1 使用迭代器的優點 對于原生支持隨機訪問的數據…

LazyInitializationException的四種解決方案–第2部分

本文從教程??的第1部分繼續。 使用PersistenceContextType.EXTENDED的有狀態EJB加載收集 該方法只能應用于與Full JEE環境兼容的應用程序:將EJB與PersistenceContextType.EXTENDED一起使用。 檢查下面的代碼,DAO的樣子: package com.ejb…

Linux將硬盤轉化為pv,Linux擴展硬盤 物理卷(PV) 卷組(VG) 邏輯卷(LV)

1、給虛擬機添加兩塊新的sata虛擬硬盤,容量8G和10G# fdisk -l 命令2、分別在這兩個硬盤上建立pvPvcreate /dev/sdb 創建一個物理卷/dev/sdb 磁盤名是 fdisk -l 查詢出來的Pvscan 查看當前所有物理卷Pvdisplay 查看當前所有物理卷的詳情3、創建VG,使得…

ubuntu 16.10 shu rufa meiy ou l e geng xi zhi hou

轉載于:https://www.cnblogs.com/ganmk--jy/p/6035894.html

ZOJ Monthly, November 2012

A.ZOJ 3666 Alice and Bob 組合博弈&#xff0c;SG函數應用#include<vector> #include<cstdio> #include<cstring> #include<algorithm>using namespace std;const int maxn 10000 100; int SG[maxn]; vector<int> g[maxn];int mex(int u) { /…

使用Aspect和Spring Profile進行電子郵件過濾

在Web應用程序開發期間&#xff0c;經常需要發送電子郵件。 但是&#xff0c;有時數據庫中會包含來自生產的數據&#xff0c;并且存在在電子郵件測試執行期間向真實客戶發送電子郵件的風險。 這篇文章將解釋如何避免在沒有在發送電子郵件功能中明確編寫代碼的情況下避免這種情…

紅旗linux 進不去圖形界面,進不了紅旗Linux6.0的圖形界面請高手幫忙

習生 于 2008-11-02 11:08:42發表:引用:原帖由 zhaoruiqi 于 2008-11-2 10:03 發表 我的也是進不了圖形界面&#xff0c;用文本安裝后進系統也一樣正常按rtl的方法對xorg.conf進行修改,已經能進入圖形界面。你看看樓上rtl的回復的能否對你有幫助。zhaoruiqi 于 2008-11-02 10:0…

總結繼承的幾種方式

簡單總結繼承的幾種方式 JavaScript作為一門弱類型的語言&#xff0c;本著精簡的原則&#xff0c;它取消了類的概念&#xff0c;只有對象的概念&#xff0c; 更是有萬物皆對象的說法。在基于類的面向對象方式中&#xff0c;對象&#xff08;object&#xff09;依靠類&#xff0…

Oracle SQL精妙SQL語句講解(二)

- 如果存在就更新&#xff0c;不存在就插入用一個語句實現 DROP TABLE t_mg; CREATE TABLE t_mg(code VARCHAR2(10), NAME VARCHAR2(10)); SELECT * FROM t_mg; MERGE INTO t_mg a USING (SELECT the code code, the name NAME FROM dual) b ON (a.code b.code) WHEN M…

Spring Security –在一個應用程序中有兩個安全領域

這篇博客文章主要是關于Spring Security配置的。 更具體地說&#xff0c;它打算顯示如何在一個Web應用程序中配置兩個不同的安全領域。 第一安全領域是針對瀏覽器客戶端的。 它使我們能夠在登錄頁面中登錄并訪問受保護的資源。 第二安全領域旨在處理來自android應用程序的REST…

基于Activiti工作流引擎實現的請假審核流程

概要 本文檔介紹的是某商用中集成的Activiti工作流的部署及使用&#xff0c;該框架用的Activiti版本為5.19.0。本文檔中主要以一個請假流程為例子進行說明&#xff0c;該例子的流程圖如下&#xff1a; 這是一個可以正常運作的工作流業務了&#xff0c;但是它也有不足的地方&…

linux編譯ffmpeg成so,「ffmpeg」一 mac 環境下編譯ffmpeg,生成so庫文件

1.下載ffmpeg源碼,官網&#xff0c;我這里直接采用git 方式下載&#xff1a;下載ffmpeg.png終端輸入git命令&#xff1a;靜靜等待~最后下載的版本為3.4.6 。image.png這里注意一下&#xff0c;剛開始我用的ndk版本是ndk-17b&#xff0c;在編譯該版本的ffmpeg時始終失敗&#xf…

4Web Service中的幾個重要術語

4.1WSDL: web service definition language 直譯:Webservice定義語言 1.對應一種類型的文件.wsdl 2.定義了webservice的服務端與客戶端應用交互傳遞請求和響應數據的格式和方式 3.一個webservice對應一個唯一的esdl文檔 4.2SOAP: simple object access protocal 直譯:簡單對象訪…

云端:亞馬遜,谷歌應用引擎,Windows Azure,Heroku,Jelastic

您想在云端嗎&#xff1f; 您有很多選擇。 我已經評估或使用了許多方法&#xff0c;因此這里有幾句話。 &#xff08;當我使用Java時&#xff0c;我將包括一些與Java相關的注釋&#xff0c;但大多數情況適用于所有&#xff08;受支持的&#xff09;語言。&#xff09; 但是在深…

JS-字符串操作-替換

<!DOCTYPE HTML><html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8"><title>無標題文檔</title><style>p { border:10px solid #ccc; background:#FFC; width:400px; padding:20px;…

linux下kegg注釋軟件,KEGG數據中全部代謝反應和代謝物注釋信息的下載

# 加載函數與R包 -----------------------------------------------------------------library(KEGGREST)library(plyr)source("./RbioRXN-master/RbioRXN-master/R/get.kegg.all.R")source("./RbioRXN-master/RbioRXN-master/R/get.kegg.byId.R")## KEGG數…