装饰器模式-原理分析以及动手练习

发布于:2024-05-07 ⋅ 阅读:(32) ⋅ 点赞:(0)

应用场景

  • 需要给一个现有类添加附加功能,但由于某些原因不能使用继承来生成子类进行扩充时,可以使用装饰模式。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时,可以使用装饰模式。

涉及的角色和类(个人理解)

  • 简单来说是两类角色:Source(Component)Decorator,即 被装饰者(原类)装饰者
  • 从类实现分析:
    • 由于 被装饰者装饰者 需要实现同样的方法,需要定义一个抽象接口。
    • 为便于区分,被装饰者抽象接口叫 Component,具体的被装饰者叫 ConcreteComponent
    • 考虑到可能有多个具体的装饰器,需要一个抽象类装饰器叫 Decorator,它的多个具体实现类分别叫 AConcreteDecorator, BConcreteDecorator
      在这里插入图片描述

涉及的角色组件(标准)

  • 被装饰组件接口:Component
  • 具体的被装饰组件实现类:AConcreteComponent, BConcreteComponent
  • 装饰器抽象类:Decorator
  • 具体的被装饰器实现类:AConcreteDecorator, BConcreteDecorator

基本实现 Demo(可以直接 copy 跑一下看效果)

  • Demo,有一个 图形Shape 被装饰接口,有 两个被装饰者的具体实现 Circle, Rectangle,有两个装饰器,分别用来 给图形设置绿色给图形设置红色
  • 在本地创建一个java类 DecoratorTest02,然后 copy 一下代码,直接跑
/**
 * 装饰器模式要实现的类
 * Component
 * AConcreteComponent
 * BConcreteComponent
 * Decorator
 * AConcreteDecorator
 * BConcreteDecorator
 */

// 1. 实现 被装饰器组件 操作
// Component
interface Shape {
    void draw();
}

// 2. 实现 被装饰器组件 的具体实现类
// AConcreteComponent
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

// BConcreteComponent
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个方形");
    }
}

// 3. 实现 装饰器
// Decorator
abstract class Decorator implements Shape {
    // 使用 protected,便于子类访问
    protected Shape shape;

    public Decorator(Shape shape) {
        this.shape = shape;
    }

    @Override
    public void draw() {
        shape.draw();
    }

}

// 4. 实现 具体功能的 装饰器
// AConcreteDecorator
class RedDecorator extends Decorator {

    public RedDecorator(Shape shape) {
        super(shape);
    }

    @Override
    public void draw() {
        // 可以在原功能之前增加功能
        // 调用原方法
        shape.draw();
        // 可以在原功能之后增加功能
        setRed(shape);
    }

    // 装饰器功能:设置红色
    public void setRed(Shape shape) {
        System.out.println("设置红色");
    }
}

// BConcreteDecorator
class GreenDecorator extends Decorator {

    public GreenDecorator(Shape shape) {
        super(shape);
    }

    @Override
    public void draw() {
        shape.draw();
        setRed(shape);
    }

    // 装饰器功能:设置绿色
    public void setRed(Shape shape) {
        System.out.println("设置绿色");
    }
}

// 5. 在客户端中使用 装饰器
public class DecoratorTest02 {
    public static void main(String[] args) {
        // 1. 标准的使用过程,画一个 圆,红色的
        // 创建一个 被装饰器组件圆
        Circle circle = new Circle();
        // 创建一个 具体的装饰器红色
        RedDecorator redDecorator = new RedDecorator(circle);
        // 执行方法
        redDecorator.draw();

        // 2. 画一个 方形,红色的
        new RedDecorator(new Rectangle()).draw();

        // 3. 画一个 方形,绿色的
        new GreenDecorator(new Rectangle()).draw();

        // 总结 可以看出,使用装饰器,可以对原来的类 动态添加、删除装饰功能
    }
}

自己动手实战

需求

小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。

请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。

要求:可以制作 加牛奶的黑咖啡,加糖的黑咖啡,加糖的拿铁咖啡

原练习题链接

参考答案

// Component: 被装饰者接口
interface Coffee {
    void createCoffee();
}

// AConcreteComponent: 被装饰者的具体实现类 黑咖啡
class BlackCoffee implements Coffee {
    @Override
    public void createCoffee() {
        System.out.println("create black coffee");
    }
}

// BConcreteComponent: 被装饰者的具体实现类 拿铁咖啡
class Latte implements Coffee {
    @Override
    public void createCoffee() {
        System.out.println("create latte coffee");
    }
}


// Decorator: 装饰器抽象类
abstract class Decorator implements Coffee {
    // 让子类可以访问到 被装饰者
    protected Coffee coffee;

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

    @Override
    public void createCoffee() {
        coffee.createCoffee();
    }
}

// AConcreteDecorator: 装饰器具体实现类 加牛奶装饰
class MilkDecorator extends Decorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public void createCoffee() {
        // 在原方法之前 做装饰
        washCup();
        // 执行原方法
        coffee.createCoffee();
        // 在原方法之后做装饰
        addMilk(coffee);
    }

    // 装饰功能:洗杯子
    public void washCup() {
        System.out.println("洗杯子");
    }

    // 装饰功能:加牛奶
    public void addMilk(Coffee coffee) {
        System.out.println("加入牛奶");
    }
}

// BConcreteDecorator: 装饰器具体实现类 加糖装饰
class SugarDecorator extends Decorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public void createCoffee() {
        coffee.createCoffee();
        addSugar(coffee);
    }

    public void addSugar(Coffee coffee) {
        System.out.println("加入一些糖");
    }
}

public class DecoratorTest01 {
    public static void main(String[] args) {
        BlackCoffee blackCoffee = new BlackCoffee();
        SugarDecorator sugarDecorator = new SugarDecorator(blackCoffee);
        sugarDecorator.createCoffee();
    }
}

相关话题

  • Java IO 流中如何应用的装饰器模式
  • 什么时候可以考虑使用装饰器模式
  • 能徒手写一个装饰器模式的demo吗

参考文章

  • https://github.com/youngyangyang04/kama-DesignPattern/blob/main/DesignPattern/8-%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F.md
  • https://www.runoob.com/design-pattern/decorator-pattern.html
  • https://pdai.tech/md/java/io/java-io-basic-design-pattern.html
  • https://kamacoder.com/problempage.php?pid=1086