Selenium系列教程(十一)Selenium Grid 分散式測試
設計模式文章
中介者模式
代理模式
抽象工廠模式詳解 —— head first 設計模式
裝飾者模式
介面卡模式
策略模式
觀察者模式
建造者模式 (Builder)
概述
在現實生活中,某些類具有兩個或多個維度的變化,如圖形既可按形狀分,又可按顏色分。如何設計類似於 Photoshop 這樣的軟體,能畫不同形狀和不同顏色的圖形呢?如果用繼承方式,m 種形狀和 n 種顏色的圖形就有 m×n 種,不但對應的子類很多,而且擴充套件困難。
當然,這樣的例子還有很多,如不同顏色和字型的文字、不同品牌和功率的汽車、不同性別和職業的男女、支援不同平臺和不同檔案格式的媒體播放器等。如果用橋接模式就能很好地解決這些問題。
橋接模式的定義與特點
橋接(Bridge)模式的定義如下:將抽象與實現分離,使它們可以獨立變化。它是用組合關係代替繼承關係來實現,從而降低了抽象和實現這兩個可變維度的耦合度。
橋接(Bridge)模式的優點是:
-
由於抽象與實現分離,所以擴充套件能力強;
-
其實現細節對客戶透明。
缺點是:由於聚合關係建立在抽象層,要求開發者針對抽象化進行設計與程式設計,這增加了系統的理解與設計難度。
橋接模式的結構與實現
主要解決:在多維可能會變化的情況下,用繼承會造成類爆炸問題,擴充套件起來不靈活。
何時使用:實現系統可能有多個角度分類,每一種角度都可能變化。
如何解決:把這種多角度分類分離出來,讓它們獨立變化,減少它們之間耦合。
注意事項:對於兩個獨立變化的維度,使用橋接模式再適合不過了。
結構
可以將抽象化部分與實現化部分分開,取消二者的繼承關係,改用組合關係。
橋接(Bridge)模式包含以下主要角色。
-
抽象化(Abstraction)角色:定義抽象類,幷包含一個對實現化物件的引用。
-
擴充套件抽象化(Refined Abstraction)角色:是抽象化角色的子類,實現父類中的業務方法,並通過組合關係調用實現化角色中的業務方法。
-
實現化(Implementor)角色:定義實現化角色的介面,供擴充套件抽象化角色呼叫。
-
具體實現化(Concrete Implementor)角色:給出實現化角色介面的具體實現。
模式示例
1、定義實現類介面(Implementor)
public interface Implementor { public void operationImpl(); }
2、定義具體實現類(ConcreteImplementor)A和B
public class ConcreteImplementorA implements Implementor{ @Override public void operationImpl() { System.out.println("型別A"); } } public class ConcreteImplementorB implements Implementor{ @Override public void operationImpl() { System.out.println("型別B"); } }
3、定義抽象類(Abstraction)
public abstract class Abstraction { public Implementor implementor; public void setImplementor(Implementor implementor) { this.implementor = implementor; } public abstract void operation(); }
4、定義擴充抽象類(Refined Abstraction)
public class RefinedAbstraction extends Abstraction{ @Override public void operation() { implementor.operationImpl(); } }
5、測試程式碼如下:
public class TestMain { public static void main(String[] args) { Abstraction a = new RefinedAbstraction(); a.setImplementor(new ConcreteImplementorA()); a.operation(); } }
示例分析
我們都去買過手機,手機按照品牌分可以分為華為、小米、oppo、vivo 等品牌,如果這些手機按照記憶體分又可以分為 4G、6G、8G 等等。假如我們每一種手機都想要玩一下,至少需要 4*3 個。這對我們來說這些手機也太多了,竟然有 12 個,最主要的是手機品牌和記憶體是放在一起的。現在有這樣一種機制,手機牌品商是一個公司,做手機記憶體的是一個公司,想要做什麼手機我們只需要讓其兩者搭配起來即可。有點類似於全球貿易分工明確的思想,這就是橋接模式,把兩個不同維度的東西橋接起來。
1、定義實現類介面(Implementor),這裡定義手機記憶體介面:
/*Implementor:定義手機記憶體介面*/ public interface Memory { public void addMemory(); }
2、定義具體實現類(ConcreteImplementor),這裡指具體的記憶體,記憶體這裡定義了兩種一種是 6G,一種是 8G
/*ConcreteImplementor:具體實現類1*/ public class Memory6G implements Memory{ @Override public void addMemory() { System.out.println("手機裝了6G記憶體"); } } /*ConcreteImplementor:具體實現類2*/ public class Memory8G implements Memory{ @Override public void addMemory() { System.out.println("手機裝了8G記憶體"); } }
3、定義抽象類(Abstraction),這裡指手機
/*Abstraction:手機抽象類*/ public abstract class Phone { public Memory memory; public void set(Memory memory) { this.memory = memory; } public abstract void buyPhone(); }
4、定義擴充抽象類(Refined Abstraction),這裡指具體的手機品牌,以華為和小米為例
public class HuaWei extends Phone{ public void buyPhone() { memory.addMemory(); System.out.println("購買華為手機"); } } public class XiaoMi extends Phone{ public void buyPhone() { memory.addMemory(); System.out.println("購買小米手機"); } }
5、測試程式碼如下:
public class TestMain { public static void main(String[] args) { //讓華為搭配8G記憶體 Phone huawei = new HuaWei(); huawei.set(new Memory8G()); huawei.buyPhone(); //讓小米搭配6G記憶體 Phone xiaomi = new XiaoMi(); xiaomi.set(new Memory6G()); xiaomi.buyPhone(); } }
6、輸出結果如下:
從程式碼就可以看出,購買手機的時候,品牌和記憶體兩個維度是分開的,這樣後續品牌和記憶體之間是可以獨立變化,而不會影響到另一個類。
橋接模式與策略模式的區別
橋接模式如下:
策略如下:
在橋接中,Abstraction 通過聚合方式引用 Implementor.
在策略中,Context 也通過聚合引用 Strategy.
橋接 (Bridge) 模式是結構型模式的一種,而策略 (strategy) 模式則屬於行為模式。
從他們的結構圖可知,在這兩種模式中,都存在一個物件使用聚合的方式引用另一個物件的抽象介面的情況,而且該抽象介面的實現可以有多種並且可以替換。可以說兩者在表象上都是呼叫者與被呼叫者之間的解耦,以及抽象介面與實現的分離。
那麼兩者的區別體現在什麼地方呢?
-
首先,在形式上,兩者還是有一定區別的,對比兩幅結構圖,我們可以發現,在橋接模式中不僅 Implementor 具有變化(ConcreateImplementior),而且 Abstraction 也可以發生變化(RefinedAbstraction),而且兩者的變化是完全獨立的,RefinedAbstraction 與 ConcreateImplementior 之間鬆散耦合,它們僅僅通過 Abstraction 與 Implementor 之間的關係聯絡起來。而在策略模式中,並不考慮Context的變化,只有演算法的可替代性。
-
其次在語意上,橋接模式強調 Implementor 介面僅提供基本操作,而 Abstraction 則基於這些基本操作定義更高層次的操作。而策略模式強調 Strategy 抽象介面的提供的是一種演算法,一般是無狀態、無資料的,而 Context 則簡單呼叫這些演算法完成其操作。
-
橋接模式中不僅定義 Implementor 的介面而且定義 Abstraction 的介面,Abstraction 的介面不僅僅是為了與 Implementor 通訊而存在的,這也反映了結構型模式的特點:通過繼承、聚合的方式組合類和物件以形成更大的結構。在策略模式中,Startegy 和 Context 的介面都是兩者之間的協作介面,並不涉及到其它的功能介面,所以它是行為模式的一種。行為模式的主要特點就是處理的是物件之間的通訊方式,往往是通過引入中介者物件將通訊雙方解耦,在這裡實際上就是將 Context 與實際的演算法提供者解耦。
所以相對策略模式,橋接模式要表達的內容要更多,結構也更加複雜。橋接模式表達的主要意義其實是介面隔離的原則,即把本質上並不內聚的兩種體系區別開來,使得它們可以鬆散的組合,而策略在解耦上還僅僅是某一個演算法的層次,沒有到體系這一層次。從結構圖中可以看到,策略的結構是包容在橋接結構中的,橋接中必然存在著策略模式,Abstraction 與 Implementor 之間就可以認為是策略模式,但是橋接模式一般 Implementor 將提供一系列的成體系的操作,而且 Implementor 是具有狀態和資料的靜態結構。而且橋接模式 Abstraction 也可以獨立變化。