装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
比如游戏机有一个GamePad类, 现在要增加一个作弊功能(例如100条命), 如果直接在GamePad类中去添加可能会影响其他子类的使用
我们考虑装饰模式思维, 先建立一个装饰器实现GamePad的所有功能, 然后在装饰器类的子类中去添加作弊放方法
上代码
比如GamePad类是这样
#import <Foundation/Foundation.h>
@interface GamePad : NSObject
- (void)up;
- (void)down;
- (void)left;
- (void)right;
- (void)buttonA;
- (void)buttonB;
@end
我们创建一个装饰器类, 让它持有一个GamePad实例并实现相同的方法接口
GamePadDecorator.h
#import <Foundation/Foundation.h>
#import "GamePad.h"
@interface GamePadDecorator : NSObject
- (void)up;
- (void)down;
- (void)left;
- (void)right;
- (void)buttonA;
- (void)buttonB;
@end
GamePadDecorator.m
#import "GamePadDecorator.h"
@interface GamePadDecorator ()
@property (nonatomic, strong) GamePad *gamePad;
@end
@implementation GamePadDecorator
- (instancetype)init {
self = [super init];
if (self) {
self.gamePad = [[GamePad alloc] init];
}
return self;
}
- (void)up {
[self.gamePad up];
}
- (void)down {
[self.gamePad down];
}
- (void)left {
[self.gamePad left];
}
- (void)right {
[self.gamePad right];
}
- (void)buttonA {
[self.gamePad buttonA];
}
- (void)buttonB {
[self.gamePad buttonB];
}
@end
现在我们新增一个子类来实现作弊方法
CheatGamePadDecorator.h
#import "GamePadDecorator.h"
@interface CheatGamePadDecorator : GamePadDecorator
- (void)cheat;
@end
CheatGamePadDecorator.m
#import "CheatGamePadDecorator.h"
@implementation CheatGamePadDecorator
- (void)cheat {
NSLog(@"cheat");
}
@end
这样我们就可以直接在Controller中直接用CheatGamePadDecorator类去实现GamePad的所有功能还能额外实现作弊方法
#import "ViewController.h"
#import "CheatGamePadDecorator.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建CheatGamePadDecorator实例
CheatGamePadDecorator *cheaterGamePad = [[CheatGamePadDecorator alloc] init];
//实现GamePad的功能
[cheaterGamePad up];
[cheaterGamePad down];
//实现作弊方法
[cheaterGamePad cheat];
}
@end
这样就完成了一个装饰模式思路的代码构建
下面说说cocoa touch中自带的Category, 它也是对装饰模式的一个实现
我们用Category来实现上面GamePad添加作弊功能
我们创建一个Cheat Category
GamePad+Cheat.h
#import "GamePad.h"
@interface GamePad (Cheat)
- (void)cheat;
@end
GamePad+Cheat.m
#import "GamePad+Cheat.h"
@implementation GamePad (Cheat)
- (void)cheat {
NSLog(@"cheat");
}
@end
这样我们就可以直接在Controller中通过Category来实现上面功能
#import "ViewController.h"
#import "GamePad+Cheat.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建GamePad实例
GamePad *gamePad = [[GamePad alloc] init];
//实现GamePad原有方法
[gamePad up];
[gamePad down];
//实现作弊方法
[gamePad cheat];
}
使用Category更为简单
但是在使用Category时有个细节一定要注意, 尽量不要在Category类中去重写基类方法
假如我们在GamePad+Cheat.h中重写了- (void)up方法, 则整个工程中的up方法都被重载了
即使我们不在任何地方引用GamePad+Cheat.h, 只要这个文件在工程里面就会让GamePad方法被重载