设计模式-装饰者模式

栏目: IOS · 发布时间: 5年前

内容简介:考虑一个咖啡店收费的问题:如何实现灵活的咖啡的价格计算。 咖啡店主要卖咖啡,但是后来为了满足不同客户的不同口味,只是纯咖啡,显得太单调了,就考虑增加不同的搭配,搭配不同的配料后会组成另一种饮品,这样,品种丰富了,但随之问题也来了,如何为不同新的品种计算新的准确的价格。两种方案:

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

第一种 :可以采用继承的方式,将纯咖啡作为基类,而后需要什么品种的话,可以生成一个子类,单独作为一个品种来重写计算价格的方法,并且还可以为这个品种添加其他功能。但是:继承有一个很大的问题就是,这样的方案实现是首先你是知道都有什么品种的,才会派生出各种子类,但是,如果后续想要在某个现有品种中去掉一些或者加上一些内容,甚至直接删除这个品种,就会很麻烦的总是修改对应的类了,而且还有个缺点是:会产生很多种子类,如果品种很多,而且每个品种的差别很小的时候,都分别单独的作为一个类就会很麻烦。

第二种 :就是采用我们今天要讲的这篇文章的主题 装饰者模式 。先类比一下生活中的一个例子:一张纸质的照片,想要让这张照片保存的久一点,我们可以先给这张照片塑封;塑封后,觉得还不够的话,可能还会给这张照片装一个相框;加一个相框还觉得不能好好保护相片的话,再加个玻璃罩。在这个例子中,我们可以理解照片本身就是要被装饰的对象,塑封胶、相框、玻璃罩都是作为装饰者。每一层的装饰者都不会修改最里边的被装饰的对象。这里我们可以把具体的咖啡饮品当做被装饰者,要加入的食物或饮料当做装饰者,每一种咖啡饮品可以被不同的装饰者装饰。

将上述为不同咖啡饮品计算价格的问题用编程的概念来讲就是如何能够透明地给一个对象增加功能,并实现功能的动态组合。这就是 装饰者模式 的功能。

模式定义

装饰者模式能够实现动态地为对象添加功能,从一个对象外部透明的给对象增加功能。 透明地给一个对象增加功能,就是说要给一个对象增加功能,但是不能让这个对象知道,也就是不能去修改这个对象

每个被装饰者可以被多个装饰者装饰。例如:黑咖啡(被装饰者)可以被牛奶(装饰者)、水果(装饰者)装饰,而且,不同的装饰者之间没有先后顺序的限制。

具体实现

装饰者需要和被装饰的对象继承于同样的类或者实现同样的接口(iOS中称遵守同样的协议),而后,在具体的装饰者的实现中,转调被装饰者对象【这就需要装饰者对象持有一个被装饰者对象】

下边是具体实现的UML图和不同类之间的调用层次图。

设计模式-装饰者模式
  • 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]);

复制代码

总结

  • 装饰者模式比继承更灵活:继承是静态的,而且继承的子类都有基类同样的功能,但是装饰者模式能够把功能分离到不同的装饰器中,可以动态的选择想要什么功能。
  • 装饰者模式的本质是 动态组合 :动态的进行装饰器的组合,可以为被装饰对象透明的增加功能。
  • 装饰者模式不仅可以增加功能,也可以完全实现新的功能和控制功能的访问。可以在装饰器中调用被装饰对象功能的时候,进行控制。
  • 装饰者模式的 缺点 :会产生细粒度的对象,如果一系列的复杂功能,想要把不同的功能都细分到不同的装饰器上,就会产生很多细粒度的对象。

以上作为笔者自己的读书笔记,如有理解错误的地方,还请指出。谢谢!

Demo地址

参考致谢:

《研磨设计模式》

《Head First设计模式》


以上所述就是小编给大家介绍的《设计模式-装饰者模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web安全测试

Web安全测试

霍普(Paco Hope)、沃尔瑟(Ben Waltber) / 傅鑫 / 清华大学出版社 / 2010-3 / 39.00元

《Web安全测试》内容简介:在你对Web应用所执行的测试中,安全测试可能是最重要的,但它却常常是最容易被忽略的。《Web安全测试》中的秘诀演示了开发和测试人员在进行单元测试、回归测试或探索性测试的同时,如何去检查最常见的Web安全问题。与即兴的安全评估不同的是,这些秘诀是可重复的、简洁的、系统的——可以完美地集成到你的常规测试套装中。 《Web安全测试》中的秘诀所覆盖的基础知识包括了从观察客......一起来看看 《Web安全测试》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具