再講具體內(nèi)容之前我們先看一個(gè)《Head First 設(shè)計(jì)模式》里舉的星巴克訂單的例子散休,星巴克提供不同種類的咖啡和咖啡的調(diào)料栋齿,星巴克需要一些類來描述他們并且能計(jì)算出任意一種咖啡和任意幾種調(diào)料搭配在一起的價(jià)格覆山,如果我們用繼承為每一種搭配寫一個(gè)類的話,那就會(huì)有N多個(gè)類,如下圖:
看到上面的類圖瞬間真?zhèn)€人都不好了,是不是后悔選擇了程序員這個(gè)行業(yè)狮杨,不要急,我們可以使用裝飾者模式來讓您的心情陽(yáng)光起來到忽。你也許會(huì)想到可以建了一個(gè)父類橄教,把coffee的配料都寫在里面,然后不同的coffee繼承父類喘漏,這種方式比上面確實(shí)要好护蝶,不過帶來很多數(shù)據(jù)冗余,因?yàn)楦割惖呐淞喜皇敲糠Ncoffee都需要的陷遮。
使用裝飾者模式后滓走,上面的咖啡例子的UML圖如下:
裝飾者模式通過組合的方式擴(kuò)展對(duì)象的特性垦江,這種方式允許我們?cè)谌魏螘r(shí)候?qū)?duì)象的功能進(jìn)行擴(kuò)展帽馋,甚至是運(yùn)行時(shí)擴(kuò)展,面向?qū)ο蟮脑O(shè)計(jì)有原則二是對(duì)擴(kuò)展開放比吭,對(duì)修改關(guān)閉绽族,裝飾者模式就很好的遵循了該原則。裝飾者模式具有一些特征:
1.裝飾者(decorator)和被裝飾(擴(kuò)展)的對(duì)象有著相同的超類(supertype)衩藤。
2.我們可以用多個(gè)裝飾者去裝飾一個(gè)對(duì)象吧慢。
3.我們可以用裝飾過的對(duì)象替換代碼中的原對(duì)象,而不會(huì)出問題(因?yàn)樗麄冇邢嗤某悾?/p>
4.裝飾者可以在委托(delegate赏表,即調(diào)用被裝飾的類的成員完成一些工作)被裝飾者的行為完成之前或之后加上他自己的行為检诗。
5.一個(gè)對(duì)象能在任何時(shí)候被裝飾匈仗,甚至是運(yùn)行時(shí)。
上面來自https://www.cnblogs.com/coffeeSS/p/5405787.html逢慌,具體大家可以進(jìn)去看悠轩。
裝飾者的UML圖如下:
Component:一般是抽象類,在iOS中可以使用類攻泼,也可以使用protocol實(shí)現(xiàn)火架,定義一些接口。
ConcreteComponetA:被修者A忙菠, iOS中繼承Component類或者遵循Component協(xié)議
ConcreteComponetB:被修者B何鸡,同被修飾者A,可以有多個(gè)被修飾者
Decorator:?iOS中繼承Component類或者遵循Component協(xié)議牛欢,裝飾者共同的父類
ConcreteDecoratorA:裝飾者A骡男,用來裝飾ConcreteComponetA或者ConcreteComponetB
ConcreteDecoratorB:裝飾者B,同裝飾者A
下面我們來看一個(gè)吃火鍋的例子傍睹,火鍋有紅鍋和鴛鴦鍋兩種洞翩,每種火鍋又可以添加不同的菜,最終的價(jià)格根據(jù)火鍋的種類和菜的種類來計(jì)算價(jià)格焰望。如果使用裝飾者模式代碼如下:
1.定義Component:使用協(xié)議來實(shí)現(xiàn)
@protocolHuoGuoProtocol
@optional
- (NSString*)getDesc;
- (double)getPrice;
@end
2.定義被被修飾者ConcreteComponetA紅鍋:
#import "HuoGuoProtocol.h"
@interface HongGuo : NSObject<HuoGuoProtocol>
- (instancetype)initWithType:(NSString*)type;
@end
@interface HongGuo()
@property (nonatomic, copy) NSString *type;
@end
@implementation HongGuo
- (instancetype)initWithType:(NSString*)type
{
? ? self= [superinit];
? ? if(self) {
? ? ? ? _type= type;
? ? }
? ? return self;
}
- (NSString*)getDesc
{
? ? return [NSString stringWithFormat:@"%@(%lf)",self.type,[self getPrice]];
}
- (double)getPrice
{
? ? return 30.0;
}
@end
3.定義被被修飾者ConcreteComponetB鴛鴦鍋:
#import "HuoGuoProtocol.h"
@interfaceYuanYangGuo :NSObject
- (instancetype)initWithType:(NSString*)type;
@end
#import "YuanYangGuo.h"
@interface YuanYangGuo()
@property (nonatomic, copy) NSString *type;
@end
@implementation YuanYangGuo
- (instancetype)initWithType:(NSString*)type
{
? ? self= [superinit];
? ? if(self) {
? ? ? ? _type= type;
? ? }
? ? return self;
}
- (NSString*)getDesc
{
? ? return [NSString stringWithFormat:@"%@(%lf)",self.type,[self getPrice]];
}
- (double)getPrice
{
? ? return 50;
}
@end
4.定義Decorator:使用類來實(shí)現(xiàn)骚亿,遵循第一步的協(xié)議
#import "HuoGuoProtocol.h"
@interfaceHuoGuoDecorator :NSObject
@property (nonatomic, weak) id<HuoGuoProtocol> huoGuoObj;
- (instancetype)initWithHuoObj:(id)obj;
@end
#import "HuoGuoDecorator.h"
@implementationHuoGuoDecorator
- (instancetype)initWithHuoObj:(id)obj
{
? ? self= [superinit];
? ? if(self) {
? ? ? ? _huoGuoObj= obj;
? ? }
? ? return self;
}
- (NSString*)getDesc
{
? ? return [self.huoGuoObj getDesc];
}
- (double)getPrice
{
? ? if (self.huoGuoObj)
? ? {
?? ? return[self.huoGuoObjgetPrice];
? ? }
? ? return 0;
}
@end
5.定義裝飾者ConcreteDecoratorA豆腐
@interface DouFu : HuoGuoDecorator
@end
#import "DouFu.h"
@implementation DouFu
- (NSString*)getDesc
{
? ? return [NSString stringWithFormat:@"%@+%@(%lf)",[self.huoGuoObj getDesc],@"豆腐",5.0];
}
- (double)getPrice
{
? ? return[self.huoGuoObjgetPrice] +5;
}
@end
6.同理定義裝飾者ConcreteDecoratorB,ConcreteDecoratorC牛肉和土豆
7.調(diào)用
? ? id<HuoGuoProtocol> hongGuo = [[HongGuo alloc] initWithType:@"紅鍋"];
? // ?id<HuoGuoProtocol> hongGuo = [[YuanYangGuo alloc] initWithType:@"鴛鴦鍋"];
? ? HuoGuoDecorator*decorator = [[HuoGuoDecoratoralloc]initWithHuoObj:hongGuo];
? ? DouFu*doufu = [[DouFualloc]init];
? ? doufu.huoGuoObj= decorator;
? ? Niurou*niuRou = [[Niuroualloc]init];
? ? niuRou.huoGuoObj= doufu;
? ? TuDou*tudou = [[TuDoualloc]init];
? ? tudou.huoGuoObj= niuRou;
? ? typeLabel.text= [tudougetDesc];
? ? priceLabel.text= [NSStringstringWithFormat:@"price:%lf",[tudougetPrice]];
代碼見:https://github.com/steven2008/DesignPattens.git