深入浅出装饰模式.doc

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
深入浅出装饰模式.doc

深入浅出装饰模式 一、引子 装饰模式?肯定让你想起又黑又火的家庭装修来。其实两者在道理上还是有很多相像的地方。家庭装修无非就是要掩盖住原来实而不华的墙面,抹上一层华而不实的涂料,让生活多一点色彩。而墙还是那堵墙,他的本质一点都没有变,只是多了一层外衣而已。 那设计模式中的装饰模式,是什么样子呢? 通常OO程序员会用继承的方法来扩展类的功能,并进而解决所面临的问题。但继承的威力最多也只能到编译时刻为止,运行时它也无能为力了(这里还没有说继承可能带来的麻烦,我们将在后面见到)。但是能够在运行时对类功能进行扩展那才叫“牛”。且看装饰模式是如何做到这点的。 二、定义和结构 装饰模式(Decorator Pattern)也叫包装器模式(Wrapper Pattern)。GoF在《设计模式》一书中给出的定义为:动态地给一个对象添加一些额外的职责。换而言之,装饰类为子类扩展新功能提供了一种灵活的替换机制,Decorator模式比生成子类更为灵活。 这里有一家著名的咖啡店Starbuzz,正在抓狂地更新其订货系统,以适应不断增长的供货要求。 为了是咖啡更好喝,或更符合你的口味,你可以向咖啡店要多种调味品,如steamed milk、soy、mocha,或巧克力等等(当然这都是要付钱的,否则就不会有我们这里的问题的 ()。Starbuzz咖啡店为了调味品计费的问题头都大了,因为它们都要单独处理才行,请看他们的第一个设计: 怎么样?类爆炸了吧!这是因为每种咖啡中的cost( ) 方法都要考虑其订单中的不同的调味料计费问题。 上面的设计显然太蠢了,看看一个更聪明的OO程序员是如何设计的。他将设计一些实例变量,并用继承超类的方法来追踪调味料的情况。 然后再添加子类,它们各自对应于菜单上的一种咖啡(或其它饮料): 相关代码如下,其中最关键的是cost( )方法的代码: 看起来还不错,一共也只有5个类,cost( )方法也不算太复杂。那么这样的设计行吗?请想想下列问题: 当每种调料的价格发生变化怎么办?——好象问题不大,我们还不必改写代码! 如果要加入新的调味料该怎么办?——我们不得不增加新方法并修改超类中的cost( )方法! 咖啡店还可以卖别的饮料。如Ice Tea,调味料是不适用于它们的,但子类IceTea继承hasWhip( )这样的方法仍然是非常合理的。千万不要忘记分类学的原则,想想上述设计违反了分类学的哪些原则? 如果客人想要两份mocha调料,该怎么办? 如果客人想要三份whip调料,该怎么办? 如果客人想要四份soy调料,该怎么办? ……等等其它问题…… 此时我们可以考虑采用装饰模式来动态的解决上述问题了。先看看装饰模式的组成,不必急于解决上面的问题,到了下面自然就明白了! 抽象构件角色(Component):定义一个抽象接口,以规范准备接收附加责任的对象。 具体构件角色(Concrete Component):这是被装饰器,定义一个将要被装饰增加功能的类。 装饰角色(Decorator):持有一个构件对象的实例,并定义了抽象构件定义的接口。 具体装饰角色(Concrete Decorator):负责给构件添加增加的功能。 以下是装饰模式的类图: 卧室谈话 Mary:哦,我有点困惑……我以为我们不会在这个模式中使用继承,而是更加依赖组合来解决问题。 Sue: 你什么意思? Mary:看看这个类图。类CondimentDecorator扩展了类Beverage。这是继承,对吗? Sue: 对。我想关键点在于装饰器必须与被装饰对象具有相同的类型。因此我们在这里使用了继承以获得类型匹配的效果,但我们并不使用继承来获得行为。 Mary:哦,我知道装饰器为何需要具有与被包装组件一致的“接口”了,因为它们需要取代后者。但相关的行为从哪里来呢? Sue: 当我们将一个装饰器与一个组件组合在一起时,我们就在增加新的行为。我们不是通过继承超类,而是通过将对象组合在一起来获得新的行为。 Mary:好的,因此我们继承了抽象类Beverage以便具有正确的类型,而不是继承它的行为。行为是通过与其它装饰器进行组合而加入的。 Sue: 非常正确。 Mary:喔……我知道了,因为我们使用了对象组合,我们在如何将调味品与饮料混合起来的问题上获得了全面而更多的灵活性。非常顺畅。 Sue: 是的,如果我们依赖继承的话,那么我们的行为在编译时就被静态地确定了。换句话说,我们只能拥有超类给予的,或是我们重载的行为。而通过组合,我们可以将装饰器任意地进行混合和匹配……在运行时。 Mary:而按我的理解,我们可以在任意时刻实现新的装饰器以增加新的行为。如果我们依赖继承,当我们需要新的行为时就必须进入并修改原有的代码了。 Sue: 完全正确。 Mary:我还有一个问题。如果

文档评论(0)

shengyp + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档