装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
比如游戏机有一个GamePad类, 现在要增加一个作弊功能(例如100条命), 如果直接在GamePad类中去添加可能会影响其他子类的使用
我们考虑装饰模式思维, 先建立一个装饰器实现GamePad的所有功能, 然后在装饰器类的子类中去添加作弊放方法
上代码
比如GamePad类是这样
代码语言:javascript复制 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
代码语言:javascript复制 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
代码语言:javascript复制 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
代码语言:javascript复制1 #import "GamePadDecorator.h"
2
3 @interface CheatGamePadDecorator : GamePadDecorator
4
5 - (void)cheat;
6
7 @end
CheatGamePadDecorator.m
代码语言:javascript复制1 #import "CheatGamePadDecorator.h"
2
3 @implementation CheatGamePadDecorator
4
5 - (void)cheat {
6 NSLog(@"cheat");
7 }
8
9 @end
这样我们就可以直接在Controller中直接用CheatGamePadDecorator类去实现GamePad的所有功能还能额外实现作弊方法
代码语言:javascript复制 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
代码语言:javascript复制1 #import "GamePad.h"
2
3 @interface GamePad (Cheat)
4
5 - (void)cheat;
6
7 @end
GamePad Cheat.m
代码语言:javascript复制1 #import "GamePad Cheat.h"
2
3 @implementation GamePad (Cheat)
4
5 - (void)cheat {
6 NSLog(@"cheat");
7 }
8
9 @end
这样我们就可以直接在Controller中通过Category来实现上面功能
代码语言:javascript复制 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方法被重载