考慮一個咖啡店收費的問題:如何實現靈活的咖啡的價格計算。 咖啡店主要賣咖啡,可是後來爲了知足不一樣客戶的不一樣口味,只是純咖啡,顯得太單調了,就考慮增長不一樣的搭配,搭配不一樣的配料後會組成另外一種飲品,這樣,品種豐富了,但隨之問題也來了,如何爲不一樣新的品種計算新的準確的價格。兩種方案:git
第一種
:能夠採用繼承的方式,將純咖啡做爲基類,然後須要什麼品種的話,能夠生成一個子類,單獨做爲一個品種來重寫計算價格的方法,而且還能夠爲這個品種添加其餘功能。可是:繼承有一個很大的問題就是,這樣的方案實現是首先你是知道都有什麼品種的,纔會派生出各類子類,可是,若是後續想要在某個現有品種中去掉一些或者加上一些內容,甚至直接刪除這個品種,就會很麻煩的老是修改對應的類了,並且還有個缺點是:會產生不少種子類,若是品種不少,並且每一個品種的差異很小的時候,都分別單獨的做爲一個類就會很麻煩。github
第二種
:就是採用咱們今天要講的這篇文章的主題裝飾者模式。先類比一下生活中的一個例子:一張紙質的照片,想要讓這張照片保存的久一點,咱們能夠先給這張照片塑封;塑封后,以爲還不夠的話,可能還會給這張照片裝一個相框;加一個相框還以爲不能好好保護相片的話,再加個玻璃罩。在這個例子中,咱們能夠理解照片自己就是要被裝飾的對象,塑封膠、相框、玻璃罩都是做爲裝飾者。每一層的裝飾者都不會修改最裏邊的被裝飾的對象。這裏咱們能夠把具體的咖啡飲品當作被裝飾者,要加入的食物或飲料當作裝飾者,每一種咖啡飲品能夠被不一樣的裝飾者裝飾。編程
將上述爲不一樣咖啡飲品計算價格的問題用編程的概念來說就是如何可以透明地給一個對象增長功能,並實現功能的動態組合。這就是裝飾者模式的功能。設計模式
裝飾者模式可以實現動態地爲對象添加功能,從一個對象外部透明的給對象增長功能。透明地給一個對象增長功能,就是說要給一個對象增長功能,可是不能讓這個對象知道,也就是不能去修改這個對象
bash
每一個被裝飾者能夠被多個裝飾者裝飾。例如:黑咖啡(被裝飾者)能夠被牛奶(裝飾者)、水果(裝飾者)裝飾,並且,不一樣的裝飾者之間沒有前後順序的限制。ui
裝飾者須要和被裝飾的對象繼承於一樣的類或者實現一樣的接口(iOS中稱遵照一樣的協議),然後,在具體的裝飾者的實現中,轉調被裝飾者對象【這就須要裝飾者對象持有一個被裝飾者對象】atom
下邊是具體實現的UML圖和不一樣類之間的調用層次圖。 spa
CoffeeComponent
:咖啡基類(也能夠是接口/協議)BlackCoffee
:具體的咖啡,就是要被裝飾的對象。CondimentDecorator
:配料的基類(裝飾者的基類),並且須要繼承於被裝飾者基類CoffeeComponent
,同時還要持有一個CoffeeComponent
類型的屬性。MilkDecorator
:牛奶裝飾者,具體的裝飾者對象。從上邊的層次圖中能夠看出,多層裝飾者一層層的包在被裝飾對象的外部,功能方法的調用也是一層層遞歸調用被裝飾的對象。從圖中能夠看出:當黑咖啡被牛奶裝飾後,牛奶裝飾器就成爲了新的被裝飾者,能夠被後續的其它裝飾者裝飾,並且各個裝飾者之間是沒有順序要求的。順序徹底能夠按照本身的意願來進行。設計
//********************************咖啡組件(基類)*********************
@interface CoffeeComponent : NSObject
- (double)getPrice;
@end
@implementation CoffeeComponent//抽象組件,能夠寫默認實現的方法,也能夠用協議實現
- (double)getPrice
{
return 0.f;
}
@end
//********************************黑咖啡(具體咖啡類)*********************
@interface BlackCoffee : CoffeeComponent//繼承於抽象組件的具體組件
- (double)getPrice;
@end
@implementation BlackCoffee
- (double)getPrice
{
return 5;
}
@end
//********************************裝飾者基類*********************
@interface CondimentDecorator : CoffeeComponent//繼承於組件的裝飾者抽象類
- (instancetype)initWithComponent:(CoffeeComponent *)component;
@property (nonatomic,strong)CoffeeComponent *component;
@end
@implementation CondimentDecorator
- (instancetype)initWithComponent:(CoffeeComponent *)component
{
if (self = [super init]) {
_component = component;
}
return self;
}
@end
//********************************牛奶裝飾者(具體裝飾者)*********************
@interface MilkDecorator : CondimentDecorator//繼承於抽象佐料裝飾者的具體裝飾者
@end
@implementation MilkDecorator
- (double)getPrice
{
NSLog(@"牛奶加了2元");
return 2 + [self.component getPrice];
}
@end
//在此省略其它裝飾者的代碼,與牛奶裝飾者的代碼同樣。代碼能夠查看demo。
//=========================外部調用=====================
//純咖啡
BlackCoffee *blackCoffee = [[BlackCoffee alloc]init];
//加奶
MilkDecorator *milkDecorator = [[MilkDecorator alloc]initWithComponent:blackCoffee];
//加豆漿
SoyDecorator *soyDecorator = [[SoyDecorator alloc]initWithComponent:milkDecorator];
//加水果
FruitDecorator *fruitDecorator = [[FruitDecorator alloc]initWithComponent:soyDecorator];
NSLog(@"一共多少錢%f",[fruitDecorator getPrice]);
複製代碼
以上做爲筆者本身的讀書筆記,若有理解錯誤的地方,還請指出。謝謝!code
參考致謝:
《研磨設計模式》
《Head First設計模式》