合成/聚合複用原則(CAPP),儘量使用合成/聚合,儘量不要使用類繼承。
合成(Composition,也有翻譯成組合)和聚合(Aggregation)都是關聯的特殊種類。聚合表示一種弱的‘擁有’關係,體現的是A對象可以包含B對象,但B對象不是A對象的一部分;合成則是一種強的‘擁有’關係,體現了嚴格的部分和整體的關係,部分和整體的生命週期一樣。打個比方說,小鳥有兩個翅膀,翅膀與小鳥是部分和整體的關係,並且它們的生命週期是相同的,於是翅膀和小鳥就是合成關係。然而相對於鳥羣來說,一個鳥羣有多隻小鳥,所以小鳥和鳥羣是聚合關係。合成/聚合複用原則的好處是,優先使用對象的合成/聚合將有助於你保持每個類被封裝,並被集中在單個任務上。這樣類和類繼承層次會保持較小規模,並且不太可能增長爲不可控制的龐然大物。
那麼,說這個原則的目的是什麼呢?呵呵,其實今天所要說的橋接模式就是遵循這個原則的。下面給出橋接模式的定義。
橋接模式(Bridge),將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
這裏說明一下,什麼叫抽象與它的實現分離,這並不是說,讓抽象類與其派生類分離,因爲這沒有任何意義。實現指的是抽象類和它的派生類用來實現自己的對象。舉個例子,當我們封裝手機軟件類的時候,如果把手機軟件整體抽象類作爲根類,那麼當我們往下細分的時候,比如我們可以派生出通訊錄類,那麼這個通訊錄類再往下派生出各個品牌上的通訊錄類,以此類推,每當我們要從手機軟件類派生出一個新軟件時又需要重複派生之前已有的手機品牌的派生類。如此一來我們就做了很多無用功而且日積月累,很容易會變成一個龐然大物,而且也破壞了開放封閉原則。
說了半天反面的例子,其實目的就是爲了說明橋接模式要解決的問題是什麼,呵呵。下面先給出橋接模式的類結構圖。
從這張圖中,我們可以類比之前描述的那個例子,按照橋接模式重新把類進行劃分。比如這裏的Abstraction可以對應到手機品牌,RefinedAbstraction是派生的各個手機品牌,Implementor可以對應手機軟件,其派生類ConcreteImplementorA和ConcreteImplementorB可以對應通訊錄類和遊戲類,這樣劃分就可以保證它們各自的變化不會影響其他實現,從而達到應對變化的目的,當然也避免了之前說的超級龐大的結構。
其實,橋接模式的價值在於當實現系統可能有多角度分類時,每一種分類都可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減少它們之間的耦合。
說了這麼多,給大家簡單展示一下代碼實現。
-
Implementor類接口
1
2
3
4
5
|
#import
<Foundation/Foundation.h> @interface
Implementor: NSObject -( void )Operation; @end |
-
Implementor類實現
1
2
3
4
5
6
7
|
#import
"Implementor.h" @implementation
Implementor -( void )Operation{ return ; } @end |
-
ConcreteImplementorA類接口
1
2
3
4
|
#import
"Implementor.h" @interface
ConcreteImplementorA :Implementor @end |
-
ConcreteImplementorA類實現
1
2
3
4
5
6
7
|
#import
"ConcreteImplementorA.h" @implementation
ConcreteImplementorA -( void )Operation{ NSLog (@ "具體實現A的方法執行" ); } @end |
-
ConcreteImplementorB類接口
1
2
3
4
|
#import
"Implementor.h" @interface
ConcreteImplementorB:Implementor @end |
-
ConcreteImplementorB類實現
1
2
3
4
5
6
7
|
#import
"ConcreteImplementorB.h" @implementation
ConcreteImplementorB -( void )Operation{ NSLog (@ "具體實現B的方法執行" ); } @end |
-
Abstraction類接口
1
2
3
4
5
6
7
8
9
|
#import
<Foundation/Foundation.h> @class
Implementor; @interface
Abstraction : NSObject { Implementor
*myImplementor; } -( void )SetImplementor:(Implementor*)implementor; -( void )Operation; @end |
-
Abstraction類實現
1
2
3
4
5
6
7
8
9
10
11
|
#import
"Abstraction.h" #import
"Implementor.h" @implementation
Abstraction -( void )SetImplementor:(Implementor
*)implementor{ myImplementor
= implementor; } -( void )Operation{ [myImplementor
Operation]; } @end |
-
RefinedAbstraction類接口
1
2
3
4
|
#import
"Abstraction.h" @interface
RefinedAbstraction:Abstraction @end |
-
RefinedAbstraction類實現
1
2
3
4
5
6
7
8
|
#import
"RefinedAbstraction.h" #import
"Implementor.h" @implementation
RefinedAbstraction -( void )Operation{ [myImplementor
Operation]; } @end |
-
Main方法調用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#import
<Foundation/Foundation.h> #import
"RefinedAbstraction.h" #import
"ConcreteImplementorA.h" #import
"ConcreteImplementorB.h" int
main( int
argc, const
char
* argv[]) { @autoreleasepool { Abstraction
*ab = [RefinedAbstraction new ]; [ab
SetImplementor:[ConcreteImplementorA new ]]; [ab
Operation]; [ab
SetImplementor:[ConcreteImplementorB new ]]; [ab
Operation]; } return
0; } |