装饰者模式

简介

装饰者模式_第1张图片

从简介不难看出,装饰器模式主要的作用在于扩充原来类的功能。就好像HTML可以用来展示数据,CSS可以在展示数据的基础上,对数据进行美化。

一般我们想要扩充一个类的功能,可以使用继承的方式,也可以使用装饰器模式。下面我们分别使用两种方式来模拟HTML和CSS的关系。

代码示例

需求

新建一个接口,表示展示文字的功能

public interface IDisplayText {
    void displayText();
}

新建一个Span类,实现该接口,用来展示以一段文字

public class Span implements IDisplayText {
    @Override
    public void displayText() {
        System.out.println("this is a span");
    }
}

现在我们想要扩充Span类的功能,例如想要实现红色字体的效果。

使用继承实现

新建一个Span类的子类,重写displayText方法

public class RedSpan extends Span {
    @Override
    public void displayText() {
        System.out.println("style = 'color:red;'");
        super.displayText();
    }
}

这个时候,我们就可以使用装饰之后的span了

public class Document {
    public static void main(String[] args) {
        IDisplayText span = new Span();
        span.displayText();
        System.out.println("==========装饰之后=========");
        span = new RedSpan();
        span.displayText();
    }
}

运行结果:

this is a span
==========装饰之后=========
style = 'color:red;'
this is a span

但是,继承的缺点显而易见,由于Java单继承的特性,当我们继承了要扩展的类之后就不能继承其他的类,而且代码的耦合度比较高,这个时候使用装饰者模式是一个较好的选择。

使用装饰者模式

新建一个装饰者抽象类

public abstract class DisplayTextWrapper implements IDisplayText {
    private IDisplayText span;

    public DisplayTextWrapper(IDisplayText span) {
        this.span = span;
    }

    @Override
    public void displayText() {
        span.displayText();
    }
}

新建装饰类继承抽象类

public class RedDisplayTextWrapper extends DisplayTextWrapper {
    public RedDisplayTextWrapper(IDisplayText span) {
        super(span);
    }

    @Override
    public void displayText() {
        System.out.println("style = 'color:red;'");
        super.displayText();
    }
}

这个时候就可以使用装饰类对span进行装饰

public class Document {
    public static void main(String[] args) {
        IDisplayText span = new Span();
        span.displayText();
        System.out.println("==========装饰之后=========");
        span = new RedDisplayTextWrapper(span);
        span.displayText();
    }
}

运行结果:

this is a span
==========装饰之后=========
style = 'color:red;'
this is a span

UML类图:

装饰者模式_第2张图片

总结

优点

与继承相比,装饰者模式的灵活性比较高,就上面的RedDisplayTextWrapper装饰类而言,它可以装饰任意一个实现IDisplayText接口的类,而继承只能扩充Span的功能。

装饰模式是动态的给类增加功能,而继承是静态的给类增加功能。同时,装饰模式可以替代继承,解决我们类膨胀的问题。

缺点

装饰者模式的过度使用会产生越来越多的装饰类,使程序变得复杂。

应用场景

  • 对原有类功能的增强,例如 Java IO 操作中FileInputStream和BufferedInputStream
  • 动态的给一个类添加功能,这个功能以后可能会被删除
  • 项目需求变更,需要在原有功能的基础之上升级,但是又不希望改动原有的类

你可能感兴趣的:(设计模式(java))