装饰者模式:动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更具弹性的替代方案。
装饰者模式是结构型模式之一。
装饰者模式装饰者的特点(优点)
1.装饰者和被装饰者有相同的超类,所以装饰者能在避免修改原有代码逻辑的基础上给对象添加新的责任。而使用继承将或多或少的需要修改原有的代码逻辑。
2.可以用一个或者多个对象包装装饰者
3.装饰者可以在所有被委托装饰的行为前/后添加自己的行为以达到特定的目的。
4.对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的使用你需要的装饰者来装饰被装饰者。
举个栗子
Head First 上直接给了装饰饮料的栗子,在我看来这个栗子很能体现装饰者的魅力,所以我这个栗子我打算稍微简化下,然后搬过来。
我们有三种饮料,可可,咖啡,茶。我们还可以根据喜好添加自己想加的其他配料,比如说糖,冰块等等,配料限量, 因此可以加多分,并根据次数按价格收费。比如说我们的1份糖只能达到2.5分的甜度,如果想喝甜一点的可以加两份糖,达到5分的甜度。总价格根据饮料以及配料来计算价格。
声明:饮料已经写好了。继承于Beverage调用cost()计算价格。
那我们如何处理配料的价格?可以思考下?如果用继承又需要怎么处理?
很显然,如果使用继承,那么我们需要在饮料的实现中加上一个addMature()的方法,然后根据配料的价格来添加。那添加addMature()是否有问题呢?
开闭原则:扩展是开放的,修改是闭合的。
设计原则提供给我们一个开发的思路,虽然说不见得一定得遵守,但是尽可能的遵守能让我们的代码在一个更加可控的范围内运行。
使用开闭原则,能让我们已经经过验证的代码避免修改后出现其他异常。
所以如果要遵守开闭原则,那么将没法使用继承。
那么让我们进入正题,看看用装饰者模式处理这个问题。
这是饮料的协议(java是接口/抽象子类)
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol Beverage <NSObject>
-(double)cost;
@end
NS_ASSUME_NONNULL_END
这是配料协议
#import <Foundation/Foundation.h>
#import "Beverage.h"
NS_ASSUME_NONNULL_BEGIN
@protocol Incredint <Beverage>
@property(nonatomic,strong)id<Beverage> decorator;
@end
NS_ASSUME_NONNULL_END
茶的实现
#import "Tee.h"
@implementation Tee
-(double)cost {
return 12.0;
}
-(NSString *)description {
return @"Tee";
}
@end
咖啡的实现
#import "Coffie.h"
@implementation Coffie
-(double)cost {
return 8.0;
}
-(NSString *)description {
return @"Coffie";
}
@end
可可的实现
#import "Cocol.h"
@implementation Cocol
-(double)cost {
return 3.0;
}
-(NSString *)description {
return @"Cocol";
}
@end
进入主题 这个是配料糖,配料继承于饮料,并持有它的抽象
#import "Suger.h"
@implementation Suger
@synthesize decorator = _decorator;
-(instancetype)initWithBerverage:(id<Beverage>)berverage {
if (self = [super init]) {
_decorator = berverage;
}return self;
}
-(double)cost {
return 0.2 + _decorator.cost;
}
-(NSString *)description {
return [NSString stringWithFormat:@"%@ + Suger",_decorator.description];
}
@end
这个是配料冰
#import "Ice.h"
@implementation Ice
@synthesize decorator = _decorator;
-(instancetype)initWithBerverage:(id<Beverage>)berverage {
if (self = [super init]) {
_decorator = berverage;
}return self;
}
-(double)cost {
return 0.1 + _decorator.cost;
}
-(NSString *)description {
return [NSString stringWithFormat:@"%@ + Ice",_decorator.description];
}
@end
#import <Foundation/Foundation.h>
#import "Beverage.h"
#import "Incredint.h"
#import "Tee.h"
#import "Coffie.h"
#import "Suger.h"
#import "Ice.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
id<Beverage> tea = [[Tee alloc] init];
tea = [[Suger alloc] initWithBerverage:tea];
tea = [[Ice alloc] initWithBerverage:tea];
tea = [[Ice alloc] initWithBerverage:tea];
NSLog(@"这杯%@的价格是%.2f元",tea.description,tea.cost);
id<Beverage> coffie = [[Coffie alloc] init];
coffie = [[Suger alloc] initWithBerverage:coffie];
coffie = [[Suger alloc] initWithBerverage:coffie];
coffie = [[Ice alloc] initWithBerverage:coffie];
NSLog(@"这杯%@的价格是%.2f元",coffie.description,coffie.cost);
}
return 0;
}
运行结果
缺点
多层装饰比较复杂
网友评论