2

什么是装饰者模式?

装饰者模式属于结构型设计模式之一,主要目的是通过包装对象而不是继承来扩展功能。这种模式允许用户动态地为对象添加新的行为而无需修改其源代码。这与继承相比提供了一种更为灵活的方式来扩展功能。

装饰者模式的关键组成部分:

抽象组件(Component):定义核心业务接口。
具体组件(ConcreteComponent):核心业务实现类,实现了抽象组件接口。
装饰器(Decorator):持有抽象组件的引用,实现抽象组件接口,用来扩展功能。

适用场景

想增强现有类的功能,但又不想改变这个类的原有代码。
想无需修改原有代码的情况下即可使用对象。
通过继承来扩展对象行为的方案难以实现或者根本不可行。

实践

下面是一个基础的点餐功能。现在点餐的基础功能上新增,折扣、饮料两个功能。

基础服务

接口

public interface OrderService {
    double getPrice(); // 获取价格
    void placeOrder(); // 下单
}

实现类:

@Service
public class OrderServiceImpl implements OrderService {
    private final double price = 50.0; // 固定价格

    @Override
    public double getPrice() {
        return price;
    }

    @Override
    public void placeOrder() {
        System.out.println("单价: " + getPrice());
    }
}

扩展功能

我们将实现两个新功能:折扣和饮料。这两个功能将分别使用装饰者模式进行实现。

折扣装饰者

我们将创建一个折扣装饰者,允许在订单上应用折扣

public class DiscountDecorator implements OrderService {
    private final OrderService orderService; // 被装饰的对象
    private final double discount; // 折扣金额

    public DiscountDecorator(OrderService orderService, double discount) {
        this.orderService = orderService;
        this.discount = discount;
    }

    @Override
    public double getPrice() {
        return orderService.getPrice() - discount; // 返回折扣后的价格
    }

    @Override
    public void placeOrder() {
        orderService.placeOrder();
        System.out.println("折扣: " + discount);
    }
}

饮料服务接口和实现

添加一个饮料接口和其实现类,以支持饮料功能。

接口

public interface DrinkService {
    double getPrice(); // 获取饮料价格
}

实现类

@Service
public class DrinkServiceImpl implements DrinkService {
    private final double price = 0; // 初始化饮料价格

    @Override
    public double getPrice() {
        return price;
    }
}

饮料装饰者

public abstract class DrinkServiceDecorator implements DrinkService {
    protected DrinkService drinkService;

    public DrinkServiceDecorator(DrinkService drinkService) {
        this.drinkService = drinkService;
    }

    @Override
    public double getPrice() {
        return drinkService.getPrice();
    }

}

ColaDecorator.java 可乐类

public class ColaDecorator extends DrinkServiceDecorator {
    private final double additionalPrice = 5.0; // 可乐附加价格

    public ColaDecorator(DrinkService drinkService) {
        super(drinkService);
    }

    @Override
    public double getPrice() {
        return super.getPrice() + additionalPrice; // 添加可乐价格
    }

}

OrangeJuiceDecorator.java 橙汁类

public class OrangeJuiceDecorator extends DrinkServiceDecorator {
    private final double additionalPrice = 6.0; // 橙汁附加价格

    public OrangeJuiceDecorator(DrinkService drinkService) {
        super(drinkService);
    }

    @Override
    public double getPrice() {
        return super.getPrice() + additionalPrice; // 添加橙汁价格
    }

}

修改控制器以支持新功能

@RestController
public class OrderController {

    private OrderService orderService; //订单服务
    private DrinkService drinkService; // 饮料服务

    public OrderController(OrderService orderService, DrinkService drinkService) {
        this.orderService = orderService;
        this.drinkService = drinkService;
    }

    @GetMapping("/placeOrder")
    public String placeOrder(@RequestParam(value = "drinkType", required = false) String drinkType,
                             @RequestParam(value = "discount", required = false) Double discount) {
        double totalPrice = orderService.getPrice();

        // 处理饮料逻辑
        if ("cola".equalsIgnoreCase(drinkType)) {
            drinkService = new ColaDecorator(drinkService);
        } else if ("orange".equalsIgnoreCase(drinkType)) {
            drinkService = new OrangeJuiceDecorator(drinkService);
        }

        // 处理折扣逻辑
        if (discount != null) {
            orderService = new DiscountDecorator(orderService, discount);
        }

        totalPrice = drinkService.getPrice() + orderService.getPrice();  // 计算折扣后的订单价格
        orderService.placeOrder();
        System.out.println("添加的饮料价格: " + drinkService.getPrice());
        return "总金额: + " + totalPrice;
    }
}

测试

基础功能

保证以前的功能不受影响:直接下单符合预期50

image.png

下单并同时添加可乐和折扣:

单价50,可乐5,折扣20,符合预期35

image.png

总结

装饰者模式比继承较为灵活,不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用。
继承:在编译时定义类的行为,任何新功能的添加都需要创建新的子类,一旦编译,类的行为就已经固定,无法在运行时更改。

参考

https://refactoringguru.cn/design-patterns/decorator


zZ_jie
396 声望8 粉丝

虚心接受问题,砥砺前行。