一.简介

普通班的学生在上课的时候是听课,而小班的学生在上课的之前会预习,下课之后会复习,他们相当于普通学生的加强版.我们可以选择使用继承来实现他们的关系,但是这并不复合继承的思想,超级班的学生并不是普通班的学生中的一员.

我们选择使用装饰器模式,使用一个新类,在这个类中引入我们需要加强的类(被装饰者),这样我们对它原先的方法进行重写.这样的好处在于我们并不需要维护复杂的继承关系.

二.结构


  • 被装饰对象:需要进行加强的类;它的功能不能满足我们现阶段的要求;
  • 抽象装饰器:在本类中引入被装饰者对象,一般使用构造方法的方式进行引入;
  • 公共抽象的接口:需要在面向接口的前提下才会有公共的抽象接口,如果没有这个接口,装饰器也可以实现,参考StringBuffer和String并没有实现同一个接口.而java中的io的装饰器都实现了同样的接口;
  • 具体装饰器:实现和添加具体的功能.



三.代码





版本一 使用类结构,面向类编程



使用最简单的两个类即可完成装饰器的思想,核心思想就是加强我们的原先的类的功能.但是这种方式不是面向接口的编程方式;使用类编程的弊端有很大,没有遵守规范的话,也没有能约束它的接口.



class Student {
    public void study() {
        System.out.println("上课");
    }
}

class SuperStudent {
    private Student student;

    public SuperStudent(Student student) {
        this.student = student;
    }
    public void study() {
        System.out.println("预习");
        student.study();
        System.out.println("复习");
    }
}

public class Client {
    public static void main(String[] args) {
        SuperStudent superStudent = new SuperStudent(new Student());
        superStudent.study();
    }
}
版本二 抽象公共接口



此版本使用统一抽象的接口,装饰者和被装饰者都继承了这个接口,客户端的学习成本和调用成本明显降低.



interface Student{
    void study();
}

class CommonStudent implements Student{

    @Override
    public void study() {
        System.out.println("上课.....");
    }
}

class SuperStudent implements Student{

    private Student student;

    public SuperStudent(Student student) {
        this.student = student;
    }

    @Override
    public void study() {
        System.out.println("预习");
        student.study();
        System.out.println("复习");
    }
}

public class Client {
    public static void main(String[] args) {

        SuperStudent superStudent = new SuperStudent(new CommonStudent());
        superStudent.study();

    }
}



版本三 提取抽象的装饰器



装饰者进一步进行了抽象,这样具体的装饰器可以选择继承装饰器.对代码又一次进行了优化,但是这种情况不是我们必须选择的,而我们一般最好的选择为版本二,除非我们已经确定了将会有很多的具体装饰器.不然我们没有理由去多写一个类,增加我们代码结构的复杂度.



interface Student{
    void study();
}

class CommonStudent implements Student {

    @Override
    public void study() {
        System.out.println("上课.....");
    }
}

abstract class DecoratorStudent implements Student{
    protected Student student;

    public DecoratorStudent(Student student) {
        this.student = student;
    }
}

// 超级学生
class SuperStudent extends DecoratorStudent {

    public SuperStudent(Student student) {
        super(student);
    }

    @Override
    public void study() {
        System.out.println("预习");
        student.study();
        System.out.println("复习");
    }
}

class BadStudent extends DecoratorStudent{

    public BadStudent(Student student) {
        super(student);
    }

    @Override
    public void study() {
        System.out.println("捣蛋");
        student.study();
    }
}


public class Client {
    public static void main(String[] args) {

        SuperStudent superStudent = new SuperStudent(new CommonStudent());
        superStudent.study();
        System.out.println("==================================================");
        BadStudent badStudent = new BadStudent(new CommonStudent());
        badStudent.study();

    }
}

四.特点



  • 不使用继承而是用组合的方式来对一个类进行添加和减少功能;
  • 易于扩展:这是在情况三的代码结构下,我们需要新添加一个具体的装饰器只需要继承抽象类即可,当然情况二需要添加装饰器也不是很复杂,只需要实现同样的接口即可;
  • 它与代理模式极其的相似,可以说在代码上基本无差异,但是在目的上他们不是一个意思,代理模式的目的是访问控制.所以名曰代理,而装饰器的目的是了加强对象的方法.
  • 简单实用:在我们经常使用的jdk中的api中就有大量的此模式,例如StringBuffer,BufferedRead.



五.总结



装饰器模式的使用不会很复杂,如果从目的上来说的话,我们很多时候可能都使用到了它,我们在一个类中引进一个新的类,对它的原先的方法进行调用,并且进行了一些其他的操作,这些操作可以看成加强原先类的动作.





六.参考文献



大话设计模式