设计模式-装饰模式

装饰模式在中国的使用那实在是多,说话办事都不能太直接,都需要装饰一下。以小时候成绩单需要签名来举例:
先看这个成绩单的类图:
这里写图片描述
成绩单的抽象类,然后有一个四年级的成绩单实现类,先看抽象类:

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 成绩单的抽象类
 */

public abstract class SchoolReport {

    //成绩单的主要展示的就是你的成绩情况
    public abstract void report();

    //成绩单要家长签字
    public abstract void sign(String name);

}

然后我们的实现类FouthGradSchoolReport:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 */

public class FouthGradeSchoolReport extends SchoolReport {

    //我的成绩单
    @Override
    public void report() {
        //成绩单的格式是这个样子的
        Log.e("xyz","尊敬的xxx家长:");
        Log.e("xyz","。。。");
        Log.e("xyz","语文 62 数学 65 体育 98 自然 63 思想品德 100");
        Log.e("xyz","......");
        Log.e("xyz","   家长签名:  ");
    }

    //家长签字
    public void sign(String name) {
        Log.e("xyz","家长签名为 : "+name);
    }
}

成绩单出来,怎么找,那我把这个成绩单给老爸看看?好,我们修改一下类图,成绩单给老爸看:
这里写图片描述

老爸开始看成绩单,这个成绩单可是最真实的,啥都没有动过,原装,看Father类:

private void Father() {
        //成绩单拿过来
        SchoolReport sr = new FouthGradeSchoolReport();
        //看成绩单
        sr.report();
        //签名?不可能的,揍一顿再说

还好这不是真实情况,我没有直接把成绩单交给老爸,而是再交给他之前做了点技术处理,我要把成绩单封装一下,封装分为两步走:
第一步:跟老爸说各个科目的最高分,我这个还是能够接受的
第二部:在老爸看完成绩单后,告诉他我是排名前三十,其实一共就三十几个人。
那修饰是说完了,我们看看类图如何修改:
这里写图片描述
这是我最容易想到的类图,通过直接增加一个字类,重写report方法,很容易的解决了这个问题,是不是这样?是的,确实是一个很好的办法,我们来看具体的实现

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 */

public class SugarFouthGradeSchoolReport extends FouthGradeSchoolReport {

    //首先要定义你要美化的方法,先给老爸说是学校最高成绩
    private void reportHighScore(){
        Log.e("xyz"," 这次考语文最高是75,数学是78,自然是80 ");
    }

    //在老爸看完毕业成绩单后,我再汇报学校的排名情况
    private void reportSort(){
        Log.e("xyz","我是排名第30名...");
    }

    //由于汇报的内容已经发生变更,那所以要重写父类


    @Override
    public void report() {
        this.reportHighScore();//先说最高成绩
        super.report();//然后老爸看成绩
        this.reportSort();//然后告诉老爸学校排名
    }
}

然后Father类稍微修改就可以看到美化后的成绩单,代码如下:

    private void Father() {

        //美化过的成绩单拿过来
        SchoolReport sr = new SugarFouthGradeSchoolReport();

        //看成绩单
        sr.report();

        //然后老爸,一看,很开心,就签名了
        sr.sign("老徐");

通过继承确实能够解决这个问题,老爸看成绩很开心,然后就给签字了,但是现实的情况很复杂的,可能老爸听我汇报最高成绩后,直接乐坏了,直接签名了,后面的排名就没必要了,或者老爸要先听排名情况,怎么办?继续扩展类?你能扩展多少个类?这还是一个比较简单的场景,一旦装饰的条件非常多,比如20个甚至更多,你还通过继承来解决,你想想子类有多少个?想想都要疯了
好,看到这里,我们发现通过继承出现了问题,类爆炸,还要想想以后维护怎么办?并且在面向对象的设计中,如果超过2层继承,你就应该想想是不是设计出现问题了,继承层次越多你以后维护的成本就越多,问题这么多,那怎么办?好办,装饰模式来解决这些问题,我们先来看类图:
这里写图片描述
增加一个抽象类和两个实现类,其中Decorator的作用是封装SchoolReport类,看代码:

package com.example.xpeng.myapplication;

/**
 * Created by xpeng on 2018/6/2.
 * 装饰类,我要把成绩单装饰一下
 */

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

}

Decorate抽象类的目的很简单,就是让子类来封装SchoolReport的子类,怎么封装?重写report方法!先看HighScoreDecorate实现类:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 * 我要把我学校的最高成绩告诉老爸
 */

public class HighScoreDecorator extends Decorator {
    //构造函数
    public HighScoreDecorator(SchoolReport sr) {
        super(sr);
    }

    //我要汇报最高成绩
    private void reportHighScore(){
        Log.e("xyz","这次语文最高是75,数学是78,自然是80");
    }

    //最高成绩我要在老爸看成绩单前告诉他,否则等他一看,都歇菜了
    @Override
    public void report() {
        this.reportHighScore();
        super.report();
    }
}

重写了report方法,先调用具体装饰类的装饰方法reportHighScore,然后再调用具体构建的方法,我们再来看在呢么汇报学校排序情况ScorDecorate代码:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/6/2.
 * 学校排名的情况汇报
 */

public class SortDecorator extends Decorator {
    //构造函数
    public SortDecorator(SchoolReport sr) {
        super(sr);
    }

    //告诉老爸学校的排名情况
    private void reportDort(){
        Log.e("xyz"," 我是排名30名。。。 ");
    }

    @Override
    public void report() {
        super.report();
        this.reportDort();
    }
}

然后看老爸怎么看成绩单的:

    private void Father() {


        SchoolReport sr;
        sr = new FouthGradeSchoolReport();//原装的成绩单

        //加了最高分说明的成绩单
        sr = new HighScoreDecorator(sr);

        //又加了成绩排名的说明
        sr = new SortDecorator(sr);

        //看成绩
        sr.report();

        //签名咯
        sr.sign("老徐");
    }

这就是装饰模式,装饰模式的通用类图如下:
这里写图片描述
看类图,Component是一个接口或者抽象类,就是定义我们最核心的对象,也就是最原始的对象,比如上面的成绩单,记住装饰模式中,必然有一个被提出来最核心、最原始、最基本的接口或抽象类,就是Component
ConcreteComponent这个是最核心、最原始、最基本的接口或抽象类的实现,你要装饰的就是这个东东
Decorator一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象方法呀,在它的属性里必然有一个private变量指向Component
ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成啥东西,上面的例子就是把一个比较平庸的成绩单装饰成家长认可的成绩单。
装饰模式是对继承的有利补充,你要知道继承不是万能的。一些情况下,装饰模式可以替代继承,解决我们类膨胀的问题,我不想要SortDecorator这层的封装也很简单啊,直接在Father中去掉就可以,如果你用继承就必须修改程序。
装饰还有一个非常好的优点,扩展性非常好,在一个项目中,你会有非常多因素考虑不到,特别是业务的变更,是不是冒出一个需求,所以通过装饰类来修改继承类,等于说是创建了一个新的类,这个对原有程序没有变更,通过扩充很好的完成了这次变更。

装饰模式DEMO下载地址:

装饰模式demo下载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值