类结构

图片说明

UML类图

图片说明

初步理解

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。本例中,原本只能画圈圈,但是装饰器对现有对象进行了装饰,我们可以画出有颜色的圈圈了。

代码理解

基础接口

public interface Shape {
    void draw();
}

基础的接口实现类(2个)

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("只能画个圈圈");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("只能画个框框");
    }
}

进行扩展的装饰类

可以看到,这个抽象类实现了Shape接口,根据传入的参数决定画哪个东西,这个也是多态的体现。

public abstract class ShapeDecorator implements Shape {
    public Shape decoratedShape;

    //构造函数,给Shape属性赋值
    public ShapeDecorator(Shape decoratedShape){
        this.decoratedShape = decoratedShape;
    }

    public void draw(){
        decoratedShape.draw();
    }
}

装饰类的具体实现

抽象类里面是有方法没有实现的,因此还需要实现。
构造函数与父类的其它成员(成员变量和成员方法)不同,它不能被子类继承。因此,在创建子类对象时,为了初始化从父类中继承来的成员变量,编译器需要调用其父类的构造函数。如果子类的构造函数没有显示地调用父类的构造函数,则默认调用父类的无参构造函数。但这里需要传参数,因此需要写一个显示的构造函数,里面调用父类的构造函数。

public class RedShapeDecorator extends ShapeDecorator {

    //构造函数
    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }
    //扩展的新功能。
    private void setRedBorder(Shape decoratedShape){
        System.out.println("现在可以染红:"+decoratedShape);
    }
}

出于省事的目的,这里没有重写toString方法。

测试主方法

下面的示例中,有4行加了注释,这是多态的体现。任意两行选出来都能运行。因为核心的装饰功能,在RedShapeDecorator类中,得到了实现。

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

        Shape circle = new Circle();
        ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
        ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
//        Shape redCircle = new RedShapeDecorator(new Circle());
//        Shape redRectangle = new RedShapeDecorator(new Rectangle());
//        RedShapeDecorator redCircle = new RedShapeDecorator(new Circle());
//        RedShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
        System.out.println("看我接下来画什么:");
        circle.draw();
        System.out.println();

        System.out.println("功能提升:");
        redCircle.draw();
        System.out.println();

        System.out.println("功能提升:");
        redRectangle.draw();
    }
}

运行结果:

看我接下来画什么:
只能画个圈圈

功能提升:
只能画个圈圈
现在可以染红:_2004装饰者模式.Circle@1b6d3586

功能提升:
只能画个框框
现在可以染红:_2004装饰者模式.Rectangle@4554617c

理解与总结:

  • 一般的,我们为了扩展一个类经常使用继承方式实现,但是随着扩展功能的增多,子类会很膨胀,类的种类比较多。
  • 为了解决这个问题,我们这里并没有选择扩展一个可以画红色圈圈的类,以及一个可以画红色框框的类,而是只使用了一个装饰类,就完成了上面可能用两个类才能完成的扩展,减少了类的种类。通过这个装饰的类,传入某个参数,就可以去调用具体某个类的draw方法,然后这个装饰的类内部进行了相应的功能扩展。