设计模式-装饰者模式

要解决的问题

考虑一个咖啡店收费的问题:如何实现灵活的咖啡的价格计算。 咖啡店主要卖咖啡,可是后来为了知足不一样客户的不一样口味,只是纯咖啡,显得太单调了,就考虑增长不一样的搭配,搭配不一样的配料后会组成另外一种饮品,这样,品种丰富了,但随之问题也来了,如何为不一样新的品种计算新的准确的价格。两种方案: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

Demo地址


参考致谢:

《研磨设计模式》

《Head First设计模式》

相关文章
相关标签/搜索