设计模式——装饰器模式

170 阅读4分钟

一、概述

装饰器模式就是动态给一个对象添加一些额外的功能,比如一个客厅里面有茶几、沙发、电视柜这些固定的东西,但是太简单了,所以会加一副挂画,一些盆栽,一个书架等等装饰,加上装饰后就使得客厅更加温馨好看一些;人的身上也有很多装饰,比如穿的衣服鞋子领带,戴的眼镜耳环,头上的发卡这些都是为了让我们好看的装饰。使用装饰器模式相比用生成子类方式达到功能的扩充显得更为灵活。装饰模式的设计理念主要是以对客户端透明的方式动态扩展对象的功能,是继承关系的一个替代,而继承会使得产生大量的子类,这样代码很冗余,也增加系统的复杂性。

装饰器模式的重点也在于装饰二字,在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能,使得对象有锦上添花的效果。装饰器模式主要有4个角色:

  • 抽象组件角色(Component):即抽象的被装饰者,通常是一个抽象类或者一个接口,定义了一系列方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承该类或者实现该接口来实现特定的功能。
  • 具体组件角色(ConcreteComponent):抽象组件角色的子类,在抽象的方法中实现了具体的逻辑,此类就是被装饰的类。
  • 装饰角色(Decorator):它也是Component的子类,它是具体装饰角色共同实现的抽象类(也可以是接口),并且持有一个Component类型的对象引用,它的主要作用就是把客户端的调用委派到被装饰类。
  • 具体装饰角色(ConcreteDecorator):具体的装饰类,它是Decorator的子类,主要就是定义具体的装饰功能。

概念总是那么晦涩难懂,下面我们就用人的装饰来做具体的说明。

二、使用

首先定义一个抽象的人表示抽象组件的角色,里面包含跑步和吃东西的基本方法。

/**
 * 抽象的被装饰者——人
 */
public interface Person {

    String TAG = "XXX";

    //定义了2个基本的特征:吃饭、跑步
    void eat();
    void run();
}

再者定义具体的人——张三,表示需要被装饰的具体角色,它实现了这两个方法。

/**
 * 具体的被装饰着——张三
 */
public class ZhangSan implements Person {

    @Override
    public void eat() {
        Log.e(TAG, "吃饭");
    }

    @Override
    public void run() {
        Log.e(TAG, "跑步");
    }
}

然后就是抽象的装饰器角色,它也实现了Person接口,并且引用了抽象的Person对象。

/**
 * 抽象的装饰者
 */
public abstract class Decorator implements Person{

    private Person person;

    public Decorator(Person person){
        this.person = person;
    }

    @Override
    public void eat() {
        person.eat();
    }

    @Override
    public void run() {
        person.run();
    }
}

最后就是具体的装饰器角色,可以看到在重写的方法中添加了新的方法扩展。

/**
 * 具体的装饰器
 */
public class ConcreteDecorator extends Decorator {

    public ConcreteDecorator(Person person) {
        super(person);
    }

    @Override
    public void eat() {
        seaFood();
        super.eat();
        porridge();
    }

    @Override
    public void run() {
        jogging();
        super.run();
        runFast();
    }

    /**
     * 增加的装饰——慢跑
     */
    private void jogging(){
        Log.e(TAG, "跑步——慢跑");
    }

    /**
     * 增加的装饰——快跑
     */
    private void runFast(){
        Log.e(TAG, "跑步——快跑");
    }

    /**
     * 增加的装饰——吃海鲜
     */
    private void seaFood(){
        Log.e(TAG, "吃饭——海鲜大餐");
    }

    /**
     * 增加的装饰——喝粥
     */
    private void porridge(){
        Log.e(TAG, "吃饭——喝粥");
    }
}

最后,进行测试一下,打印输出如下图所示。

Person person = new ZhangSan();
Log.e(TAG, "装饰前-------------------------");
person.run();
person.eat();
Log.e(TAG, "装饰后-------------------------");
ConcreteDecorator concreteDecorator = new ConcreteDecorator(person);
concreteDecorator.eat();
concreteDecorator.run();

三、总结

综上所述,使用装饰者模式其实也是很简单的,不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能,其实就是创建了一个包装的对象。装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的组件。

github地址:github.com/leewell5717…

四、参考

Java装饰者模式(Decorator)

Android 装饰者模式