Java设计模式--装饰模式

本文通过一个具体例子解释了装饰模式的概念及应用,展示了如何通过装饰模式避免类爆炸问题,并降低了类间的耦合性。

装饰模式【Decorator Pattern】
装饰模式顾名思义就是将程序装饰进行装饰完成我们所想要的效果。山寨手机需要装饰,我们的程序有时候也需要进行装饰。
下面以向家长汇报分数让家长签字为例。先看下最初的类图。

这里写图片描述

倘若这样子直接拿给老爸看(直接汇报成绩,要签名),那岂不是要挨板子。对于差生来讲,还得先装饰一下好。
下面再看一下改善后的类图。

这里写图片描述

这样子设计的话,就可以在report()方法中做点手脚了,可以先汇报一下最高分,毕竟老子跟最高分差了10来分而已。然后可以报告一下排名,毕竟全班60人我考了38,(其实已经退学了快20人了)。

程序设计如下:

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(); //然后告诉老爸学习学校排名
    }
}

这样老爸看到的成绩单已经是美化过的了:

public class Father {
public static void main(String[] args) {
    //美化过的成绩单拿过来
    SchoolReport sr= new SugarFouthGradeSchoolReport();
    //看成绩单
    sr.report();
    //然后老爸,一看,很开心,就签名了
    sr.sign("老三"); //我叫小三,老爸当然叫老三
}

上面的例子通过继承来解决这个问题,通过继承只实现装饰最高分这一项,倘若我们要装饰得条件很多,那就会出问题了,出现类爆炸的情况。想想维护起来的成本。。。
我们还得好好装饰一下,先看改善后的类图:

这里写图片描述

增加一个抽象类和两个实现类,其中 Decorator 的作用是封装 SchoolReport 类。

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 进行封装。看下这么封装:

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();
    }
}
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();
    }
}

上面两个子类重写了report方法,达到了想要的结果。

老爸看成绩单:

    SchoolReport sr;
    sr = new FouthGradeSchoolReport(); //原装的成绩单
    //加了最高分说明的成绩单
    sr = new HighScoreDecorator(sr);
    //又加了成绩排名的说明
    sr = new SortDecorator(sr);
    //看成绩单
    sr.report();
    //然后老爸,一看,很开心,就签名了
    sr.sign("老三"); //我叫小三,老爸当然叫老三

通过这样的装饰模式就躲过了一顿海扁。

下面再看看其通用类图。

这里写图片描述

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

ConcreteComponent 这个事最核心、 最原始、 最基本的接口或抽象类的实现, 你要装饰的的对象。

Decorator 一般是一个抽象类,实现接口或者抽象方法。

ConcreteDecoratorA 和 ConcreteDecoratorB 是两个具体的装饰类。

总结:
(1)装饰者模式的存在,解决的问题主要就是继承带来的弊端,首先可能带来的类是上面所说的类爆炸的问题。同时继承的话由于子类必须继承父类的方法,所以当中间类的方法改变时,那么就会牵一发动全身了,利用装饰模式就可以将其进行分离,降低其耦合性,方便程序的扩展。

(2)继承与装饰模式的选取:选择继承还是装饰模式时主要考虑类之间的继承层数问题,如果只是一层,那可以考虑继承,如果出现多层继承的情况,那就应该考虑装饰模式了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值