美文网首页随笔-生活工作点滴
23种设计模式-装饰模式

23种设计模式-装饰模式

作者: stayiwithime | 来源:发表于2019-07-16 19:46 被阅读4次
  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();
        //签名?休想,一顿胖揍
    }
}

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

  • 汇报最高成绩
    跟家长说各个科目的最高分,语文最高75,数学最高78,自然是80;那么家长一看你的成绩和最高分差不多,也还行;实际普遍在70以上,这个60多还是垫底
  • 汇报排名
    全班排第38名,但是不能说参加考试的只有40个人,反正成绩单上没写多少人,相比较之前的40多名还是有进步的,哈哈
    这就是加上了一些修饰,我们看看类图如何修改,如图17-3:


    17-3

    这应该是常规的处理方式了,直接增加一个子类,覆写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

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

  • Component抽象构件
    Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,如上面的成绩单。
    注意 在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当 Component抽象构件(这个抽象构件应该是描述我们想要装饰的部分
  • ConcreteComponent具体构件
    ConcreteComponent是最核心、最原始、最基本的接口或抽象类的实现,就是我们要装饰的类,就是对应的例子中的FouthGradeSchoolReport
    -Decorator装饰角色
    一般是一个抽象类,实现接口或抽象方法,在他的属性里必然有一个private变量指向Component抽象构件。(装饰者模式的核心,和被装饰者实现或继承相同抽象,然后私有属性指向被装饰者
    -具体装饰角色
    ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,这个就是用来装饰的了,想从哪个方面哪个角度去装饰,就实现Decorator去写自己的装饰方法就好了。
    我们来看一下装饰者模式的通用代码:
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装饰者模式的优点

  • 装饰类和被装饰类可以独立发展,而不会互相耦合。换句话说,Component类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构建。
  • 装饰者模式是继承模式的一个替代方案。我们看装饰类Decorator,不管装饰多少层,返回的对象还是Component,实现的还是is-a的关系。
  • 装饰模式可以动态地扩展一个实现类的功能,而且还不会影响到被扩展的类,非常符合开闭原则
    3.2装饰模式的缺点
    装饰者模式虽然可以很好的替代继承的方式处理问题,并且比继承更加灵活 ,但是也同样带来了和继承类似的问题,那就是装饰层数过多的问题,这个就只能灵活处理;
    3.3 装饰模式的使用场景
  • 需要扩展一个类的功能,或给一个类增加附加功能;
  • 需要动态地给一个对象增加功能,这些功能还可以动态的撤销;
  • 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式
  1. 最佳实践

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

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

相关文章

网友评论

    本文标题:23种设计模式-装饰模式

    本文链接:https://www.haomeiwen.com/subject/iyfehctx.html