設(shè)計(jì)模式之裝飾者模式
需求場(chǎng)景
咖啡店訂單系統(tǒng)
需求分析
咖啡種類(lèi)比較多茧球,結(jié)賬的時(shí)候我們需要知道咖啡名和價(jià)格谨读。首先想到的是我們創(chuàng)建一個(gè)咖啡的基類(lèi)号醉,該類(lèi)提供一個(gè)價(jià)格和名稱(chēng)的接口,店里的所有的飲料都繼承該類(lèi)蚂斤。
問(wèn)題
- 我們給每種咖啡都要?jiǎng)?chuàng)建一個(gè)子類(lèi),一個(gè)咖啡店有很多種飲料槐沼,這樣就會(huì)創(chuàng)建很多的類(lèi)曙蒸,類(lèi)的數(shù)目過(guò)于龐大
- 當(dāng)咖啡店不斷出新品的時(shí)候,系統(tǒng)不便于維護(hù)
分析
決定價(jià)格的因素:
- 不同種類(lèi)的咖啡的價(jià)格不一樣
- 咖啡里面的加入的調(diào)料的價(jià)格也不同
咖啡飲料的價(jià)格 = 咖啡的價(jià)格 + 加入調(diào)料的價(jià)格
由上邊可以看出:
咖啡相當(dāng)于‘被裝飾者’ 岗钩,調(diào)料相當(dāng)于’裝飾者‘
例如:
Espresso Macchiato(濃縮瑪奇朵 = Espresso(濃縮咖啡) +Milk(牛奶) + Mocha(摩卡)纽窟。
Espresso 相當(dāng)于”被裝飾者“ , Mocha和Milk相當(dāng)于‘裝飾者’
只要對(duì)被裝飾者和裝飾者進(jìn)行不同的組合兼吓,就可以得到不同的咖啡
這樣的組合是動(dòng)態(tài)的臂港,被裝飾者和裝飾者不是寫(xiě)死在類(lèi)里的比如繼承,類(lèi)繼承是在編譯的時(shí)候增加行為视搏,而裝飾者模式是在運(yùn)行時(shí)增加行為)审孽,而是動(dòng)態(tài)的組合,即在運(yùn)行時(shí)進(jìn)行綁定
設(shè)計(jì)結(jié)構(gòu)如下圖:
客點(diǎn)了一杯 Espresso Macchiato(濃縮瑪奇朵)浑娜,那么系統(tǒng)將會(huì)開(kāi)始以下的工作流程:
- 首先實(shí)例化一個(gè)Espresso對(duì)象佑力,對(duì)象里面有名字和基本價(jià)格
- 實(shí)例化一個(gè)milk的裝飾者對(duì)象,對(duì)象里面有名字和價(jià)格筋遭,同時(shí)讓milk持有Espresso
- 調(diào)用milk的cost()方法打颤,這是會(huì)調(diào)用Espresso的cost方法,并把返回的價(jià)格和milk的價(jià)格相加漓滔。
- 實(shí)例化一個(gè)Mocha的裝飾者對(duì)象编饺,對(duì)象里面有名字和價(jià)格,同時(shí)讓Mocha持有milk對(duì)象
- 最后調(diào)用 Mocha 對(duì)象的 cost() 方法响驴,這個(gè)方法會(huì)去調(diào)用 Milk 對(duì)象的 cost() 方法透且,并將返回的價(jià)格和 mocha 的價(jià)格相加,如此我們就得到了 Espresso 配 milk 和 mocha 的價(jià)格豁鲤。
代碼實(shí)現(xiàn)
Beverage.h
#import <Foundation/Foundation.h>
@protocol Beverage <NSObject>
@optional
-(NSString *)getName;
-(double)cost;
@end
CondimentDecorator.h
#import <Foundation/Foundation.h>
#import "Beverage.h"
@protocol CondimentDecorator <Beverage>
@end
Espresso.h
#import <Foundation/Foundation.h>
#import "Beverage.h"
@interface Espresso : NSObject<Beverage>
@end
Espresso.m
#import "Espresso.h"
@implementation Espresso{
NSString * _name;
}
-(instancetype)init{
if(self = [super init]){
_name = @"Espresso";
}
return self;
}
-(NSString *)getName{
return _name;
}
-(double)cost{
return 10.0;
}
@end
Milk.h
#import <Foundation/Foundation.h>
#import "Beverage.h"
#import "CondimentDecorator.h"
@interface Milk : NSObject<CondimentDecorator>
@property(nonatomic,retain) id<Beverage> Beverage;
-(instancetype)initWithBeverage:(id<Beverage>)beverage;
@end
Milk.m
#import "Milk.h"
#import "Beverage.h"
@implementation Milk{
NSString * _name;
}
-(instancetype)initWithBeverage:(id<Beverage>)beverage{
if(self = [super init]){
_name = @"Milk";
self.Beverage = beverage;
}
return self;
}
-(NSString *)getName{
return [NSString stringWithFormat:@"%@ + %@",[self.Beverage getName],_name];
}
-(double)cost{
return [self.Beverage cost] + 4.0;
}
@end
Mocha同Milk
調(diào)用
Espresso * ex = [[Espresso alloc] init];
NSLog(@"%@ %.2f",ex.getName,ex.cost);
Milk * milk = [[Milk alloc] initWithBeverage:ex];
NSLog(@"%@ %.2f",milk.getName,milk.cost);
Mocha * mocha = [[Mocha alloc] initWithBeverage:milk];
NSLog(@"%@ %.2f",mocha.getName,mocha.cost);
參考文章:
《HeadFirst設(shè)計(jì)模式》