装饰者模式

在不改变原类文件以及不使用继承的情况下,动态地将责任附加到对象上,从而实现动态拓展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

举例说明

包含四个部分

  1. 抽象组件 —-> IDrink

  2. 具体组件 —-> Coffee

  3. 抽象装饰 —-> DrinkDecorator

  4. 具体装饰 —-> Milk, Ice

抽象主键 IDrink

public interface IDrink {
    double cost();
    String describe();
}

具体组件 Coffee

public class Coffee implements IDrink{
    @Override
    public double cost() {
        return 10;
    }

    @Override
    public String describe() {
        return "coffer";
    }
}

抽象装饰 DrinkDecorator

public abstract class DrinkDecorator implements IDrink {
    protected IDrink drink;

}

抽象装饰 Milk

public class Milk extends DrinkDecorator{

    public Milk(IDrink drink) {
        this.drink = drink;
    }


    @Override
    public double cost() {
        return 1 + this.drink.cost();
    }

    @Override
    public String describe() {
        return  this.drink.describe() + " with milk";
    }
}

说明:

主要使用类的组合来实现对于一个类进行动态的增加功能。具体组件和抽象装饰都实现了抽象组件,具体组件又是抽象组件的子类,当调用时,可以要修饰的对象传递给修饰类,这样就可以对抽象对类进行功能对增强。

使用动态代理对coffer类进行增强


public class CoffeeProxyFactory implements InvocationHandler {

    private Object target;

    public CoffeeProxyFactory(Object target) {
        this.target = target;
    }

    public Object getInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke;

        if ("describe".equals(method.getName())) {
            invoke = method.invoke(target, args);
            invoke += " with milk";
            return invoke;
        } else {
            invoke = method.invoke(target, args);
//            invoke = 1 + (Integer) invoke;
            return invoke;
        }

    }
}

测试

public class Test {
    public static void main(String[] args) {
        IDrink drink = new Coffee();
        drink = new Milk(drink);
        drink = new Ice(drink);
        System.out.println(drink.cost());
        System.out.println(drink.describe());

        System.out.println("+++++++++++++++");
        System.out.println("动态代理");
        System.out.println("+++++++++++++++");
        IDrink iDrink = new Coffee();
        IDrink drinkProxy =  (IDrink) new CoffeeProxyFactory(iDrink).getInstance();
        System.out.println(drinkProxy.cost());
        System.out.println(drinkProxy.describe());
    }
}

比较

  1. 装饰器模式可以在不增加新的装饰类的情况下对已有的功能进行组合而得到新的功能,但得修改客户端代码才能使用新的功能。动态代理则是增加一个新的类来实现功能,哪怕这个功能是对已有功能的组合,但可以不用修改客户端代码。a.增不增加新类。b.是否需要更改客户端代码

  2. 代理模式主要是控制对某个特定对象访问,而装饰模式主要是为了给对象添加行为。