装饰器模式.ppt_第1页
装饰器模式.ppt_第2页
装饰器模式.ppt_第3页
装饰器模式.ppt_第4页
装饰器模式.ppt_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

结构型 装饰器模式 Decorator 欢迎来到星巴兹咖啡 星巴兹 Starbuzz 是以扩张速度最快而闻名的咖啡连锁店如果你在街角看到它的店 在对面街上肯定还会看到另一家因为扩张速度实在太快了 他们准备更新订单系统 以合乎他们的饮料供应要求他们原先的类设计是这样的 购买咖啡时 也可以要求在其中加入各种调料 例如 蒸奶 SteamedMilk 豆浆 Soy 摩卡 Mocha 也就是巧克力风味 或覆盖奶泡星巴兹会根据所加入的调料收取不同的费用所以订单系统必须考虑到这些调料部分这是他们的第一个尝试 为什么设计这么多类呀 利用实例变量和继承 就可以追踪这些调料先从Beverage基类下手 加上实例变量代表是否加上调料 牛奶 豆浆 摩卡 奶泡 请为下面类的cost 方法书写代码 用伪Java代码即可 publicclassBeverage publicdoublecost publicclassDarkRoastextendsBeverage publicDarkRoast description MostExcellentDarkRoast publicdoublecost publicclassDarkRoastextendsBeverage publicDarkRoast description MostExcellentDarkRoast publicdoublecost return1 99 super cost 潜在的问题 当哪些需求或因素改变时会影响这个设计 调料价钱的改变会使我们更改现有代码一旦出现新的调料 我们就需要加上新的方法 并改变超类中的cost 方法以后可能会开发出新饮料 对这些饮料而言 例如 冰茶 某些调料可能并不适合 但是在这个设计方式中 Tea 茶 子类仍将继承那些不适合的方法 例如 hasWhip 加奶泡 万一顾客想要双倍摩卡咖啡 怎么办 尽管继承威力强大 但是体会到它并不总是能够实现最有弹性和最好维护的设计不通过继承又能如何达到复用呢 利用组合 composition 和委托 delegation 可以在运行时具有继承行为的效果利用继承设计子类的行为 是在编译时静态决定的 而且所有的子类都会继承到相同的行为 然而 如果能够利用组合的做法扩展对象的行为 就可以在运行时动态地进行扩展 可以利用此技巧把多个新职责 甚至是设计超类时还没有想到的职责加在对象上 而且 可以不用修改原来的代码利用组合维护代码 通过动态地组合对象 可以写新的代码添加新功能 而无须修改现有代码既然没有改变现有代码 那么引进bug或产生意外副作用的机会将大幅度减少 开放 关闭原则 类应该对扩展开放 对修改关闭我们的目标是允许类容易扩展 在不修改现有代码的情况下 就可搭配新的行为如能实现这样的目标 有什么好处呢 这样的设计具有弹性可以应对改变 可以接受新的功能来应对改变的需求想想观察者模式 通过加入新的观察者 我们可以在任何时候扩展Subject 主题 而且不需向主题中添加代码 认识装饰者模式 我们已经了解利用继承无法完全解决问题 在星巴兹遇到的问题有 类数量爆炸 设计死板 以及基类加入的新功能并不适用于所有的子类所以 在这里要采用不一样的做法 我们要以饮料为主体 然后在运行时以调料来 装饰 decorate 饮料 比方说 如果顾客想要摩卡和奶泡深焙咖啡 那么 要做的是 拿一个深焙咖啡 DarkRoast 对象以摩卡 Mocha 对象装饰它以奶泡 Whip 对象装饰它调用cost 方法 并依赖委托 delegate 将调料的价钱加上去但是如何 装饰 一个对象 而 委托 又要如何与此搭配使用呢 给一个暗示 把装饰者对象当成 包装者 让我们看看这是如何工作的 以DarkRoast对象开始 以装饰者构造饮料订单 顾客想要摩卡 Mocha 所以建立一个Mocha对象 并用它将DarkRoast对象包 wrap 起来 顾客也想要奶泡 Whip 所以需要建立一个Whip装饰者 并用它将Mocha对象包起来 别忘了 DarkRoast继承自Beverage 且有一个cost 方法 用来计算饮料价钱 现在 该是为顾客算钱的时候了 通过调用最外圈装饰者 Whip 的cost 就可以办得到 Whip的cost 会先委托它装饰的对象 也就是Mocha 计算出价钱 然后再加上奶泡的价钱 装饰者和被装饰对象有相同的超类型你可以用一个或多个装饰者包装一个对象既然装饰者和被装饰对象有相同的超类型 所以在任何需要原始对象 被包装的 的场合 可以用装饰过的对象代替它装饰者可以在所委托被装饰者的行为之前与 或之后 加上自己的行为 以达到特定的目的对象可以在任何时候被装饰 所以可以在运行时动态地 不限量地用你喜欢的装饰者来装饰对象 这是目前所知道的一切 装饰者模式动态地将责任附加到对象上若要扩展功能 装饰者提供了比继承更有弹性的替代方案 定义装饰者模式 装饰我们的饮料 在继承和组合之间 观念有一些混淆 有一点混淆 我原以为在这个模式中不会使用继承 而是要利用组合取代继承看看类图 CondimentDecorator扩展自Beverage类 这用到了继承的确是如此 但这么做的重点在于 装饰者和被装饰者必须是一样的类型 也就是有共同的超类 这是相当关键的地方 在这里 我们利用继承达到 类型匹配 而不是利用继承获得 行为 为何装饰者需要和被装饰者 亦即被包装的组件 有相同的 接口 因为装饰者必须能取代被装饰者但是行为又是从哪里来的 当我们将装饰者与组件组合时 就是在加入新的行为 所得到的新行为 并不是继承自超类 而是由组合对象得来的 将装饰者与组件组合时 就是在加入新的行为 所得到的新行为 并不是继承自超类 而是由组合对象得来的继承Beverage抽象类 是为了有正确的类型 而不是继承它的行为 行为来自装饰者和基础组件 或与其他装饰者之间的组合关系因为使用对象组合 可以把所有饮料和调料更有弹性地加以混和与匹配 非常方便 如果依赖继承 那么类的行为只能在编译时静态决定 换句话说 行如果不是来自超类 就是子类覆盖后的版本 反之 利用组合 可以把装饰者混合着用 而且是在 运行时 可以在任何时候 实现新的装饰者增加新的行为 如果依赖继承 每当需要新行为时 还得修改现有的代码 代码清单 写下星巴兹的代码 先从Beverage类下手 这不需要改变星巴兹原始的设计 如下所示 代码清单 让我们也来实现Condiment 调料 抽象类 也就是装饰者类 现在 已经有了基类 让我们开始开始实现一些饮料先从浓缩咖啡 Espresso 开始我们还需要为具体的饮料设置描述 而且还必须实现cost 方法 写饮料的代码 代码清单 如果回头去看看装饰者模式的类图 将发现我们已经完成了抽象组件 Beverage 有了具体组件 HouseBlend 也有了抽象装饰者 CondimentDecorator 现在 我们就来实现具体装饰者 先从摩卡下手 写调料代码 代码清单 供应咖啡 我们在星巴兹的朋友决定开始在菜单上加上咖啡的容量大小 供顾客可以选择小杯 tall 中杯 grande 大杯 venti 星巴兹认为这是任何咖啡都必须具备的 所以在Beverage类中加上了getSize 与setSize 他们也希望调料根据咖啡容量收费 例如 小中大杯的咖啡加上豆浆 分别加收0 10 0 15 0 20美金如何改变装饰者类应对这样的需求 习题解答 真实世界的装饰者 JavaI O 装饰java io类 编写自己的JavaI 0装饰者 编写一个装饰者 把输入流内的所有大写字符转成小写举例 当读取 IknowtheDecoratorPatternthereforeIRULE 装饰者会将它转成 iknowthedecoratorpatternthereforeirule 测试你的新JavaI O装饰者 要点 继承属于扩展形式之一 但不见得是达到弹性设计的最佳方式在我们的设计中 应该允许行为可以被扩展 而无须修改现有的代码组合和委托可用于在运行时动态地加上新的行为除了继承 装饰者模式也可以让我们扩展行为装饰者模式意味着一群装饰者类 这些类用来包装具体组件装饰者类反映出被装饰的组件类型 事实上 他们具有相同的类型 都经过接口或继承实现 要点 装饰者可以在被装饰者的行为前面与 或后面加上自己的行为 甚至将被装

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论