橋樑模式
Prerequisites:
需求
為手機品牌A寫遊戲
1
2
3
4
5
class BrandAGame {
public void play() {
System.out.println("Brand A Game!");
}
}
為手機品牌B寫遊戲
1
2
3
4
5
class BrandBGame {
public void play() {
System.out.println("Brand B Game!");
}
}
把以上二個類別整合成如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class Game {
abstract void play();
}
class BrandAGame extends Game {
public void play() {
System.out.println("Brand A Game!");
}
}
class BrandBGame extends Game {
public void play() {
System.out.println("Brand B Game!");
}
}
那如果要再增加通訊錄在各品牌手機,要如何修正?如下圖嗎?
那如果要再增加新的手機品牌,與拍照功能要如何修正?如下圖嗎?
是依軟體來分嗎?
還是依品牌來分?
若還要增加10種手機品牌,還要新增錄音、導航、行事曆…等等軟體,請問類別圖怎麼畫?
有一個比是一個更好
這種已經無法畫下去了,首先我們需要取消繼承關係,不要軟體中有品牌,也不要品牌中有軟體,要符合「單一職責原則」,一個類別就做一件事,分成「手機品牌抽象類別」與「軟體抽象類別」二類。
而在手機品牌類別中,用有一個Has-A的方式,把「軟體抽象類別」聚合在手機品牌中,使用抽象類別或介面(Interface)符合依賴反轉原則,依賴抽象,而不是依賴具體的子類別。
而且新增手機品牌與新增錄音、導航、行事曆…等等軟體,不用改動架構,比較好加入新的類別,符合開放關閉原則,對修改關閉,對擴充開放。
橋樑
注意上圖,那條菱形的線,橫跨手機品牌與軟體,就像一個橋,把二個不同的類別連接在一起,所以才稱之為橋樑模式(Bridge Pattern)。
經典橋樑模式類別圖
Abstraction意思是抽象,「手機品牌」,就是一個抽象的概念,手機品牌A、手機品牌B是品牌的子類別。
Implementor意思是實作,「軟體」有很多不同的軟體與實作方式。
但我覺得不用為名詞特別綁定一定要是抽象的概念才能歸類在Abstraction,我一開始也為此卡住,此模式的精神在於分類,單一職責、有一個比是一個更好、依賴反轉原則、開放關閉原則。
程式碼
軟體
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Software {
void operationImp();
}
public class Game implements Software{
@Override
public void operationImp() {
System.out.println("遊戲開始");
}
}
public class Contacts implements Software{
@Override
public void operationImp() {
System.out.println("列出聯絡人");
}
}
品牌
最重要在於software成員變數是set過來的,在operation()方法是呼叫software.operationImp()。
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
public abstract class Brand {
private Software software;
public void operation() {
software.operationImp();
}
public void setSoftware(Software software) {
this.software = software;
}
}
public class BrandA extends Brand{
@Override
public void operation() {
super.operation();
System.out.println("Brand A");
}
}
public class BrandB extends Brand{
@Override
public void operation() {
super.operation();
System.out.println("BrandB");
}
}
main主程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {
public static void main(String[] args) {
System.out.println("======Brand A=========");
Brand brandA = new BrandA();
brandA.setSoftware(new Game());
brandA.operation();
brandA.setSoftware(new Contacts());
brandA.operation();
System.out.println("======Brand B=========");
Brand brandB = new BrandB();
brandB.setSoftware(new Game());
brandB.operation();
brandB.setSoftware(new Contacts());
brandB.operation();
}
}
======Brand A=========
遊戲開始
Brand A
列出聯絡人
Brand A
======Brand B=========
遊戲開始
BrandB
列出聯絡人
BrandB