Published on

装饰器模式之真假美猴王

Authors

本文以西游记中的“真假美猴王”为例,一起温习一下装饰器模式的使用场景及具体实现过程。

真假美猴王的故事就不讲了,就算我标题党了吧。 我们的目的是要把一个猴子类包装成孙悟空和六耳猕猴,但是不能改变猴子类本身的结构。 简单描述一下装饰过程:

  • 首先定义一个猴子接口类,猴子具有introduce()方法,用于让猴子嗞哩哇啦的说话介绍自己;
  • 定义一个普通的猴子类,实现猴子接口类,重载introduce()方法,介绍一下自己,例如:“我是个会说话的猴子!”;
  • 定义一个抽象类,实现猴子接口,作为抽象装饰器类,因为要装饰猴子,所以需要有一个接收猴子类的构造方法;
  • 定义具体的装饰器类,继承抽象装饰器类,实现具体的装饰方法,这里我们需要定义两个具体的装饰器类,一个是孙悟空装饰器,一个是六耳猕猴装饰器,在各自的类里增加展示自己技能的描述方法,例如“我会七十二变”等;

过程大概就上面这么几步,接着咱们就开始coding!

1、首先是定义一个猴子接口,泛代表各种猴类。IMonkey.java

public interface IMonkey{
    /**
     * 猴子自我介绍
    /*
    void introduce();
}

2、定义猴子实现类,表示一个普通的猴子。Monkey.java

public class Monkey implements IMonkey{
    @Override
    public void introduce(){
        System.out.print("我是一个会说话的猴子!");
    }
}

3、定义抽象装饰器类。AbstractMonkeyDecorator.java

public abstract class AbstractMonkeyDecorator implements IMonkey{
    protected IMonkey monkey;
    public AbstractMonkeyDecorator(IMonkey monkey){
        this.monkey = monkey;
    }

    @Override
    public void introduce(){
        monkey.introduce();
    }
}

4、定义具体的装饰类,用于将普通的猴子包装成孙悟空或六耳猕猴。

  • 先来一个孙悟空的装饰类SunWuKongDecorator.java
public class SunWuKongDecorator extends AbstractMonkeyDecorator{
    public SunWuKongDecorator(IMonkey monkey){
        super(monkey);
    }
    
    @Override
    public void introduce(){
        // 调用monkey自身的方法
        monkey.introduce();
        // 调用装饰方法
        decorate(monkey);
    }

    private void decorate(IMonkey monkey){
        System.out.print("我是美猴王,我会七十二变!");
        System.out.print("我师傅是大唐高僧!");
    }
}
  • 再来一个六耳猕猴的装饰类SixEarsMonkeyDecorator.java
public class SixEarsMonkeyDecorator extends AbstractMonkeyDecorator{
    public SixEarsMonkeyDecorator(IMonkey monkey){
        super(monkey);
    }
    
    @Override
    public void introduce(){
        // 调用monkey自身的方法
        monkey.introduce();
        // 调用装饰方法
        decorate(monkey);
    }

    // 具体的装饰方法实现逻辑
    private void decorate(IMonkey monkey){
        System.out.print("我才是美猴王,我会七十二变!");
        System.out.print("大唐高僧是我师傅!");
    }
}

5、测试程序

public static void main(String[] args){
    // 首先看看一个普通的猴子的自我介绍
    System.out.print("使用装饰器前的猴子:");
    Monkey monkey = new Monkey();
    monkey.introduce();

    System.out.println();

    // 使用孙悟空装饰器装饰猴子
    System.out.print("使用孙悟空装饰器装饰后的猴子:");
    SunWuKongDecorator swkDecorator = new SunWuKongDecorator(new Monkey());
    swkDecorator.introduce();

    System.out.println();

    // 使用六耳猕猴装饰器装饰猴子
    System.out.print("使用六耳猕猴装饰器装饰后的猴子:");
    SixEarsMonkeyDecorator semDecorator = new SixEarsMonkeyDecorator(new Monkey());
    semDecorator.introduce();
}

6、输出结果

使用装饰器前的猴子:我是一个会说话的猴子!
使用孙悟空装饰器装饰后的猴子:我是一个会说话的猴子!我是美猴王,我会七十二变!我师傅是大唐高僧!
使用六耳猕猴装饰器装饰后的猴子:我是一个会说话的猴子!我才是美猴王,我会七十二变!大唐高僧是我师傅!

总结:上面的例子中,我们并没有对Monkey类本身进行改造,而是采用装饰器包装的方式为Monkey增加了新的功能,这种方式可以动态的为实体类增加功能,比继承更灵活,且装饰类和被装饰类互不影响,可以各自扩展。