随笔-生活工作点滴

23种设计模式-装饰模式

2019-07-16  本文已影响4人  stayiwithime
  1. 罪恶的成绩单

考试成绩单以及成绩排名,大家都懂得,以前上学的时候,这玩意往家里寄是真的要命。成绩单还需要家长签字,那么,我们来模拟将成绩单给家长签字这一情景,如图17-1:


17-1

我们先来看成绩单的抽象类SchoolReport,代码如下:

public abstract class SchoolReport {
    //显示成绩情况
    public abstract void report();
    //要家长签字
    public abstract void sign();
}

有抽象类了,在来看看具体的四年级成绩单FouthGradeSchoolReport,代码如下:

public class FouthGradeSchoolReport extends SchoolReport {
    @Override
    public void report() {
        //成绩单的格式
        System.out.println("尊敬的xxx家长:");
        System.out.println("..............");
        System.out.println("语文 62 数学 65 体育 98 自然 63");
        System.out.println("..............:");
        System.out.println("家长签名:");
    }

    @Override
    public void sign(String name) {
        System.out.println("家长签名:" + name);
    }
}

成绩单出来62、65之类的在小学基本就是垫底,那么我们把成绩单带回去给家长看,修改一下类图,如图17-2:


17-2

这是原装的成绩单,没有动过的,来看Father类代码如下:

public class Father {
    public static void main(String[] args) {
        SchoolReport sc = new FouthGradeSchoolReport();
        //看成绩单
        sc.report();
        //签名?休想,一顿胖揍
    }
}

这个成绩直接拿出来肯定是找打,我们把成绩单封装一下,封装分为两步来实现:

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

通过继承确实能够解决这个问题,但是这个只能作为应急的一种方式,如果需要继续加装饰那怎么办,而且装饰条件不是一次就明确的,可能过一段时间加一个,那一直通过继承来处理肯定是不合理的。在面向对象的设计中,如果超过两层,是不是该考虑设计的问题了,这是经验,不是绝对,继承的层次越多以后的维护成本越多,那这么解决这个装饰的问题呢,我们专门定义一批负责装饰的类,然后根据实际情况来决定是否需要进行装饰,类图如17-4:


17-4

增加一个抽象类和两个实现类,其中Decorator的作用是封装SchoolReport类,如果大家还记得代理模式,那么很容易看懂这个类图,装饰类的作用也是一个特殊的代理类,真实的执行者还是被代理的角色FouthGradeSchoolReport,代码如下:

public abstract class Decorator extends SchoolReport {
    //首先得知道是哪个成绩单
    private SchoolReport schoolReport;
    public Decorator(SchoolReport schoolReport){
        this.schoolReport = schoolReport;
    }
    @Override
    public void report(){
        this.schoolReport.report();
    }
    @Override
    public void sign(String name){
        this.schoolReport.sign(name);
    }
}

装饰类还是把动作的执行委托给需要装饰的对象,Decorator抽象类的目的很简单,就是要让子类来封装SchoolReport的子类,先看HighScoreDecorator实现类,代码如下:

public class HighScoreDecorator extends Decorator {

    public HighScoreDecorator(SchoolReport schoolReport) {
        super(schoolReport);
    }
    private void reportHighScore(){
        System.out.println("这次考试语文最高是75,数学是78,自然是80");
    }

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

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

public class SortDecorator extends Decorator {
    public SortDecorator(SchoolReport schoolReport) {
        super(schoolReport);
    }
    private void reportSort(){
        System.out.println("我是排名第38名。。。");
    }
    @Override
    public void report(){
        super.report();
        this.reportSort();
    }
}

通过这两个强力的修饰工具,然后就可以拿一份"漂亮"的成绩单出来了,代码如下:

public class Client  {
    public static void main(String[] args) {
        SchoolReport schoolReport;
        schoolReport = new FouthGradeSchoolReport();
        schoolReport = new HighScoreDecorator(schoolReport);
        schoolReport = new SortDecorator(schoolReport);
        schoolReport.report();
        schoolReport.sign("老三");
    }
}

这就是装饰者模式,可以处理一些用继承来处理的问题,但是比继承更加的灵活,但是装饰过多层之后就不太友好了,就像继承过多之后可读性就变的很差了。

  1. 装饰者模式的定义

装饰模式(Decorator Pattern)是一种比较常见的模式,其定义如下:Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。)
类图17-5:


17-5

在类图中,有四个角色需要说明:

public abstract class Component {
    public abstract void operation();
}
public class ConcreateComponent extends Component {
    @Override
    public void operation() {
        //需要被装饰的方法
        System.out.println("do something");
    }
}
public class Decorator extends Component {
    private Component component;
    public Decorator(Component component){
        this.component = component;
    }
    @Override
    public void operation() {
        //委托给装饰者执行
        component.operation();
    }
}
public class ConcreteDecorator extends Decorator {

    public ConcreteDecorator(Component component) {
        super(component);
    }

    private void method(){
        //do something
    }

    @Override
    public void operation() {
        this.method();
        super.operation();
    }
}

(这个装饰者模式和代理模式非常相近,而且都是用来增强被装饰类(被代理类)的;但是这两者的具体的区别和用法又是怎么样的呢)

  1. 装饰者模式应用

3.1装饰者模式的优点

  1. 最佳实践

装饰模式是对继承的有力补充,而且装饰模式比继承更加的灵活,易维护,易扩展,衣服用;这个之前学习例子的时候就有很好的体会。
这里有一点就是装饰模式和代理模式的对比,这一章中并没有提出,有兴趣可以百度一下;我们学完23种设计模式后,会接着学后续的相似的设计模式之前的对比。

内容来自《设计模式之禅》

上一篇 下一篇

猜你喜欢

热点阅读