命令模式

109 阅读3分钟

1. 简介

命令模式是一种行为设计模式,它允许将请求或操作封装成一个独立的对象,从而使得请求的发送者和接收者解耦。在命令模式中,命令对象包含了执行特定操作所需的所有信息,包括执行操作的方法以及操作的参数。

2. 命令模式的结构

2.1 模式结构

命令模式主要包含以下5个实体:

  1. 命令(Command) :命令是一个接口或抽象类,定义了执行特定操作的方法。

  2. 具体命令(Concrete Command) :具体命令是命令接口的具体实现,它包含了执行特定操作的具体逻辑和参数。

  3. 接收者(Receiver) :接收者是真正执行操作的对象,它知道如何执行具体的命令。

  4. 调用者/请求者(Invoker) :调用者是负责向命令对象发送请求的对象,它只知道如何调用命令对象,而不需要知道命令的具体实现细节。

  5. 客户端(Client) :客户端创建具体的命令对象,并将其与接收者对象关联起来,然后将命令对象传递给调用者对象。

2.2 UML图例

classDiagram
    class Client {
        +client()
    }
    
    class Invoker {
        -commands: List[Command]
        +addCommand(cmd: Command)
        +executeCommand(args: Any)
    }
    
    class Command {
        <<interface>>
        +execute(args: Any)
    }
    
    class ConcreteCommand {
        -receiver: Receiver
        +execute(args: Any)
    }
    
    class Receiver {
        +execute(args: Any)
    }
    
    Command <|.. ConcreteCommand
    ConcreteCommand o-- Receiver
    Invoker o-- Command
    Client <.. Invoker
    Client <.. Receiver
    Client <.. ConcreteCommand

3. 命令模式的优缺点以及使用场景

命令模式在需要将请求封装成对象、支持撤销和重做、设计命令队列等情况下,都是一个有效的设计模式。

  • 撤销操作:  需要支持撤销操作,命令模式可以存储历史命令,轻松实现撤销功能。
  • 队列请求:  命令模式可以将请求排队,形成一个命令队列,依次执行命令。
  • 可扩展性:  可以很容易地添加新的命令类和接收者类,而不影响现有的代码。新增命令不需要修改现有代码,符合开闭原则。

但是对于每个命令,都会有一个具体命令类,这可能导致类的数量急剧增加,增加了系统的复杂性。

4. 示例:【设计模式专题之命令模式】15-自助点餐机

""" 
【设计模式专题之命令模式】15-自助点餐机
时间限制:1.000S  空间限制:256MB
题目描述
小明去奶茶店买奶茶,他可以通过在自助点餐机上来点不同的饮品,请你使用命令模式设计一个程序,模拟这个自助点餐系统的功能。

输入描述

第一行是一个整数 n(1 ≤ n ≤ 100),表示点单的数量。
接下来的 n 行,每行包含一个字符串,表示点餐的饮品名称。

输出描述
输出执行完所有点单后的制作情况,每行输出一种饮品的制作情况。如果制作完成,输出 "XXX is ready!",其中 XXX 表示饮品名称。
输入示例
4
MilkTea
Coffee
Cola
MilkTea
输出示例
MilkTea is ready!
Coffee is ready!
Cola is ready!
MilkTea is ready!
"""


from abc import ABC, abstractmethod
from typing import List


class DrinkMaker:
    def make(self, drinkName: str):
        print(f"{drinkName} is ready!")


class Order(ABC):
    @abstractmethod
    def place(self):
        raise NotImplemented
        
        
class DrinkOrder(Order):
    def __init__(self, drinkName: str, drinkMaker: DrinkMaker):
        self.drinkName = drinkName
        self.drinkMaker = drinkMaker
        
    def place(self):
        self.drinkMaker.make(self.drinkName)
        
        
class SelfOrderingMachine:
    def __init__(self):
        self.orders: List[Order] = []
        
    def addOrder(self, order: Order):
        self.orders.append(order)
        
    def placeOrders(self):
        for order in self.orders:
            order.place()
            
            
def client():
    maker = DrinkMaker()
    machine = SelfOrderingMachine()
    n = int(input())
    for _ in range(n):
        drinkName = input()
        order = DrinkOrder(drinkName, maker)
        machine.addOrder(order)
    machine.placeOrders()
            

if __name__ == "__main__":
    client()