有爱,有技术,有你^_^)y
╱人◕‿‿◕人╲订下契约(注册新用户)

合作站点账号登陆

QQ登录

只需一步,快速开始

快捷导航

玩不坏的小黑

https://www.gn00.com/?480680

设计模式 装饰者模式学习

已有 97 次阅读2016-5-3 10:26 |个人分类:编程| 设计模式, 装饰者模式

装饰者模式

设计模式 装饰者模式

英文中文
cost价钱;成本
beverage饮料
warp包;包裹
component零件
concrete具体
decorator装饰
condlment调料品;调料

认识装饰着模式 
好了,我们已经了解利用继承无法完全解决问题,在星巴兹遇到的问题有:类数量爆炸,设计死板,以及基类加入的新功能并不适用于所有的子类

所以,在这里要采用不一样的做法:我们要以饮料为主题,然后在运行是以调料来"装饰"(decorate)饮料 比方说,如果顾客想要摩卡和奶泡深焙咖啡,那么,要做的是: 
1 一个深焙咖啡(DarkRoast)对象 
2 以摩卡(Mocha) 对象装饰它 
3 以奶泡(Whip)对象装饰它

好了!但是如何"装饰"一个对象,而"委托"又要如何与此搭配使用呢?给你一个暗示:吧装饰着对象当成"包装者".让我们看看这是如何工作的 
以装饰着构造饮料订单

1.以DarkRoast对象开始 
别忘了,DarkRoast继承自Beverage,且有一个用来计算饮料借钱的cost()方法 
2.顾客想要摩卡(Mocha),所以建立一个Mocha对象,并用它将DarkRoast对象包(wrap)起来 
Mocha对象是一个装饰者,它的类型"反应"了它装饰的对象(本例中,就是Beverage),所谓的"反映",指的就是两者类型一致 
所以Mocha也有一个cost()方法,通过多态也可以把Mocha所包裹的任何Beverage当成是Beverage(因为Mocha是Beverage的子类型) 
3.顾客也想要奶泡(Whip),所以需要建立一个Whip装饰者,并用它将Mocha对象包起来 别忘了,DarkRoast继承字Beverage,且有一个cost()方法,用来计算饮料价钱 
whip是一个装饰者,所以它也反映了DarkRoast类型,并包括一个cost()方法

所以,被Mocha和Whip抱起来的DarkRoast对象仍然是一个Beverage,仍然可以具有DarkRoast的一切行为,包括调用它的cost()方法 
4.现在,该是为顾客算钱的时候了,通过调用最外圈装饰者(Whip)的cost()就可以办得到 Whip的cost()会先委托它装饰的对象也就是Mocha 计算出价钱, 
然后再加上奶泡的价钱

1 首先,调用最外圈装饰者Whip的cost() 
2 Whip调用Mocha的cost() 
3 Mocha调用DarkRoast的cost() 
4 DarkRoast返回它的价钱0.99 
5 Mocha在DarkRoast的结果上,加上自己的价钱0.20,返回新的价钱1.19 
6 Whip在Mocha的返回结果上加上自己的价钱0.10,然后返回最后结果1.29

好了,这是目前所知道的一切

装饰者和被装饰者对象有相同的超类型 
你可以用一个或多个装饰者包装一个对象 
既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它 
装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的 
对象可以在任何时候被装饰,所以可以在运行是动态地,不限量的使用你喜欢的装饰者来装饰对象

现在,就来看看装饰者模式,并写一些代码,了解他到底是怎么工作的

定义装饰者模式 
让我们先来看看装饰者模式的说明:

装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案 
虽然这说明装饰者模式的"角色",但是没说明怎么在我们实现中应用它,我们来看看类图,会有一些帮助(下一页,我们会将此结构套用在饮料问题上)

装饰我们的饮料 
好吧!让星巴兹饮料也能符合此框架 
Beverage相当于抽象的 
Component类

 Beverage
description(描述)
getDescription()
cost()
//其他有用的方法
Beveragecost()
HouseBlendcost()
DarkRoastcost()
Espressocost()
decafcost()
↑四个具体组件,每个代表一种咖啡类型
Beverage
CondlmentDecoratorgetDescription()
CondlmentDecoratorgetDescription())
MilkBeverage Beveragecost()getDescription()
MochaBeverage beveragecost()getDescription()
SoyBeverage beveragecost()getDescription()
WhipBeverage beveragecost()getDescription()
这是调料装饰者 请注意,他们除了必须实现cost()之外,还必须实现getDescription(),稍后我们会解释为什么

在往下看之前,想想如何实现咖啡和调料的cost()方法,也思考一下如何实现调料的getDescription()方法

办公室隔间对话 
在继承和组合之间,观念有一些混淆

我原以为在这个模式中不会使用继承,而是要利用组合取代继承 
1 看看类图 CondimentDecorator扩展字Beverage类,这用到了继承,不是吗 
2 的确是如此,但我认为,这么做的重点在于,装饰者和被装饰者必须是一样的类型,也就是有共同的超累,这是相当关键的地方.在这里,我们利用继承达到 类型匹配,而不是利用继承类获得 "行为" 
1 我知道为何装饰者需要和被装饰者有相同的"接口" ,因为装饰者必须能取代被装饰者 但是行为又是从哪里来的? 
2 当我们将装饰者与组件组合时,就是在加入新的行为 所得到的新行为,并不是继承自超类,而是由组合对象得来的 
1 好的.继承Beverage抽象类,是为了有正确的类型,而不是继承它的行为

Abstract(抽象)可以修饰类 方法

如果将一个类设置为abstract,则此类必须被继承使用 此类不可生成对象,必须被继承使用 
Abstract可以将子类的共性最大限度的提取出来,放在父类中,以提高程序的间接性 
Abstract虽然不能生成对象,但是可以声明,作为编译时类型,但不能作为运行时类型

装饰者模式

如果我将代码针对特定种类的具体组件,做一些特殊的事,比如 打折

设计箱内的工具 
本章已经接近尾声,你的工具箱内又多了一个新的原则和一个新的模式 
要点 
继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式 
在我们的设计中,应该允许行为被扩展,而无须修改现有的代码 
组合和委托可用于在运行时动态地加上新的行为 
除了继承,装饰者模式也可以让我们扩展行为 
装饰者模式意味着一群装饰者类,这些类用来包装具体组件 
装饰者类反映出装饰者的组件类型 
装饰者模式--动态地将责任附加到对象上 想要扩展功能,装饰者提供有别于继承的另一种选择


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist doodle 涂鸦板

小黑屋|技术宅(基宅) ( 粤ICP备18082987号-1 | 浙公网安备 33010902001746号 )

GMT+8, 2024-5-19 11:51 , Processed in 0.113368 second(s), 7 queries , Redis On.

Copyright © 2018 技术宅社区

Powered by Discuz! X3.5

返回顶部