小易说IT 小易说IT

Java 装饰器模式(Decorator)示例代码

装饰器模式:动态给对象增加额外职责,不修改原有类代码,通过包装原有对象实现功能增强,Java IO 就是典型装饰器模式。

核心角色:

  1. 抽象组件 (Component):定义被装饰对象和装饰器共同接口

  2. 具体组件 (ConcreteComponent):原始被装饰对象

  3. 抽象装饰器 (Decorator):持有组件引用,实现组件接口,包装原始对象

  4. 具体装饰器 (ConcreteDecorator):扩展额外功能

完整示例代码

// 1.抽象组件:咖啡接口
interface Coffee {
    // 获取描述
    String getDescription();
    // 获取价格
    double cost();
}

// 2.具体组件:基础黑咖啡(被装饰的原始对象)
class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "黑咖啡";
    }

    @Override
    public double cost() {
        return 10.0;
    }
}

// 3.抽象装饰器:咖啡装饰器,必须实现Coffee,持有Coffee成员
abstract class CoffeeDecorator implements Coffee {
    // 持有被装饰对象
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

// 4.具体装饰器1:加牛奶
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " +牛奶";
    }

    @Override
    public double cost() {
        return coffee.cost() + 2.5;
    }
}

// 具体装饰器2:加糖
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " +糖";
    }

    @Override
    public double cost() {
        return coffee.cost() + 1.0;
    }
}

// 具体装饰器3:加奶泡
class FoamDecorator extends CoffeeDecorator {
    public FoamDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " +奶泡";
    }

    @Override
    public double cost() {
        return coffee.cost() + 3.0;
    }
}

// 测试客户端
public class DecoratorDemo {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + ",价格:" + coffee.cost());

        // 动态加牛奶
        Coffee milkCoffee = new MilkDecorator(coffee);
        System.out.println(milkCoffee.getDescription() + ",价格:" + milkCoffee.cost());

        // 继续叠加:黑咖啡+牛奶+糖
        Coffee milkSugarCoffee = new SugarDecorator(milkCoffee);
        System.out.println(milkSugarCoffee.getDescription() + ",价格:" + milkSugarCoffee.cost());

        // 多重装饰:黑咖啡+牛奶+糖+奶泡
        Coffee fullCoffee = new FoamDecorator(new SugarDecorator(new MilkDecorator(new SimpleCoffee())));
        System.out.println(fullCoffee.getDescription() + ",价格:" + fullCoffee.cost());
    }
}

输出结果

黑咖啡,价格:10.0
黑咖啡 +牛奶,价格:12.5
黑咖啡 +牛奶 +糖,价格:13.5
黑咖啡 +牛奶 +糖 +奶泡,价格:16.5

关键点说明

  1. 装饰器和被装饰对象实现同一个接口,保证可以互相替换;

  2. 抽象装饰器持有组件对象,把请求委托给原始对象,再叠加自己逻辑;

  3. 可以无限嵌套装饰,动态组合功能,不用写大量继承子类;

  4. 和继承区别:继承是静态编译期扩展;装饰器是运行时动态包装对象

Java 原生 IO 中的装饰器对照

// FileInputStream:原始组件
FileInputStream fis = new FileInputStream("test.txt");
// BufferedInputStream:装饰器,增加缓冲功能
BufferedInputStream bis = new BufferedInputStream(fis);
  • FileInputStream → ConcreteComponent

  • FilterInputStream → 抽象 Decorator

  • BufferedInputStream / DataInputStream → 具体 Decorator

优缺点

✅ 优点

  • 比继承更灵活,运行时动态增删功能

  • 遵循开闭原则,新增装饰不需要修改原有代码

❌ 缺点

  • 会产生很多小的装饰器类,增加代码复杂度

  • 对象多层包装,调试稍微麻烦


本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。

原文链接 https://yijunzhao.cc/archives/java-decorator-pattern-example-code

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/