裝飾模式是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。
比如游戲機有一個GamePad類, 現在要增加一個作弊功能(例如100條命), 如果直接在GamePad類中去添加可能會影響其他子類的使用
我們考慮裝飾模式思維, 先建立一個裝飾器實現GamePad的所有功能, 然後在裝飾器類的子類中去添加作弊放方法
上代碼
比如GamePad類是這樣
1 #import <Foundation/Foundation.h> 2 3 @interface GamePad : NSObject 4 5 - (void)up; 6 - (void)down; 7 - (void)left; 8 - (void)right; 9 - (void)buttonA; 10 - (void)buttonB; 11 12 @end
我們創建一個裝飾器類, 讓它持有一個GamePad實例並實現相同的方法接口
GamePadDecorator.h
1 #import <Foundation/Foundation.h> 2 #import "GamePad.h" 3 4 @interface GamePadDecorator : NSObject 5 6 - (void)up; 7 - (void)down; 8 - (void)left; 9 - (void)right; 10 - (void)buttonA; 11 - (void)buttonB; 12 13 @end
GamePadDecorator.m
1 #import "GamePadDecorator.h"
2
3 @interface GamePadDecorator ()
4
5 @property (nonatomic, strong) GamePad *gamePad;
6
7 @end
8
9 @implementation GamePadDecorator
10
11 - (instancetype)init {
12 self = [super init];
13 if (self) {
14 self.gamePad = [[GamePad alloc] init];
15 }
16 return self;
17 }
18
19 - (void)up {
20 [self.gamePad up];
21 }
22
23 - (void)down {
24 [self.gamePad down];
25 }
26
27 - (void)left {
28 [self.gamePad left];
29 }
30
31 - (void)right {
32 [self.gamePad right];
33 }
34
35 - (void)buttonA {
36 [self.gamePad buttonA];
37 }
38
39 - (void)buttonB {
40 [self.gamePad buttonB];
41 }
42
43 @end
現在我們新增一個子類來實現作弊方法
CheatGamePadDecorator.h
1 #import "GamePadDecorator.h" 2 3 @interface CheatGamePadDecorator : GamePadDecorator 4 5 - (void)cheat; 6 7 @end
CheatGamePadDecorator.m
1 #import "CheatGamePadDecorator.h"
2
3 @implementation CheatGamePadDecorator
4
5 - (void)cheat {
6 NSLog(@"cheat");
7 }
8
9 @end
這樣我們就可以直接在Controller中直接用CheatGamePadDecorator類去實現GamePad的所有功能還能額外實現作弊方法
1 #import "ViewController.h"
2 #import "CheatGamePadDecorator.h"
3
4 @interface ViewController ()
5
6 @end
7
8 @implementation ViewController
9
10 - (void)viewDidLoad {
11 [super viewDidLoad];
12
13 //創建CheatGamePadDecorator實例
14 CheatGamePadDecorator *cheaterGamePad = [[CheatGamePadDecorator alloc] init];
15
16 //實現GamePad的功能
17 [cheaterGamePad up];
18 [cheaterGamePad down];
19
20 //實現作弊方法
21 [cheaterGamePad cheat];
22 }
23
24
25
26 @end
這樣就完成了一個裝飾模式思路的代碼構建
下面說說cocoa touch中自帶的Category, 它也是對裝飾模式的一個實現
我們用Category來實現上面GamePad添加作弊功能
我們創建一個Cheat Category
GamePad+Cheat.h
1 #import "GamePad.h" 2 3 @interface GamePad (Cheat) 4 5 - (void)cheat; 6 7 @end
GamePad+Cheat.m
1 #import "GamePad+Cheat.h"
2
3 @implementation GamePad (Cheat)
4
5 - (void)cheat {
6 NSLog(@"cheat");
7 }
8
9 @end
這樣我們就可以直接在Controller中通過Category來實現上面功能
1 #import "ViewController.h"
2 #import "GamePad+Cheat.h"
3
4 @interface ViewController ()
5
6 @end
7
8 @implementation ViewController
9
10 - (void)viewDidLoad {
11 [super viewDidLoad];
12
13 //創建GamePad實例
14 GamePad *gamePad = [[GamePad alloc] init];
15
16 //實現GamePad原有方法
17 [gamePad up];
18 [gamePad down];
19
20 //實現作弊方法
21 [gamePad cheat];
22
23 }
使用Category更為簡單
但是在使用Category時有個細節一定要注意, 盡量不要在Category類中去重寫基類方法
假如我們在GamePad+Cheat.h中重寫了- (void)up方法, 則整個工程中的up方法都被重載了
即使我們不在任何地方引用GamePad+Cheat.h, 只要這個文件在工程裡面就會讓GamePad方法被重載