设计模式

设计模式之禅-装饰模式

2020-12-26  本文已影响0人  凉快先生

1.业务背景

小学的时候考完试,试卷发下来要家长签字

2.成绩单类图

成绩单的抽象类

public abstract class SchoolReport {

    //成绩单的主要展示的就是你的成绩情况

    public abstract void report();

    //成绩单要家长签字,这个是最要命的

    public abstract void sign();

}

四年级的成绩单

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

    }

}

3.小学低于 90 分基本上就是中下等了,那我把这个成绩单给老爸看看?好,我们修改一下类图

老爸看成绩单了

public class Father {

    public static void main(String[] args) {

        //成绩单拿过来

        SchoolReport sr = new FouthGradeSchoolReport();

        //看成绩单

        sr.report();

        //签名?休想!

    }

}

运行结果如下:

尊敬的XXX家长:

......

语文 62 数学65 体育 98 自然 63

.......

家长签名:

4.这个不是当时的真实情况,我没有直接把成绩单交给老爸,而是在交给他之前做了点技术工作,我要把成绩单封装一下,封装分类两步走:

第一步:跟老爸说各个科目的最高分,语文最高是 75,数学是 78,自然是 80,然老爸觉的我成绩与最高分数相差不多

第二步:在老爸看成绩单后,告诉他我是排名第 38 名,全班,这个也是实情,为啥呢?有将近十个同学退学了!

对这个成绩单进行美化

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 类稍做修改

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名...

家长签名为:老三

5.通过继承确实能够解决这个问题,但是现实的情况很复杂的,可能老爸听我汇报最高成绩后,就直接乐开花了,直接签名了,后面的排名就没必要了,或者老爸要先听排名情况,那怎么办?继续扩展类?你能扩展多少个类?这还是一个比较简单的场景,一旦需要装饰的条件非常的多,比如20 个,你还通过继承来解决,你想想的子类有多少个?你是不是马上就要崩溃了!

装饰模式出场来解决这些问题

增加一个抽象类和两个实现类,其中 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);

    }

}

6.Decorator 抽象类的目的很简单,就是要让子类来对封装 SchoolReport 的子类,怎么封装?重写report 方法!先看 HighScoreDecorator 实现类:

我要把我学校的最高成绩告诉老爸

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

    }

}

老爸看成绩单

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("老三");

    }

}

7.装饰模式的通用类图

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

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

Decorator 一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方法呀,在它的属性里必然有一个 private 变量指向 Component。

ConcreteDecoratorA 和 ConcreteDecoratorB 是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰城啥东西,上面的例子就是把一个比较平庸的成绩单装饰成家长认可的成绩单。

装饰模式是对继承的有力补充,你要知道继承可不是万能的,继承可以解决实际的问题,但是在项目中你要考虑诸如易维护、易扩展、易复用等,而且在一些情况下(比如上面那个成绩单例子)你要是用继承就会增加很多了类,而且灵活性非常的差,那当然维护也不容易了,也就是说装饰模式可以替代继承,解决我们类膨胀的问题,你要知道继承是静态的给类增加功能,而装饰模式则是动态的给增加功能。

上一篇 下一篇

猜你喜欢

热点阅读