设计模式 -- 装饰器模式

261 阅读2分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

含义: 在不改变原有对象的基础上添加新的功能,与继承相比能够更加灵活地扩展对象的功能。

下面是具体的实现方式,拿 coffee 和 tea 中添加 milk 举例,分别被装饰成 latte 和 milky tea

创建一个接口

public interface Drink{
    void getName();
}

创建实现接口的实体类

public class Coffee implements Drink{
    @Override
    public void getName(){
        System.out.println("Drink: Coffee");
    }
}
​
public class Tea implements Drink{
    @Override
    public void getName(){
        System.out.println("Drink: Tea");
    }
}

创建装饰 Drink 的接口

public interface DrinkDecorator extends Drink{
    
    private Drink drink;
    
    public DrinkDecorator(Drink  drink){
        this.drink = drink;
    }
    
    @Override
    public void getName(){
        drink.getName();
    }
}

创建具体的装饰

public class MilkDecorator extends DrinkDecorator{
    
    public MilkDecorator(Drink  drink) {
        super(drink);
    }
    public void getName() {
        super.getName();
        setMilk();
    }
    public void setMilk() {
        System.out.println("setMilk");
    }
}

使用 MilkDecorator 来装饰 Drink 对象

public class DecoratorDemo {
   public static void main(String[] args) {
       
       System.out.println("drink latte");
       Drink latte = new MilkDecorator(new Coffee());
       latte.getName();
       
       System.out.println("drink milky tea");
       Drink milkyTea = new MilkDecorator(new Tea());
       milkyTea.getName();
   }
}

上面代码可以看出装饰器模式包含四个角色,抽象接口,具体事物,抽象装饰,具体装饰;但是并不是所有的装饰器模式都要有这四个角色。当只有一个具体事物时,可以让抽象装饰直接继承具体事务;当只有一个具体装饰时,可以让抽象装饰和具体装饰进行合并。

什么时候使用这一模式呢?

  • 采用继承的方式会产生大量的子类
  • 类不可以被继承
  • 动态的添加和删除对象的功能

装饰器模式的主要优点

  • 在不改变原有对象的情况下,可以动态的给一个对象添加功能,能够做到即插即用
  • 装饰器模式遵守设计模式原则的开闭原则

但是装饰器模式同样会增加许多的子类,过度的依赖装饰器模式也会增加程序的复杂性。

与代理模式的区别

装饰器模式的关注点在于给对象动态添加⽅法,⽽动态代理更注重对象的访问控制。动态代理通常会在代理类中创建被代理对象的实例,⽽装饰器模式会将装饰者作为构造⽅法的参数。