`
vanadiumlin
  • 浏览: 504871 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

每日一计:装饰模式【Decorator Pattern】

阅读更多

Ladies and gentlemen,May I get your attention,Please?,Now I’m going to talk about decorator
pattern.装饰模式在中国使用的那实在是多,中国的文化是中庸文化,说话或做事情都不能太直接,需要
有技巧的,比如说话吧,你要批评一个人,你不能一上来就说你这个做的不对,那个做的不对,你要先肯
定他的成绩,表扬一下优点,然后再指出瑕疵,指出错误的地方,最后再来个激励,你修改了这些缺点后
有那些好处,比如你能带更多的小兵,到个小头目等等,否则你一上来就是一顿批评,你瞅瞅看,肯定是
不服气,顶撞甚至是直接“此处不养爷,自有养爷处”开溜哇。这是说话,那做事情也有很多,在山寨产
品流行之前,假货很是比较盛行的,我在2002年买了个手机,当时老板吹的是天花乱坠,承诺这个手机是
最新的,我看着也像,壳子是崭新的,包装是崭新的,没有任何瑕疵,就是比正品便宜了一大截,然后我
买了,缺钱哪,用来3个月,坏了,一送修,检查,说这是个新壳装旧机,我晕!拿一个旧手机的线路板,
找个新的外壳、屏幕、包装就成了新手机,装饰模式害人不浅呀!

我们不说不开心的事情,今天举一个什么例子呢?就说说我上小学的的糗事吧。我上小学的时候学习
成绩非常的差,班级上40多个同学,我基本上都是在排名45名以后,按照老师给我的定义就是“不是读
书的料”,但是我老爸管的很严格,明知道我不是这块料,还是往赶鸭子上架,每次考试完毕我都是战战兢
兢的,“竹笋炒肉”是肯定少不了的,能少点就少点吧,肉可是自己的呀。四年级期末考试考完,学校出来
个很损的招儿(这招儿现在很流行的),打印出成绩单,要家长签字,然后才能上五年级,我那个恐惧呀,
不过也就是几秒钟的时间,玩起来什么都忘记了。

我们先看看这个成绩单的类图:

图片

 

成绩单的抽象类,然后有一个四年级的成绩单实现类,先看抽象类:
 
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.



 * 四年级的成绩单,这个是我们学校第一次实施,以前没有干过
 * 这种“缺德”事。
 */
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类:

图片

 

 

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名,全班,这个也是实情,为啥呢?有将近十个同学退
学了!这个情况我是不说的。不知道是不是当时第一次发成绩单,学校没有考虑清楚,没有写上总共有多少同学,
排名第几名等等,反正是被我钻了个空子。
那修饰是说完了,我们看看类图如何修改:

 

图片

 

我想这是你最容易想到的类图,通过直接增加了一个子类,重写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名...");
 }
 
 //由于汇报的内容已经发生变更,那所以要重写父类
 @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
 .......
 家长签名:
我是排名第38名...
家长签名为:老三

 

通过继承确实能够解决这个问题,老爸看成绩单很开心,然后就给签字了,但是现实的情况很复杂的,可能
老爸听我汇报最高成绩后,就直接乐开花了,直接签名了,后面的排名就没必要了,或者老爸要先听排名情况,
那怎么办?继续扩展类?你能扩展多少个类?这还是一个比较简单的场景,一旦需要装饰的条件非常的多,比如
20个,你还通过继承来解决,你想想的子类有多少个?你是不是马上就要崩溃了!
好,你也看到通过继承情况确实出现了问题,类爆炸,类的数量激增,光写这些类不累死你才怪,而且还要
想想以后维护怎么办,谁愿意接收这么一大堆类的维护哪?并且在面向对象的设计中,如果超过2层继承,你就
应该想想是不是出设计问题了,是不是应该重新找一条道了,这是经验值,不是什么绝对的,继承层次越多你以
后的维护成本越多,问题这么多,那怎么办?好办,装饰模式出场来解决这些问题,我们先来看类图:

 

图片

增加一个抽象类和两个实现类,其中Decorator的作用是封装SchoolReport类,看源代码:
 
package com.cbf4life;
 
/**
 * @author cbf4Life cbf4life@126.com
 * I'm glad to share my knowledge with you all.
 * 装饰类,我要把我的成绩单装饰一下
 */
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(){
 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();
 }
}
 
然后看看我老爸怎么看成绩单的:
 
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多名,进步很大,
躲过了一顿海扁。
这就是装饰模式,装饰模式的通用类图如下:

图片

 

看类图,Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,比
如上面的成绩单,记住在装饰模式中,必然有一个被提取出来最核心、最原始、最基本的接口或抽象类,

就是Component。
ConcreteComponent这个事最核心、最原始、最基本的接口或抽象类的实现,你要装饰的就是这个东东。
Decorator一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方法呀,
在它的属性里必然有一个private变量指向Component。
ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,你要把你最核心的、最原始的、最
基本的东西装饰城啥东西,上面的例子就是把一个比较平庸的成绩单装饰成家长认可的成绩单。
装饰模式是对继承的有力补充,你要知道继承可不是万能的,继承可以解决实际的问题,但是在项目
中你要考虑诸如易维护、易扩展、易复用等,而且在一些情况下(比如上面那个成绩单例子)你要是用继
承就会增加很多了类,而且灵活性非常的差,那当然维护也不容易了,也就是说装饰模式可以替代继承,
解决我们类膨胀的问题,你要知道继承是静态的给类增加功能,而装饰模式则是动态的给增加功能,你看
上面的那个例子,我不想要SortDecorator这层的封装也很简单呀,直接在Father中去掉就可以了,如果
你用继承就必须修改程序。
装饰模式还有一个非常好的优点,扩展性非常好,在一个项目中,你会有非常多因素考虑不到,特别
是业务的变更,时不时的冒出一个需求,特别是提出一个令项目大量延迟的需求时候,那种心情是…,真
想骂娘!装饰模式可以给我们很好的帮助,通过装饰模式重新封装一个类,而不是通过继承来完成,简单
点说,三个继承关系Father,Son,GrandSon三个类,我要再Son类上增强一些功能怎么办?我想你会坚决
的顶回去!不允许,对了,为什么呢?你增强的功能是修改Son类中的方法吗?增加方法吗 ?对GrandSon
的影响哪?特别是GrandSon有多个的情况,你怎么办?这个评估的工作量就是够你受的,所以这个是不允
许的,那还是要解决问题的呀,怎么办?通过建立SonDecorator类来修饰Son,等于说是创建了一个新的
类,这个对原有程序没有变更,通过扩充很好的完成了这次变更。

分享到:
评论

相关推荐

    设计模式之装饰模式(Decorator Pattern)

    装饰模式(Decorator Pattern)是一种结构型设计模式,它在不改变原有对象的基础上,通过包裹一个对象并为其添加新的行为或责任,实现对对象功能的扩展。这种模式在软件开发中非常常见,尤其当需要在运行时动态改变...

    通过C#实现设计模式-装饰模式(DecoratorPattern).rar

    装饰模式(Decorator Pattern)是一种结构型设计模式,它允许你向一个现有的对象添加新的功能,同时又不改变其结构。装饰模式通过创建一个装饰类,该类包装了原始类的实例,并在调用原始类方法之前或之后添加额外的...

    装饰者模式(Decorator Pattern)原理图

    装饰者模式(Decorator Pattern)是一种结构型设计模式,它的定义是在不改变原有对象结构的基础上,动态地给该对象增加一些职责(即增加其额外功能)。这种模式允许向一个现有的对象添加新的功能,同时又不改变其...

    .NET设计模式(10):装饰模式(DecoratorPattern)

    在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质,使得这种扩展方式...[GOF《设计模式》]图1Decorator模式结构图装饰模式动态地给一个对象添加额外的职责。不论一幅画有没有画

    Head First 设计模式 (三) 装饰者模式(decorator pattern) C++实现

    装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许我们向对象添加新的行为或职责,而无需修改对象的原始代码。在C++中实现装饰者模式,可以让我们灵活地扩展对象的功能,同时保持代码的可读性和可维护性...

    DecoratorPattern.rar

    装饰器模式(Decorator Pattern)是一种设计模式,它允许在运行时动态地给对象添加新的行为或职责,而无需改变对象本身。在Java开发中,这种模式尤其有用,因为它提供了扩展对象功能的方式,同时保持了代码的灵活性...

    c++-设计模式之装饰模式(Decorator)

    装饰模式(Decorator Pattern)是一种结构型设计模式,允许在不改变对象接口的情况下,动态地为对象添加额外的职责或功能。装饰模式通常用于需要扩展对象功能而又不希望使用子类化的场景。 装饰模式的组成 组件接口...

    C#设计模式之Decorator 装饰模式

    装饰模式(Decorator Pattern)是设计模式中的一种结构型模式,它在不改变原有对象的基础上,通过添加额外的职责来扩展对象的功能。在C#中,装饰模式尤其适用于那些需要动态地增加或减少对象功能的情况,避免了使用...

    java Decorator装饰模式例子

    下面将详细探讨装饰模式的核心概念、结构、优点以及如何通过示例代码`decoratorDemo`来理解这一模式。 **装饰模式的核心概念** 1. **Component(组件)**: 这是所有具体组件和装饰器的共同接口或抽象类,定义了...

    设计模式C++学习之装饰模式(Decorator)

    装饰模式(Decorator)是软件设计领域中一种非常实用的结构型设计模式,它允许我们向一个对象添加新的行为或责任,而无需修改该对象的源代码。在C++编程语言中,装饰模式常用于动态地扩展类的功能,使得类的行为在...

    C#面向对象设计模式纵横谈(10):Decorator 装饰模式(结构型模式) (Level 300)

    装饰模式是一种结构型设计模式,它允许我们向一个对象添加新的功能或增强现有功能,而无需改变该对象的类。在C#中,装饰模式通常通过继承和组合来实现,它提供了一种灵活的方式来动态地改变对象的行为。在这个“C#...

    装饰器(Decorator)模式

    在《Element of Reusable Object-Oriented Software》中,GOF 对装饰器模式的用意进行了概述:Decorator Pattern――Attaches additional responsibilities to an object dynamically. Decorators provide a ...

    装饰者模式——Decorator

    在阅读这篇博客和解压后的“decorator”文件后,你可以深入理解装饰者模式的实现细节,学习如何在自己的项目中运用这一模式,以更优雅的方式扩展功能,同时避免过度使用继承导致的类爆炸问题。通过实践和理解装饰者...

    C#面向对象设计模式纵横谈(10):Decorator 装饰模式(结构型模式)

    其中,装饰模式(Decorator Pattern)作为结构型模式之一,在不改变现有对象的情况下为其添加新的功能。本文档通过一个具体的示例——游戏中的坦克,探讨了如何使用装饰模式来动态地增加对象的功能。 #### 二、问题...

    结构型模式之装饰模式(Decorator)

    装饰模式(Decorator)是软件设计模式中的一种结构型模式,其主要目的是在不改变对象原有类的基础上,通过添加新的行为或职责来扩展对象的功能。这种模式使得代码的扩展性非常优秀,避免了由于频繁地使用继承而导致...

    Decorator pattern

    装饰者模式是一种设计模式,属于结构型模式,它允许在运行时给对象添加新的行为或责任,而无需修改对象的源代码。这种模式的核心在于,它动态地将责任附加到对象上,通过将对象包裹在一个装饰类中来扩展其功能。在...

    PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

    装饰器模式(Decorator Pattern)是一种结构型设计模式,主要用于在运行时动态地给对象添加新的职责或行为,而不必改变现有对象的类定义。在面向对象编程中,装饰器模式提供了一种相对于继承更加灵活的方式来增强或...

    装饰器模式[Decorator]

    装饰器模式(Decorator)是一种设计模式,它允许在运行时向对象添加新的行为或责任,而无需修改对象的源代码。这种模式属于结构型模式,是面向对象设计中的一种非常实用的技术。 装饰器模式的核心思想是通过将一个...

    [结构型模式] head first 设计模式之装饰者模式(decorator)

    【标题】:“装饰者模式(decorator)在Head First设计模式中的详解” ...通过阅读`beverage.h`文件中的类定义,我们可以深入理解这个模式的实现细节,并在实际项目中应用这一模式来优化代码结构和提高可扩展性。

Global site tag (gtag.js) - Google Analytics