动态地给一个对象添加额外的职责,就扩展功能而言,装饰模式比生成子类更为灵活。
组件接口
public interface ICoffee {
void makeCoffee();
}
具体组件
public class OriginalCoffee implements ICoffee {
@Override
public void makeCoffee() {
System.out.print("原味咖啡 ");
}
}
抽象装饰者
public abstract class CoffeeDecorator implements ICoffee {
protected final ICoffee coffee;
public CoffeeDecorator(ICoffee coffee) {
this.coffee = coffee;
}
@Override
public void makeCoffee() {
coffee.makeCoffee();
}
}
具体装饰者
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(ICoffee coffee) {
super(coffee);
}
@Override
public void makeCoffee() {
super.makeCoffee();
addMilk();
}
private void addMilk() {
System.out.print("加奶 ");
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(ICoffee coffee) {
super(coffee);
}
@Override
public void makeCoffee() {
super.makeCoffee();
addSugar();
}
private void addSugar() {
System.out.print("加糖");
}
}
public class Client {
public static void main(String[] args) {
//原味咖啡
ICoffee coffee=new OriginalCoffee();
coffee.makeCoffee();
System.out.println();
//加奶的咖啡
coffee=new MilkDecorator(coffee);
coffee.makeCoffee();
System.out.println();
//先加奶后加糖的咖啡
coffee=new SugarDecorator(coffee);
coffee.makeCoffee();
}
}
原味咖啡
原味咖啡 加奶
原味咖啡 加奶 加糖
可以从客户端调用代码看出,装饰者模式的精髓在于动态的给对象增减功能。
当你你需要原味咖啡时那就生成原味咖啡的对象,而当你需要加奶咖啡时,仅仅需要将原味咖啡对象传递到加奶装饰者中去装饰一下就好了。如果你加了奶还想加糖,那就把加了奶的咖啡对象丢到加糖装饰者类中去装饰一下,一个先加奶后加糖的咖啡对象就出来了。 如果用继承实现就是排列组合,原味,加糖,加奶,先加糖后加奶,先加奶后加糖,如果再加蜂蜜…
一般认为代理模式侧重于使用代理类增强被代理对象的访问,而装饰者模式侧重于使用装饰者类来对被装饰对象的功能进行增减。 除了上面的区别,个人实践中还发现,装饰者模式主要是提供一组装饰者类,然后形成一个装饰者栈,来动态的对某一个对象不断加强,而代理一般不会使用多级代理.
关注点
打点日志,权限校验是不是都属于对代理对象的访问的控制