本文實例講述了PHP設計模式:橋連模式Bridge。分享給大家供大家參考,具體如下:
1. 概述
在軟件系統中,某些類型由于自身的邏輯,它具有兩個或多個維度的變化,那么如何應對這種“多維度的變化”?如何利用面向對象的技術來使得該類型能夠輕松的沿著多個方向進行變化,而又不引入額外的復雜度?
例子1:設想如果要繪制矩形、圓形、橢圓、正方形,我們至少需要4個形狀類,但是如果繪制的圖形需要具有不同的顏色,如紅色、綠色、藍色等,此時至少有如下兩種設計方案:
•第一種設計方案是為每一種形狀都提供一套各種顏色的版本。
•第二種設計方案是根據實際需要對形狀和顏色進行組合。
方案1:
方案2:
對于有兩個變化維度(即兩個變化的原因)的系統,采用方案二來進行設計系統中類的個數更少,且系統擴展更為方便。設計方案二即是橋接模式的應用。橋接模式將繼承關系轉換為關聯關系,從而降低了類與類之間的耦合,減少了代碼編寫量。
例子2:一個普通的開關控制的電燈、電風扇等等,都是橋接的例子。開關的目的是將設備打開或關閉。實際的開關可以是簡單的雙刀拉鏈開關,也可以是調光開關。
2. 問題
如何應對這種“多維度的變化”?如何利用面向對象的技術來使得該類型能夠輕松的沿著多個方向進行變化,而又不引入額外的復雜度?
3. 解決方案
橋連模式:將抽象部分與實現部分分離,使它們都可以獨立的變化。它是一種結構性模式,又稱柄體(Handle and body)模式或者接口(Interface)模式。 當一個抽象可能有多個實現時,通常用繼承來協調他們。抽象類的定義對該抽象的接口。而具體的子類則用不同的方式加以實現,但是此方法有時不夠靈活。繼承機制將抽象部分與他的視線部分固定在一起,使得難以對抽象部分和實現部分獨立地進行修改、擴充和充用。
理解橋接模式,重點需要理解如何將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化。
•抽象化:抽象化就是忽略一些信息,把不同的實體當作同樣的實體對待。在面向對象中,將對象的共同性質抽取出來形成類的過程即為抽象化的過程。
•實現化:針對抽象化給出的具體實現,就是實現化,抽象化與實現化是一對互逆的概念,實現化產生的對象比抽象化更具體,是對抽象化事物的進一步具體化的產物。
•脫耦:脫耦就是將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯,將兩個角色之間的繼承關系改為關聯關系。橋接模式中的所謂脫耦,就是指在一個軟件系統的抽象化和實現化之間使用關聯關系(組合或者聚合關系)而不是繼承關系,從而使兩者可以相對獨立地變化,這就是橋接模式的用意。
4. 適用性
1). 你不希望在抽象和他的實現部分之間有一個固定的邦定關系,如在程序的運行時刻實現部分應該可以被選擇或者切換。
2). 類的抽象以及他的視像都可以通過生成子類的方法加以擴充。這時bridge模式使你可以對不同的抽象接口
和實現部分進行組合,并對他們進行擴充。
3). 對一個抽象的實現部分的修改應該對客戶不產生影響,即客戶的代碼不需要重新編譯。
4). 你想對客戶完全隱藏抽象的實現部分。
5). 你想在多個實現間 共享實現,但同時要求客戶并不知道這一點。
5. 結構
6. 構建模式的組成
抽象類(Abstraction):定義抽象類的接口,維護一個指向Implementor類型對象的指針
擴充抽象類(RefinedAbstraction):擴充由Abstraction定義的接口
實現類接口(Implementor):定義實現類的接口,該接口不一定要與 Abstraction的接口完全一致;事實上這兩個接口可以完全不同。一般來講, Implementor接口僅提供基本操作,而 Abstraction則定義了基于這些基本操作的較高層次的操作。
具體實現類(ConcreteImplementor):實現Implementor接口并定義它的具體實現。
7. 效果
Bridge模式有以下一些優點:
1) 分離接口及其實現部分 一個實現未必不變地綁定在一個接口上。抽象類的實現可以在運行時刻進行配置,一個對象甚至可以在運行時刻改變它的實現。將Abstraction與Implementor分離有助于降低對實現部分編譯時刻的依賴性,當改變一個實現類時,并不需要重新編譯 Abstraction類和它的客戶程序。為了保證一個類庫的不同版本之間的二進制兼容性,一定要有這個性質。另外,接口與實現分離有助于分層,從而產生更好的結構化系統,系統的高層部分僅需知道Abstraction和Implementor即可。
2) 提高可擴充性 你可以獨立地對Abstraction和Implementor層次結構進行擴充。
3 ) 實現細節對客戶透明 你可以對客戶隱藏實現細節,例如共享 Implementor對象以及相應的引用計數機制(如果有的話) 。
橋接模式的缺點
•橋接模式的引入會增加系統的理解與設計難度,由于聚合關聯關系建立在抽象層,要求開發者針對抽象進行設計與編程。
•橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用范圍具有一定的局限性。
8.實現
模擬毛筆:
現需要提供大中小3種型號的畫筆,能夠繪制5種不同顏色,如果使用蠟筆,我們需要準備3*5=15支蠟筆,也就是說必須準備15個具體的蠟筆類。而如果使用毛筆的話,只需要3種型號的毛筆,外加5個顏料盒,用3+5=8個類就可以實現15支蠟筆的功能。
實際上,蠟筆和毛筆的關鍵一個區別就在于筆和顏色是否能夠分離。即將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化"。關鍵就在于能否脫耦。蠟筆的顏色和蠟筆本身是分不開的,所以就造成必須使用15支色彩、大小各異的蠟筆來繪制圖畫。而毛筆與顏料能夠很好的脫耦,各自獨立變化,便簡化了操作。在這里,抽象層面的概念是:"毛筆用顏料作畫",而在實現時,毛筆有大中小三號,顏料有紅綠藍黑白等5種,于是便可出現3×5種組合。每個參與者(毛筆與顏料)都可以在自己的自由度上隨意轉換。
蠟筆由于無法將筆與顏色分離,造成筆與顏色兩個自由度無法單獨變化,使得只有創建15種對象才能完成任務。
Bridge模式將繼承關系轉換為組合關系,從而降低了系統間的耦合,減少了代碼編寫量。
UML如圖:
代碼實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
<?php /******************************Abstraction **************************/ /** * * Abstraction抽象類的接口 * @author guisu * */ abstract class BrushPenAbstraction { protected $_implementorColor = null; /** * * Enter description here ... * @param Color $color */ public function setImplementorColor(ImplementorColor $color ) { $this ->_implementorColor = $color ; } /** * * Enter description here ... */ public abstract function operationDraw(); } /******************************RefinedAbstraction **************************/ /** * * 擴充由Abstraction;大毛筆 * @author guisu * */ class BigBrushPenRefinedAbstraction extends BrushPenAbstraction { public function operationDraw() { echo 'Big and ' , $this ->_implementorColor->bepaint (), ' drawing' ; } } /** * * 擴充由Abstraction;中毛筆 * @author guisu * */ class MiddleBrushPenRefinedAbstraction extends BrushPenAbstraction { public function operationDraw() { echo 'Middle and ' , $this ->_implementorColor->bepaint (), ' drawing' ; } } /** * * 擴充由Abstraction;小毛筆 * @author guisu * */ class SmallBrushPenRefinedAbstraction extends BrushPenAbstraction { public function operationDraw() { echo 'Small and ' , $this ->_implementorColor->bepaint(), ' drawing' ; } } /******************************Implementor **************************/ /** * 實現類接口(Implementor) * * @author mo-87 * */ class ImplementorColor { protected $value ; /** * 著色 * */ public function bepaint(){ echo $this ->value; } } /******************************oncrete Implementor **************************/ class oncreteImplementorRed extends ImplementorColor { public function __construct() { $this ->value = "red" ; } /** * 可以覆蓋 */ public function bepaint() { echo $this ->value; } } class oncreteImplementorBlue extends ImplementorColor { public function __construct() { $this ->value = "blue" ; } } class oncreteImplementorGreen extends ImplementorColor { public function __construct() { $this ->value = "green" ; } } class oncreteImplementorWhite extends ImplementorColor { public function __construct() { $this ->value = "white" ; } } class oncreteImplementorBlack extends ImplementorColor { public function __construct() { $this ->value = "black" ; } } /** * * 客戶端程序 * @author guisu * */ class Client { public static function Main() { //小筆畫紅色 $objRAbstraction = new SmallBrushPenRefinedAbstraction(); $objRAbstraction ->setImplementorColor( new oncreteImplementorRed()); $objRAbstraction ->operationDraw(); } } Client::Main(); |
跨平臺視頻播放器:兩個維度的變化,平臺和不同格式的視頻文件:
9. 橋接模式與其他相關模式
1)抽象工廠(Abstract Factory 模式可以用來創建和配置一個特定的Bridge模式。
2)Adapter模式 用來幫助無關的類協同工作,它通常在系統設計完成后才會被使用。然而,Bridge模式則是在系統開始時就被使用,它使得抽象接口和實現部分可以獨立進行改變。
3)橋接模式與裝飾的區別:
裝飾模式:
這兩個模式在一定程度上都是為了減少子類的數目,避免出現復雜的繼承關系。但是它們解決的方法卻各有不同,裝飾模式把子類中比基類中多出來的部分放到單獨的類里面,以適應新功能增加的需要,當我們把描述新功能的類封裝到基類的對象里面時,就得到了所需要的子類對象,這些描述新功能的類通過組合可以實現很多的功能組合 .
橋接模式:
橋接模式則把原來的基類的實現化細節抽象出來,在構造到一個實現化的結構中,然后再把原來的基類改造成一個抽象化的等級結構,這樣就可以實現系統在多個維度上的獨立變化 。
10. 總結
Bridge模式是一個非常有用的模式,也非常復雜,它很好的符合了開放-封閉原則和優先使用對象,而不是繼承這兩個面向對象原則。
希望本文所述對大家PHP程序設計有所幫助。
原文鏈接:https://blog.csdn.net/hguisu/article/details/7529194