设计模式--装饰模式

装饰模式【Decorator Pattern】
Ladies and gentlemen,May I get your attention,Please?,Now I’m going to talk
about decorator pattern.装饰模式在中国使用的那实在是多,中国的文化是中庸文化,说
话或做事情都不能太直接,需要有技巧的,比如说话吧,你要批评一个人,你不能一上来就
说你这个做的不对,那个做的不对,你要先肯定他的成绩,表扬一下优点,然后再指出瑕疵,
指出错误的地方,最后再来个激励,你修改了这些缺点后有那些好处,比如你能带更多的小
兵,到个小头目等等,否则你一上来就是一顿批评,你瞅瞅看,肯定是不服气,顶撞甚至是
直接“此处不养爷,自有养爷处”开溜哇。这是说话,那做事情也有很多,在山寨产品流行
之前,假货很是比较盛行的,我在2002 年买了个手机,当时老板吹的是天花乱坠,承诺这
个手机是最新的,我看着也像,壳子是崭新的,包装是崭新的,没有任何瑕疵,就是比正品
便宜了一大截,然后我买了,缺钱哪,用来3 个月,坏了,一送修,检查,说这是个新壳装
旧机,我晕!拿一个旧手机的线路板,找个新的外壳、屏幕、包装就成了新手机,装饰模式
害人不浅呀!
我们不说不开心的事情,今天举一个什么例子呢?就说说我上小学的的糗事吧。我上小
学的时候学习成绩非常的差,班级上40 多个同学,我基本上都是在排名45 名以后,按照老
师给我的定义就是“不是读书的料”,但是我老爸管的很严格,明知道我不是这块料,还是
往赶鸭子上架,每次考试完毕我都是战战兢兢的,“竹笋炒肉”是肯定少不了的,能少点就
少点吧,肉可是自己的呀。四年级期末考试考完,学校出来个很损的招儿(这招儿现在很流
行的),打印出成绩单,要家长签字,然后才能上五年级,我那个恐惧呀,不过也就是几秒
钟的时间,玩起来什么都忘记了。
我们先看看这个成绩单的类图:
您的设计模式
第 130 页
成绩单的抽象类,然后有一个四年级的成绩单实现类,先看抽象类:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 成绩单的抽象类
*/
public abstract class SchoolReport {
//成绩单的主要展示的就是你的成绩情况
public abstract void report();
//成绩单要家长签字,这个是最要命的
public abstract void sign();
}
然后看我们的实现类FouthGradSchoolReport:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
您的设计模式
第 131 页
* 四年级的成绩单,这个是我们学校第一次实施,以前没有干过
* 这种“缺德”事。
*/
public class FouthGradeSchoolReport extends SchoolReport {
//我的成绩单
public void report() {
//成绩单的格式是这个样子的
System.out.println("尊敬的XXX家长:");
System.out.println(" ......");
System.out.println(" 语文 62 数学65 体育 98 自然 63");
System.out.println(" .......");
System.out.println(" 家长签名: ");
}
//家长签名
public void sign(String name) {
System.out.println("家长签名为:"+name);
}
}
成绩单出来,你别看什么62,65 之类的成绩,你要知道在小学低于90 分基本上就是中
下等了,唉,爱学习的人太多了!怎么着,那我把这个成绩单给老爸看看?好,我们修改一
下类图,成绩单给老爸看:
老爸开始看成绩单,这个成绩单可是最真实的,啥都没有动过,原装,看Father 类:
您的设计模式
第 132 页
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 老爸看成绩单了
*/
public class Father {
public static void main(String[] args) {
//成绩单拿过来
SchoolReport sr = new FouthGradeSchoolReport();
//看成绩单
sr.report();
//签名?休想!
}
}
运行结果如下:
尊敬的XXX家长:
......
语文 62 数学65 体育 98 自然 63
.......
家长签名:
就这成绩还要我签字?!老爸就开始找笤帚,我的屁股已经做好了准备,肌肉要绷紧,要
不那个太疼了!哈哈,幸运的是,这个不是当时的真实情况,我没有直接把成绩单交给老爸,而
是在交给他之前做了点技术工作,我要把成绩单封装一下,封装分类两步走:
第一步:跟老爸说各个科目的最高分,语文最高是75,数学是78,自然是80,然老爸觉
的我成绩与最高分数相差不多,这个是实情,但是不知道是什么原因,反正期末考试都考的不怎
么样,但是基本上都集中在70 分以上,我这60 多分基本上还是垫底的角色;
第二步:在老爸看成绩单后,告诉他我是排名第38 名,全班,这个也是实情,为啥呢?有
将近十个同学退学了!这个情况我是不说的。不知道是不是当时第一次发成绩单,学校没有考虑
清楚,没有写上总共有多少同学,排名第几名等等,反正是被我钻了个空子。
您的设计模式
第 133 页
那修饰是说完了,我们看看类图如何修改:
我想这是你最容易想到的类图,通过直接增加了一个子类,重写report 方法,很容易的
解决了这个问题,是不是这样?是的,确实是,确实是一个很好的办法,我们来看具体的实现:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 对这个成绩单进行美化
* Sugar这个词太好了,名词是糖的意思,动词就是美化
* 给你颗糖你还不美去
*/
public class SugarFouthGradeSchoolReport extends
FouthGradeSchoolReport {
//首先要定义你要美化的方法,先给老爸说学校最高成绩
private void reportHighScore(){
System.out.println("这次考试语文最高是75,数学是78,自然是80");
}
//在老爸看完毕成绩单后,我再汇报学校的排名情况
private void reportSort(){
System.out.println("我是排名第38名...");
}
您的设计模式
第 134 页
//由于汇报的内容已经发生变更,那所以要重写父类
@Override
public void report(){
this.reportHighScore(); //先说最高成绩
super.report(); //然后老爸看成绩单
this.reportSort(); //然后告诉老爸学习学校排名
}
}
然后Father 类稍做修改就可以看到美化后的成绩单,看代码如下:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 老爸看成绩单了
*/
public class Father {
public static void main(String[] args) {
//美化过的成绩单拿过来
SchoolReport sr= new SugarFouthGradeSchoolReport();
//看成绩单
sr.report();
//然后老爸,一看,很开心,就签名了
sr.sign("老三"); //我叫小三,老爸当然叫老三
}
}
运行结果如下:
这次考试语文最高是75,数学是78,自然是80
尊敬的XXX家长:
......
语文 62 数学65 体育 98 自然 63
.......
家长签名:
您的设计模式
第 135 页
我是排名第38名...
家长签名为:老三
通过继承确实能够解决这个问题,老爸看成绩单很开心,然后就给签字了,但是现实的情
况很复杂的,可能老爸听我汇报最高成绩后,就直接乐开花了,直接签名了,后面的排名就没必
要了,或者老爸要先听排名情况,那怎么办?继续扩展类?你能扩展多少个类?这还是一个比较
简单的场景,一旦需要装饰的条件非常的多,比如20 个,你还通过继承来解决,你想想的子类
有多少个?你是不是马上就要崩溃了!
好,你也看到通过继承情况确实出现了问题,类爆炸,类的数量激增,光写这些类不累死
你才怪,而且还要想想以后维护怎么办,谁愿意接收这么一大堆类的维护哪?并且在面向对象的
设计中,如果超过2 层继承,你就应该想想是不是出设计问题了,是不是应该重新找一条道了,
这是经验值,不是什么绝对的,继承层次越多你以后的维护成本越多,问题这么多,那怎么办?
好办,装饰模式出场来解决这些问题,我们先来看类图:
增加一个抽象类和两个实现类,其中Decorator 的作用是封装SchoolReport 类,看源
代码:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 装饰类,我要把我的成绩单装饰一下
您的设计模式
第 136 页
*/
public abstract class Decorator extends SchoolReport{
//首先我要知道是那个成绩单
private SchoolReport sr;
//构造函数,传递成绩单过来
public Decorator(SchoolReport sr){
this.sr = sr;
}
//成绩单还是要被看到的
public void report(){
this.sr.report();
}
//看完毕还是要签名的
public void sign(String name){
this.sr.sign(name);
}
}
Decorator 抽象类的目的很简单,就是要让子类来对封装SchoolReport 的子类,怎么
封装?重写report 方法!先看HighScoreDecorator 实现类:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 我要把我学校的最高成绩告诉老爸
*/
public class HighScoreDecorator extends Decorator {
//构造函数
public HighScoreDecorator(SchoolReport sr){
super(sr);
}
//我要汇报最高成绩
private void reportHighScore(){
您的设计模式
第 137 页
System.out.println("这次考试语文最高是75,数学是78,自然是80");
}
//最高成绩我要做老爸看成绩单前告诉他,否则等他一看,就抡起笤帚有揍我,我那
还有机会说呀
@Override
public void report(){
this.reportHighScore();
super.report();
}
}
重写了report 方法,先调用具体装饰类的装饰方法reportHighScore,然后再调用具
体构件的方法,我们再来看怎么回报学校排序情况SortDecorator 代码:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 学校排名的情况汇报
*/
public class SortDecorator extends Decorator {
//构造函数
public SortDecorator(SchoolReport sr){
super(sr);
}
//告诉老爸学校的排名情况
private void reportSort(){
System.out.println("我是排名第38名...");
}
//老爸看完成绩单后再告诉他,加强作用
@Override
public void report(){
super.report();
this.reportSort();
}
}
您的设计模式
第 138 页
然后看看我老爸怎么看成绩单的:
package com.cbf4life;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 老爸看成绩单了
*/
public class Father {
public static void main(String[] args) {
//成绩单拿过来
SchoolReport sr;
sr = new FouthGradeSchoolReport(); //原装的成绩单
//加了最高分说明的成绩单
sr = new HighScoreDecorator(sr);
//又加了成绩排名的说明
sr = new SortDecorator(sr);
//看成绩单
sr.report();
//然后老爸,一看,很开心,就签名了
sr.sign("老三"); //我叫小三,老爸当然叫老三
}
}
老爸一看成绩单,听我这么一说,非常开心,儿子有进步呀,从40 多名进步到30 多名,
进步很大,躲过了一顿海扁。
这就是装饰模式,装饰模式的通用类图如下:
您的设计模式
第 139 页
看类图,Component 是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最
原始的对象,比如上面的成绩单,记住在装饰模式中,必然有一个被提取出来最核心、最原
始、最基本的接口或抽象类,就是Component。
ConcreteComponent 这个事最核心、最原始、最基本的接口或抽象类的实现,你要装饰
的就是这个东东。
Decorator 一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定
有抽象的方法呀,在它的属性里必然有一个private 变量指向Component。
ConcreteDecoratorA 和ConcreteDecoratorB 是两个具体的装饰类,你要把你最核心的、
最原始的、最基本的东西装饰城啥东西,上面的例子就是把一个比较平庸的成绩单装饰成家
长认可的成绩单。
装饰模式是对继承的有力补充,你要知道继承可不是万能的,继承可以解决实际的问题,
但是在项目中你要考虑诸如易维护、易扩展、易复用等,而且在一些情况下(比如上面那个
成绩单例子)你要是用继承就会增加很多了类,而且灵活性非常的差,那当然维护也不容易
了,也就是说装饰模式可以替代继承,解决我们类膨胀的问题,你要知道继承是静态的给类
增加功能, 而装饰模式则是动态的给增加功能, 你看上面的那个例子, 我不想要
SortDecorator 这层的封装也很简单呀,直接在Father 中去掉就可以了,如果你用继承就
必须修改程序。
装饰模式还有一个非常好的优点,扩展性非常好,在一个项目中,你会有非常多因素考
虑不到,特别是业务的变更,时不时的冒出一个需求,特别是提出一个令项目大量延迟的需
求时候,那种心情是…,真想骂娘!装饰模式可以给我们很好的帮助,通过装饰模式重新封
您的设计模式
第 140 页
装一个类,而不是通过继承来完成,简单点说,三个继承关系Father,Son,GrandSon 三个类,
我要再Son 类上增强一些功能怎么办?我想你会坚决的顶回去!不允许,对了,为什么呢?
你增强的功能是修改Son 类中的方法吗?增加方法吗 ?对GrandSon 的影响哪?特别是
GrandSon 有多个的情况,你怎么办?这个评估的工作量就是够你受的,所以这个是不允许
的,那还是要解决问题的呀,怎么办?通过建立SonDecorator 类来修饰Son,等于说是创
建了一个新的类,这个对原有程序没有变更,通过扩充很好的完成了这次变更。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值