• decorator


    欢迎来到星巴兹咖啡

    星巴兹(Starbuzz)是以扩张速度最快而闻名的咖啡连锁店之一,因为扩张速度实在太快,他们准备更新订单系统,以合乎他们的饮料供应要求。他们原来的设计是这样的……

    decorator

    购买咖啡时,也可以在其中加入各种饮料。例如:蒸奶(Steamed Milk)、豆浆(Soy)、摩卡(Mocha,也就是巧克力)或覆盖奶泡。星巴兹会根据所加入的饮料收取不同的费用。

    QQ图片20160419072120

    这简直是“类”爆炸,干嘛设计这么多类,可以利用实例变量和继承追踪这些调料呀!先从Beverage基类下手,加上实例变量代表是否加上饮料(牛奶、豆浆、摩卡、奶泡……)

    decorator

    Beverage类中的cost()不再是个抽象方法,提供了它的实现,计算要加入各种饮料的调料价钱。子类覆盖cost()并扩展其功能,把指定的饮料类型的价钱加进来。然而,这种设计存在着问题:若有其它类型的饮料加进来,需要在Beverage类中假如成员变量,并生成setteer/getter方法,需要再写个子类继承它,这违背了重要的设计原则:类应该对扩展开放,对修改关闭。也就是说子类可以扩展父类Beverage,但不能修改其内部结构。

    认识装饰者模式

    好了,我们已经了解利用继承无法完全解决问题,在星巴兹遇到的问题有:类数量爆炸、设计死板、以及基类加入的新功能并不适用于所有的子类。所以,这里需要采用不一样的做法:一饮料为主题,然后运行时以调料来“装饰”(decorate)饮料。比如,顾客想要摩卡和奶泡深焙咖啡,那么,要做的是:

    1、拿一个深焙咖啡(DarkRoast)对象

    2、以摩卡(Mocha)对象装饰它

    3、以奶泡(Whip)对象装饰它

    4、调用cost()方法,并依赖委托(delegate)将调料的价钱加上去。

    以装饰者构造饮料订单

    1、以DarkRoast对象开始

    decorator

    2、顾客想要摩卡(Mocha),所以建立一个Mocha对象,并用它将DarkRoast对象包装(wrap)起来。Mocha对象是个装饰者,它的类型“反映”了它所装饰的对象(本例中,就是Beverage)。所谓的“反映”,指的是两者类型一致。所以Mocha也有一个cost()方法,通过多态,可以把Mocha所包裹的任何Beverage当成是Beverage(因为Mocha是Beverage的子类型)。

    3、顾客也想要奶泡(Whip),所以建立一个Whip装饰者,并用它将Mocha对象包装起来。别忘了,DarkRoast继承自Beverage,且有一个cost()方法,用来计算饮料价钱。

    4、现在,是顾客算钱的时候了,通过最外圈装饰者Whip的cost()就可以办到。Whip的cost()会先委托它装饰的对象(Mocha)计算出价钱,然后加上奶泡的价钱。

    QQ图片20160421062930

    通过以上可以发现:

    1、装饰者和被装饰对象有相同的超类型;

    2、可以用一个或多个装饰者包装一个对象;

    3、既然装饰者和被装饰者有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它;

    4、装饰者可以在所委托被装饰者的行为之前/之后,加上自己的行为,以达到特定的目的;

    5、对象可以在任何时候被装饰,所以可以在运行时动态地,不限量的用你喜欢的装饰者来装饰对象。

    定义装饰者模式

    装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的解决方案。

    QQ图片20160421064823

    Java I/O中的装饰者模式

    Java I/O中FileInputStream是被装饰的“组件”,I/O程序库包含了FileInputStream、StringBufferInputStream、FileInputStream、ByteArrayInputStream……这些类都提供了最基本的字节读取功能。

    BufferedInputStream是一个具体的“装饰者”,他加入了两种行为:利用缓冲输入来改进性能;用一个readLine()方法(用来一次读取一行文本输入数据)来增强接口。

    LineNumberInputStream也是一个具体的“装饰者”,他加上了计算行数的能力。

    BufferedInputStream及LineNumberInputStream都扩展自FilterInputStream,而FilterInputStream是一个抽象的装饰类。

    Java I/O引出装饰者模式的一个缺点:利用装饰者模式,常常造成设计中有大量的小类,数量很多,会造成使用此API的困扰。

  • 相关阅读:
    魔兽70TBC猎人常用宏
    魔兽70TBC猎人宝宝技能汇总
    redis常用概念
    mongodb分片集群开启安全认证
    mongodb集群搭建(分片+副本)
    mongodb 用户权限控制
    greenplum数据迁移
    greenplum资源队列
    GreenPlum 集群常用命令
    COCOS 实现Player玩家控制的左右控制,实现马里奥一样的移动
  • 原文地址:https://www.cnblogs.com/devotion/p/5411013.html
Copyright © 2020-2023  润新知