Stories

Detail Return Return

SpringBoot實踐設計模式———裝飾者模式 - Stories Detail

什麼是裝飾者模式?

裝飾者模式屬於結構型設計模式之一,主要目的是通過包裝對象而不是繼承來擴展功能。這種模式允許用户動態地為對象添加新的行為而無需修改其源代碼。這與繼承相比提供了一種更為靈活的方式來擴展功能。

裝飾者模式的關鍵組成部分:

抽象組件(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

user avatar zaotalk Avatar nihaojob Avatar kobe_fans_zxc Avatar zhaozixing Avatar leexiaohui1997 Avatar inslog Avatar Dream-new Avatar yuzhihui Avatar joe235 Avatar gaozhipeng Avatar shawn_5dd516205b8bd Avatar momeak9 Avatar
Favorites 56 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.