1. 程式人生 > >橋接模式(Bridge)

橋接模式(Bridge)

1.簡述

橋接模式即將抽象部分與它的實現部分分離開來,使他們都可以獨立變化。橋接模式將繼承關係轉化成關聯關係,它降低了類與類之間的耦合度,減少了系統中類的數量,也減少了程式碼量。將抽象部分與他的實現部分分離這句話不是很好理解,其實這並不是將抽象類與他的派生類分離,而是抽象類和它的派生類用來實現自己的物件。這樣還是不能理解的話。我們就先來認清什麼是抽象化,什麼是實現化,什麼是脫耦。

  • 抽象化:從眾多的事物中抽取出共同的、本質性的特徵,而捨棄其非本質的特徵,就是抽象化。例如蘋果、香蕉、生梨、 桃子等,它們共同的特性就是水果。得出水果概念的過程,就是一個抽象化的過程。要抽象,就必須進行比較,沒有比較就無法找到在本質上共同的部分。共同特徵是指那些能把一類事物與他類事物區分開來的特徵,這些具有區分作用的特徵又稱本質特徵。因此抽取事物的共同特徵就是抽取事物的本質特徵,捨棄非本質的特徵。 所以抽象化的過程也是一個裁剪的過程。在抽象時,同與不同,決定於從什麼角度上來抽象。抽象的角度取決於分析問題的目的。通常情況下,一組物件如果具有相同的特徵,那麼它們就可以通過一個共同的類來描述。如果一些類具有相同的特徵,往往可以通過一個共同的抽象類來描述。
  • 實現化:抽象化給出的具體實現,就是實現化。一個類的例項就是這個類的例項化,一個具體子類是它的抽象超類的例項化。
  • 脫耦:所謂耦合,就是兩個實體的行為的某種強關聯。而將它們的強關聯去掉,就是耦合的解脫,或稱脫耦。在這裡,脫耦是指將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯。所謂強關聯,就是在編譯時期已經確定的,無法在執行時期動態改變的關聯;所謂弱關聯,就是可以動態地確定並且可以在執行時期動態地改變的關聯。顯然,在Java語言中,繼承關係是強關聯,而聚合關係是弱關聯。將兩個角色之間的繼承關係改為聚合關係,就是將它們之間的強關聯改換成為弱關聯。因此,橋樑模式中的所謂脫耦,就是指在一個軟體系統的抽象化和實現化之間使用聚合關係而不是繼承關係,從而使兩者可以相對獨立地變化。這就是橋樑模式的用意。

2.角色

  • 抽象化(Abstraction)角色:抽象化給出的定義,並儲存一個對實現化物件的引用。
  • 修正抽象化(RefinedAbstraction)角色:擴充套件抽象化角色,改變和修正父類對抽象化的定義。
  • 實現化(Implementor)角色:這個角色給出實現化角色的介面,但不給出具體的實現。必須指出的是,這個介面不一定和抽象化角色的介面定義相同,實際上,這兩個介面可以非常不一樣。實現化角色應當只給出底層操作,而抽象化角色應當只給出基於底層操作的更高一層的操作。
  • 具體實現化(ConcreteImplementor)角色:這個角色給出實現化角色介面的具體實現。

3.UML類圖

image

4.舉例說明

例如:我們現在要畫三種形狀,分別是長方形,圓形和正方形。而且可以分別用三種顏色來畫。

66666

程式碼如下:

首先是形狀類:該類為一個抽象類,主要提供畫圖形的方法

public abstract class Shape {
    Color color;

    public void setColor(Color color) {
        this.color = color;
    }
    
    public abstract void draw();
}

 然後是畫三個形狀的類

public class Circle extends Shape{

    public void draw() {
        color.bepaint("正方形");
    }
}

public class Rectangle extends Shape{

    public void draw() {
        color.bepaint("長方形");
    }

}

public class Square extends Shape{

    public void draw() {
        color.bepaint("正方形");
    }

}

畫形狀所用的顏色介面

public interface Color {
    public void bepaint(String shape);
}

 用於畫形狀的三種顏色類

public class Gray implements Color{

    public void bepaint(String shape) {
        System.out.println("灰色的" + shape);
    }
}


public class Black implements Color{

    public void bepaint(String shape) {
        System.out.println("黑色的" + shape);
    }
}


public class White implements Color{

    public void bepaint(String shape) {
        System.out.println("白色的" + shape);
    }

}

 客戶端

public class Client {
    public static void main(String[] args) {
        //白色
        Color white = new White();
        //正方形
        Shape square = new Square();
        //白色的正方形
        square.setColor(white);
        square.draw();
        
        //長方形
        Shape rectange = new Rectangle();
        rectange.setColor(white);
        rectange.draw();
    }
}

執行結果: 

白色的正方形 白色的長方形

注意:可以將shape中的setColor刪去,改為新增一個構造方法,利用構造方法給Shape中的color初始化也是可以的。

5.橋接模式通用程式碼


/*
 * 實現化角色
 */
public interface Implementor {
	// 基本方法
	public void doSomething();

	public void doAnything();
}

/*
 * 具體實現化角色
 */

public class ConcreteImplementor1 implements Implementor {

	public void doAnything() {
		// 業務處理邏輯
	}

	public void doSomething() {
		// 業務處理邏輯
	}

}

public class ConcreteImplementor2 implements Implementor {
	
	public void doAnything() {
		// 業務處理邏輯
	}

	public void doSomething() {
		// 業務處理邏輯
	}
}

/*
 * 抽象化角色
 */
public abstract class Abstraction {
	// 定義對實現化角色的引用
	private Implementor imp;

	// 約束子類必須實現該建構函式
	public Abstraction(Implementor _imp) {
		this.imp = _imp;
	}

	// 自身的行為和屬性
	public void request() {
		this.imp.doSomething();
	}

	// 獲得實現化角色
	public Implementor getImp() {
		return this.imp;
	}
}

/*
 * 具體抽象化角色
 */
public class RefinedAbstraction extends Abstraction {
	// 覆寫建構函式
	public RefinedAbstraction(Implementor _imp) {
		super(_imp);
	}

	// 修正父類的行為
	public void request() {
		super.request();
		super.getImp().doAnything();
	}
}

/*
 * 客戶端
 */
public class Client {
	public static void main(String[] args) {
		// 定義一個實現化角色
		Implementor imp = new ConcreteImplementor1();
		// 定義一個抽象化角色
		Abstraction abs = new RefinedAbstraction(imp);
		// 執行行文
		abs.request();
	}
}

6.橋接模式優點

  • 實現了抽象和實現部分的分離:橋接模式分離了抽象部分和實現部分,從而極大的提供了系統的靈活性,讓抽象部分和實現部分獨立開來,分別定義介面,這有助於系統進行分層設計,從而產生更好的結構化系統。對於系統的高層部分,只需要知道抽象部分和實現部分的介面就可以了。
  • 更好的可擴充套件性:由於橋接模式把抽象部分和實現部分分離了,從而分別定義介面,這就使得抽象部分和實現部分可以分別獨立擴充套件,而不會相互影響,大大的提供了系統的可擴充套件性。
  • 可動態的切換實現,由於橋接模式實現了抽象和實現的分離,所以在實現橋接模式時,就可以實現動態的選擇和使用具體的實現。
  • 實現細節對客戶端透明,可以對使用者隱藏實現細節。分離抽象介面及其實現部分。提高了比繼承更好的解決方案。

7.橋接模式缺點

  • 橋接模式的引入增加了系統的理解和設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計和程式設計。
  • 橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用範圍有一定的侷限性。

8.橋接模式適用場景

  • 如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯絡,通過橋接模式可以使它們在抽象層建立一個關聯關係。
  • 抽象化角色和實現化角色可以以繼承的方式獨立擴充套件而互不影響,在程式執行時可以動態將一個抽象化子類的物件和一個實現化子類的物件進行組合,即系統需要對抽象化角色和實現化角色進行動態耦合。
  • 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件。
  • 雖然在系統中使用繼承是沒有問題的,但是由於抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。
  • 對於那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用