定義
裝飾者模式動(dòng)態(tài)
地將責(zé)任附加到對(duì)象上.若要擴(kuò)展對(duì)象,裝飾者提供了比繼承更有彈性的替代方案.
實(shí)現(xiàn)要點(diǎn)
- 繼承屬于
擴(kuò)展
的形式之一,但不見(jiàn)得是達(dá)到彈性設(shè)計(jì)的最佳方式. - 在我們的設(shè)計(jì)中,應(yīng)該允許行為可以被
擴(kuò)展
,而無(wú)需修改
現(xiàn)有的代碼. -
組合
和委托
可用于在運(yùn)行時(shí)
動(dòng)態(tài)的加上新的行為. - 裝飾者模式意味著
一群
裝飾者類,這些類用來(lái)包裝具體組件. - 裝飾者類可以反映出被裝飾的組件類型(一般是通過(guò)
接口
或繼承
實(shí)現(xiàn)的,這里的繼承
并不是用來(lái)繼承行為,而只是記錄下自身的類型). -
裝飾者
可以對(duì)被裝飾者
的行為進(jìn)行修改,而達(dá)到特定的目的. - 裝飾者一般對(duì)組件的客戶是
透明的
,除非客戶程序依賴于組件的具體類型. - 裝飾者會(huì)導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小對(duì)象,如果過(guò)度使用,會(huì)讓程序變得很復(fù)雜.
個(gè)人理解
實(shí)現(xiàn)起來(lái)其實(shí)不難,裝飾者采用接口
或者繼承
來(lái)獲取到基類
,這里采用了繼承
這個(gè)比較簡(jiǎn)單的方式,繼承
我也僅僅只是繼承了狀態(tài)
和保存了自身被裝飾者
而已,并沒(méi)有繼承
他的行為,這里對(duì)行為的擴(kuò)展還是去使用組件
來(lái)完成比較好.但其實(shí)有一個(gè)問(wèn)題,使用裝飾者會(huì)導(dǎo)致出現(xiàn)許多小的
對(duì)象,這可能會(huì)讓自己編寫(xiě)的程序變得復(fù)雜
,可能還沒(méi)有原來(lái)好維護(hù)
,這當(dāng)然和使用者的編寫(xiě)水平
有關(guān)!在后面采取的MVVM
架構(gòu)中,我們需要對(duì)項(xiàng)目的業(yè)務(wù)顆粒度
進(jìn)行劃分,其實(shí)到時(shí)候可以注意到這一點(diǎn).現(xiàn)實(shí)中也有許多業(yè)務(wù)確確實(shí)實(shí)可以用到這種模式,希望能通過(guò)后面的學(xué)習(xí)來(lái)提高自己的編碼水平.??
OC實(shí)現(xiàn)代碼練習(xí)
是先來(lái)介紹下文件結(jié)構(gòu),Beverage
是一個(gè)抽象的基類
,Condiment
代表著我們需要添加的調(diào)料
,Component
則代表著我們需要銷售的飲料.
看一看調(diào)用吧,這里飲料并沒(méi)有使用基類的構(gòu)造方法
,是因?yàn)樯畋嚎Х绕鋵?shí)并沒(méi)有裝飾別的對(duì)象,而我們需要裝飾者
去裝飾他.從下面的代碼我們也可以看出裝飾者這樣子寫(xiě)會(huì)有些繁瑣
,在以后的學(xué)習(xí)我會(huì)去使用工廠模式
和生成器模式
來(lái)簡(jiǎn)化這個(gè)繁瑣的步驟.下面來(lái)看一下調(diào)用代碼:
//獲取到一杯普通的深焙咖啡
DarkRoast *darkRoast = [[DarkRoast alloc] init];
NSLog(@"飲品名稱:%@,價(jià)格:%ld",darkRoast.beverageDesc,[darkRoast cost]);
//加入一杯牛奶后的深焙咖啡
Beverage *oneMilkDarkRoast = [[Milk alloc] initWithBeverage:darkRoast];
NSLog(@"飲品名稱:%@,價(jià)格:%ld",oneMilkDarkRoast.beverageDesc,[oneMilkDarkRoast cost]);
//向加入一杯牛奶后的深焙咖啡再次加入摩卡
Beverage *oneMilkAndOneMochaDarkRoast = [[Mocha alloc] initWithBeverage:oneMilkDarkRoast];
NSLog(@"飲品名稱:%@,價(jià)格:%ld",oneMilkAndOneMochaDarkRoast.beverageDesc,[oneMilkAndOneMochaDarkRoast cost]);
那如何實(shí)現(xiàn)的呢?下面來(lái)看一下基類的代碼,在這里我實(shí)現(xiàn)了一個(gè)構(gòu)造方法
,這個(gè)構(gòu)造方法主要是為了當(dāng)飲料被構(gòu)造出來(lái)之后,我們的裝飾者
可以存儲(chǔ)下這個(gè)對(duì)象,并對(duì)這個(gè)對(duì)象進(jìn)行裝飾.這是基類的頭文件:
#import <Foundation/Foundation.h>
@interface Beverage : NSObject
@property (nonatomic, copy) NSString *beverageDesc;
@property (nonatomic, strong, readonly) Beverage *beverage;
- (NSInteger)cost;
- (instancetype)initWithBeverage:(Beverage *)beverage;
@end
實(shí)現(xiàn)文件:
#import "Beverage.h"
@interface Beverage ()
@property (nonatomic, strong, readwrite) Beverage *beverage;
@end
@implementation Beverage
- (instancetype)initWithBeverage:(Beverage *)beverage{
if (self = [super init]) {
self.beverage = beverage;
}
return self;
}
- (NSInteger)cost{
//子類若不實(shí)現(xiàn)花銷,則會(huì)采用父類,這會(huì)導(dǎo)致可能與我們的設(shè)計(jì)不同
return 0;
}
@end
深焙咖啡實(shí)現(xiàn)文件
#import "DarkRoast.h"
@implementation DarkRoast
- (NSString *)beverageDesc{
return @"DarkRoast";
}
- (NSInteger)cost{
return 15;
}
@end
牛奶調(diào)料的實(shí)現(xiàn)文件
#import "Milk.h"
@implementation Milk
- (NSInteger)cost{
return [self.beverage cost] + 8;
}
- (NSString *)beverageDesc{
return [NSString stringWithFormat:@"%@ 添加 Milk",self.beverage.beverageDesc];
}
@end
摩卡調(diào)料的實(shí)現(xiàn)文件
#import "Mocha.h"
@implementation Mocha
- (NSInteger)cost{
return [self.beverage cost] + 10;
}
- (NSString *)beverageDesc{
return [NSString stringWithFormat:@"%@ 添加 Mocha",self.beverage.beverageDesc];
}
@end