後端開發 設計模式 · 第 15 / 24 篇

命令模式:靈活封裝的請求指令

命令模式 (Command Pattern) 將請求封裝成物件,支援撤銷與排程。本文透過 C# 餐廳點餐範例,示範如何解耦請求發送者與執行者。

哈囉大家,今天我們來聊聊 命令模式(Command),這個設計模式能幫助你將請求封裝成物件,讓你可以輕鬆地操作、延遲或撤銷命令。

🌟 命令模式是什麼?

命令模式是一種將「動作」封裝成獨立物件的設計模式。這樣做的好處是,你可以隨時決定何時執行這個動作,甚至是取消它。

舉個例子來說,就像餐廳點餐時,你的每一份點餐單都是一個命令,廚房按照你的點餐單來做餐點,服務生只需將點餐單交給廚房即可,不需要知道廚房如何烹飪食物。


🤔 什麼情況適合使用命令模式?

  • 想要將執行動作的物件與觸發動作的物件解耦。
  • 需要將命令排程、延遲或撤銷。
  • 想記錄請求歷史,以支援撤銷操作。

🍔 C# 命令模式範例

這次我們以餐廳點餐的例子來實作命令模式。

📝 定義命令介面

/// <summary>
/// 命令介面
/// </summary>
public interface ICommand
{
    /// <summary>
    /// 執行命令
    /// </summary>
    void Execute();
}

🍲 建立具體命令

using System;

/// <summary>
/// 點餐命令
/// </summary>
public class OrderCommand : ICommand
{
    private readonly Kitchen _kitchen;
    private readonly string _dish;

    public OrderCommand(Kitchen kitchen, string dish)
    {
        _kitchen = kitchen;
        _dish = dish;
    }

    /// <summary>
    /// 執行點餐動作
    /// </summary>
    public void Execute()
    {
        _kitchen.PrepareDish(_dish);
    }
}

👨‍🍳 建立接收者(Receiver)

using System;

/// <summary>
/// 廚房,負責準備料理
/// </summary>
public class Kitchen
{
    /// <summary>
    /// 準備菜餚
    /// </summary>
    public void PrepareDish(string dish)
    {
        Console.WriteLine($"廚房正在準備:{dish}");
    }
}

🧑‍💼 建立調用者(Invoker)

using System.Collections.Generic;

/// <summary>
/// 服務生,負責接收並送出點餐
/// </summary>
public class Waiter
{
    private readonly List<ICommand> _orders = new();

    /// <summary>
    /// 接收點餐
    /// </summary>
    public void TakeOrder(ICommand command)
    {
        _orders.Add(command);
    }

    /// <summary>
    /// 送出所有點餐
    /// </summary>
    public void SubmitOrders()
    {
        foreach (var order in _orders)
        {
            order.Execute();
        }
        _orders.Clear();
    }
}

🚀 實際使用範例

using System;

class Program
{
    static void Main(string[] args)
    {
        Kitchen kitchen = new();
        Waiter waiter = new();

        ICommand order1 = new OrderCommand(kitchen, "牛排");
        ICommand order2 = new OrderCommand(kitchen, "沙拉");

        waiter.TakeOrder(order1);
        waiter.TakeOrder(order2);

        waiter.SubmitOrders();
    }
}

🎯 執行結果

廚房正在準備:牛排
廚房正在準備:沙拉

⚠️ 命令模式使用注意事項

  • 優點:能夠輕鬆處理命令的延遲執行、撤銷以及記錄歷史。
  • 缺點:可能會產生大量的命令類別,增加系統複雜度。

🎉 結語

太棒了!你又學會了一個有趣又實用的設計模式—命令模式(Command)!透過這個模式,你的系統將更加靈活、易於控制。

繼續追蹤設計模式系列吧,下篇再見囉~

系列:

讀完了!你覺得這篇如何?

你的回饋會決定下一篇要寫什麼。

還有疑問

Learning path

設計模式

這篇是系列中的第 15 / 24 篇。可以順著列表補完整脈絡,也可以直接跳到需要的段落。

  1. 01 搞懂設計模式到底是什麼?
  2. 02 單例模式:只要一個就夠!
  3. 03 工廠方法模式:點披薩不用親自下廚
  4. 04 抽象工廠模式:系列產品輕鬆生產
  5. 05 原型模式:複製的藝術
  6. 06 建造者模式:一步步完成複雜任務
  7. 07 介面卡模式:讓不相容也能合作
  8. 08 橋接模式:抽象與實作分離
  9. 09 組合模式:樹狀結構的好幫手
  10. 10 裝飾者模式:讓功能自由加點
  11. 11 外觀模式:化繁為簡
  12. 12 享元模式:節省記憶體的利器
  13. 13 代理模式:控制存取的守門員
  14. 14 責任鏈模式:層層把關的處理機制
  15. 15 命令模式:靈活封裝的請求指令 目前閱讀
  16. 16 解譯器模式:讓程式聽懂你的指令
  17. 17 迭代器模式:輕鬆遍歷集合元素
  18. 18 中介者模式:管理複雜溝通的好幫手
  19. 19 備忘錄模式:保存與恢復物件狀態
  20. 20 觀察者模式:即時通知的好幫手
  21. 21 狀態模式:依狀態改變行為的祕訣
  22. 22 策略模式:靈活切換行為的好幫手
  23. 23 模板方法模式:固定流程靈活實作
  24. 24 訪問者模式:新增功能不動既有架構

Further reading

中介者模式:管理複雜溝通的好幫手 封面圖 2025-06-13 中介者模式:管理複雜溝通的好幫手 備忘錄模式:保存與恢復物件狀態 封面圖 2025-06-13 備忘錄模式:保存與恢復物件狀態 模板方法模式:固定流程靈活實作 封面圖 2025-06-13 模板方法模式:固定流程靈活實作

留言討論

用 GitHub 帳號留言,留言會同步到這個 Blog 的 GitHub Discussions。

閱讀導覽

約 2 分鐘

本篇所在系列 · 第 15 / 24 篇

設計模式

  1. 搞懂設計模式到底是什麼?
  2. 單例模式:只要一個就夠!
  3. 工廠方法模式:點披薩不用親自下廚
  4. 抽象工廠模式:系列產品輕鬆生產
  5. 原型模式:複製的藝術
  6. 建造者模式:一步步完成複雜任務
  7. 介面卡模式:讓不相容也能合作
  8. 橋接模式:抽象與實作分離
  9. 組合模式:樹狀結構的好幫手
  10. 裝飾者模式:讓功能自由加點
  11. 外觀模式:化繁為簡
  12. 享元模式:節省記憶體的利器
  13. 代理模式:控制存取的守門員
  14. 責任鏈模式:層層把關的處理機制
  15. 命令模式:靈活封裝的請求指令
  16. 解譯器模式:讓程式聽懂你的指令
  17. 迭代器模式:輕鬆遍歷集合元素
  18. 中介者模式:管理複雜溝通的好幫手
  19. 備忘錄模式:保存與恢復物件狀態
  20. 觀察者模式:即時通知的好幫手
  21. 狀態模式:依狀態改變行為的祕訣
  22. 策略模式:靈活切換行為的好幫手
  23. 模板方法模式:固定流程靈活實作
  24. 訪問者模式:新增功能不動既有架構
看完整系列 24 篇