0%

Bridge 設計模式

我們可能會遇到因爲物件有不同的變型,而造成組成出來的類別衆多的困擾,例如汽車與機車,都分別有藍色與白色,就有四種排列組合:藍色汽車、白色汽車、藍色機車、白色機車,隨著交通工具的總類與顏色變多,可以組合出來的數量就會爆炸性地增加。如果你也有這個困擾,那就一起來看看如何使用 Bridge 設計模式來解決吧!

HIHI~😍 如果你是第一次來的話,『Chan-Chan-Dev』是一個專門用簡單的圖文與故事講解網路程式技術的網站。
若你也喜歡用這種方式學習的話,歡迎加入 Chan-Chan-Dev Facebook 的粉絲團,在發佈的時候就有比較多機會收到通知喔!😍


設計模式有很多種,但自己都是處於一知半解,所以在學習的過程也做些筆記與思考,希望幫助自己更能理解用法與使用的時機。

而這次在 Refactor Guru 的學習了 Bridge 的這個設計模式,但以下是我自己掰出來的小情境與筆記,所以我們來看看 Bridge 的設計模式要怎麼使用囉。

不用 Bridge 的設計模式會怎樣?🤔

一樣來個情境做起手式,傑西 KeyCode 有限公司的工程師有 John、Mary,他們兩位都會寫 JAVA、PHP、Javascript、Python 的這幾種程式語言。

如果把他們的寫全部的語言全部都列出來,那會得到以下的這幾種 class。

必須要把每一種排列組合列出來

1
2
3
public interface Developer{
String code();
}
1
2
3
4
5
6
// John ------------------------
class JohnJava implements Developer {
public String code(){
return "John coding with java";
}
}
1
2
3
4
5
class JohnPhp implements Developer {
public String code(){
return "John coding with php";
}
}
1
2
3
4
5
class JohnJavascript implements Developer {
public String code(){
return "John coding with Javascript";
}
}
1
2
3
4
5
class JohnPython implements Developer {
public String code(){
return "John coding with Python";
}
}
1
2
3
4
5
6
// Mary ------------------------------------
class MaryJava implements Developer {
public String code(){
return "Mary coding with java";
}
}
1
2
3
4
5
class MaryPhp implements Developer {
public String code(){
return "Mary coding with php";
}
}
1
2
3
4
5
class MaryJavascript implements Developer {
public String code(){
return "Mary coding with Javascript";
}
}
1
2
3
4
5
class MaryPython implements Developer {
public String code(){
return "Mary coding with Python";
}
}

Client 使用

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
public static void main(String[] args){
// John 用 java 寫 code
Developer johnJava = new JohnJava();
johnJava.code();

// John 用 php 寫 code
Developer johnPhp = new JohnPhp();
johnPhp.code();

// John 用 javascript 寫 code
Developer johnJavascript = new JohnJavascript();
johnJavascript.code();

// Mary 用 java 寫 code
Developer maryJava = new MaryJava();
maryJava.code();

// Mary 用 php 寫 code
Developer maryPhp = new MaryPhp();
maryPhp.code();

// Mary 用 Python 寫 code
Developer maryPython = new MaryPython();
maryPython.code();
}

如果今天公司需要工程師在多會一種語言 Go,那就需要在新增幾個 class:

  • JohnGo
  • MaryGo

如果今天新加入了一位工程師 Ken,那就會在需要新增幾個 class:

  • KenJava
  • KenPhp
  • KenJavascript
  • KenPython
  • KenGo

再繼續多幾個新的工程師與新的語言就會得到以下的畫面:


Bridge 的使用時機

適合類似上述情況的多種狀況的排列組合,隨著新增一種組合,總共的組合數量就會成指數型成長的 class 狀態,這時候就很適合將不同的『類別』拆分出來,以上面的狀況來說可以拆分成 DeveloperProgrammingLanguage 兩種類別,並且讓 Developer 依賴 ProgrammingLanguage 的界面。

經過類別整理後的拆分結果

1
2
3
4
// ProgrammingLanguage ----------
interface ProgrammingLanguage{
public String execute();
}
1
2
3
4
5
class Java implements ProgrammingLanguage{
public String execute(){
return "with Java";
}
}
1
2
3
4
5
class Php implements ProgrammingLanguage{
public String execute(){
return "with Php";
}
}
1
2
3
4
5
class Javascript implements ProgrammingLanguage{
public String execute(){
return "with Javascript";
}
}
1
2
3
4
5
class Python implements ProgrammingLanguage{
public String execute(){
return "with Python";
}
}
1
2
3
4
// Developer ------------------------
interface Developer{
public String code(ProgrammingLanguage lang);
}
1
2
3
4
5
class John implements Developer {
public String code(ProgrammingLanguage lang){
return "John coding " + lang.execute();
}
}
1
2
3
4
5
class Mary implements Developer {
public String code(ProgrammingLanguage lang){
return "Mary coding " + lang.execute();
}
}

有了上面針對類別拆分後,我們可以調整我們的程式碼 😇:

Client 使用

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
public static void main(String[] args){
ProgrammingLanguage java = new Java();
ProgrammingLanguage php = new Php();
ProgrammingLanguage python = new Python();

Developer john = new John();
// John 用 java 寫 code
john.code(java);

// John 用 php 寫 code
john.code(php);

// John 用 python 寫 code
john.code(python);


Developer mary = new Mary();
// Mary 用 java 寫 code
mary.code(java);

// Mary 用 php 寫 code
mary.code(php);

// Mary 用 python 寫 code
mary.code(python);
}

所以如果新增一個語言 Go 的話

1
2
3
4
5
class Go implements ProgrammingLanguage{
public String execute(){
return "with Go";
}
}

所以如果新增一位工程師 Ken 的話

1
2
3
4
5
class Ken implements Developer {
public String code(ProgrammingLanguage lang){
return "Ken coding " + lang.execute();
}
}

所以我們就可以:

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
public static void main(String args[]){
ProgrammingLanguage java = new Java();
ProgrammingLanguage php = new Php();
ProgrammingLanguage python = new Python();
ProgrammingLanguage Go = new Go();

Developer john = new John();
// John 用 java 寫 code
john.code(java);

// John 用 php 寫 code
john.code(php);

// John 用 python 寫 code
john.code(python);

// John 用 go 寫 code
john.code(go);


Developer mary = new Mary();
// Mary 用 java 寫 code
mary.code(java);

// Mary 用 php 寫 code
mary.code(php);

// Mary 用 python 寫 code
mary.code(python);

// Mary 用 go 寫 code
mary.code(go);

// 新的工程師 Ken
Developer ken = new Ken();
// Ken 用 java 寫 code
ken.code(java);

// Ken 用 php 寫 code
ken.code(php);

// Ken 用 python 寫 code
ken.code(python);

// Ken 用 go 寫 code
ken.code(go);
}

所以設計模式 Bridge  到底是什麼?😳

wiki 上的定義來看:

橋接模式是軟體設計模式中最複雜的模式之一,它把事物對象和其具體行爲、具體特徵分離開來,使它們可以各自獨立的變化。事物對象僅是一個抽象的概念。如「圓形」、「三角形」歸於抽象的「形狀」之下,而「畫圓」、「畫三角」歸於實現行爲的「畫圖」類之下,然後由「形狀」調用「畫圖」。

結構上會有以下幾種角色:

Abstraction

  • 定義抽象的接口該接口包含實現具體行爲

Refined Abstraction

  • 抽象接口 Abstraction 的子類,依舊是一個抽象的事物名

Implementor

  • 定義具體行爲、具體特徵的應用接口

ConcreteImplementor

  • 實現 Implementor 接口

如果用 UML 圖來表示傑西 KeyCode 有限公司的例子的話大概會長得像這樣子:

UML

經過調整之後的寫法是不是更有結構性?也在新增任何的元素更爲簡單容易了呢? 😇

如果資訊有誤也很歡迎在下方留言,我也是還在學習的路上,最後感謝收看囉。 😆