定义
- 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
- 命令模式的最大特点是将具体的命令与对应的接收者相关联(捆绑),使得调用方不用关心具体的行动执行者及如何执行,只要发送正确的命令,就能准确无误地完成相应的任务。就像军队,将军一声令下,士兵就得分秒不差,准确执行。
- 命令模式是一种高内聚的模式,之所以说是高内聚是因为它把命令封装成对象,并与接收者关联在一起,从而使(命令的)请求者(Invoker)和接收者(Receiver)分离。
命令模式的模型抽象
代码框架
from abc import ABCMeta, abstractmethod
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法
class Command(metaclass=ABCMeta):
"""命令的抽象类"""
@abstractmethod
def execute(self):
pass
class CommandImpl(Command):
"""命令的具体实现类"""
def __init__(self, receiver):
self.__receiver = receiver
def execute(self):
self.__receiver.doSomething()
class Receiver:
"""命令的接收者"""
def doSomething(self):
print("do something...")
class Invoker:
"""调度者"""
def __init__(self):
self.__command = None
def setCommand(self, command):
self.__command = command
def action(self):
if self.__command is not None:
self.__command.execute()
类图
模型说明
- 设计要点
- 命令模式中主要有四个角色,在设计命令模式时要找到并区分这些角色。
- 命令(Command):要完成的任务,或要执行的动作,这是命令模式的核心角色。
- 接收者(Receiver):任务的具体实施方,或行动的真实执行者。
- 调度者(Invoker):接收任务并发送命令,对接用户的需求并执行内部的命令,负责外部用户与内部命令的交互。
- 用户(Client):命令的使用者,即真正的用户。
- 优缺点
- 优点
- 对命令的发送者与接收者进行解耦,使得调用方不用关心具体的行动执行者及如何执行,只要发送正确的命令即可。
- 可以很方便地增加新的命令。
- 缺点
- 在一些系统中可能会有很多命令,而每一个命令都需要一个具体的类去封装,容易使命令的类急剧膨胀。
例子
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# Authoer: Spencer.Luo
# Date: 5/18/2018
from abc import ABCMeta, abstractmethod
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法
import time
# 引入time模块进行时间的控制
class GameRole:
"""游戏的角色"""
# 每次移动的步距
STEP = 5
def __init__(self, name):
self.__name = name
self.__x = 0
self.__y = 0
self.__z = 0
def leftMove(self):
self.__x -= self.STEP
def rightMove(self):
self.__x += self.STEP
def upMove(self):
self.__y += self.STEP
def downMove(self):
self.__y -= self.STEP
def jumpMove(self):
self.__z += self.STEP
def squatMove(self):
self.__z -= self.STEP
def attack(self):
print("%s发动攻击..." % self.__name)
def showPosition(self):
print("%s的位置:(x:%s, y:%s, z:%s)" % (self.__name, self.__x, self.__y, self.__z) )
class GameCommand(metaclass=ABCMeta):
"""游戏角色的命令类"""
def __init__(self, role):
self._role = role
def setRole(self, role):
self._role = role
@abstractmethod
def execute(self):
pass
class Left(GameCommand):
"""左移命令"""
def execute(self):
self._role.leftMove()
self._role.showPosition()
class Right(GameCommand):
"""右移命令"""
def execute(self):
self._role.rightMove()
self._role.showPosition()
class Up(GameCommand):
"""上移命令"""
def execute(self):
self._role.upMove()
self._role.showPosition()
class Down(GameCommand):
"""下移命令"""
def execute(self):
self._role.downMove()
self._role.showPosition()
class Jump(GameCommand):
"""弹跳命令"""
def execute(self):
self._role.jumpMove()
self._role.showPosition()
# 跳起后空中停留半秒
time.sleep(0.5)
class Squat(GameCommand):
"""下蹲命令"""
def execute(self):
self._role.squatMove()
self._role.showPosition()
# 下蹲后伏地半秒
time.sleep(0.5)
class Attack(GameCommand):
"""攻击命令"""
def execute(self):
self._role.attack()
class MacroCommand(GameCommand):
"""宏命令,也就是组合命令"""
def __init__(self, role = None):
super().__init__(role)
self.__commands = []
def addCommand(self, command):
# 让所有的命令作用于同一个对象
self.__commands.append(command)
def removeCommand(self, command):
self.__commands.remove(command)
def execute(self):
for command in self.__commands:
command.execute()
class GameInvoker:
"""命令调度者"""
def __init__(self):
self.__command = None
def setCommand(self, command):
self.__command = command
return self
def action(self):
if self.__command is not None:
self.__command.execute()
def testGame():
"""在控制台用字符来模拟命令"""
role = GameRole("常山赵子龙")
invoker = GameInvoker()
while True:
strCmd = input("请输入命令:");
strCmd = strCmd.upper()
if (strCmd == "L"):
invoker.setCommand(Left(role)).action()
elif (strCmd == "R"):
invoker.setCommand(Right(role)).action()
elif (strCmd == "U"):
invoker.setCommand(Up(role)).action()
elif (strCmd == "D"):
invoker.setCommand(Down(role)).action()
elif (strCmd == "JP"):
cmd = MacroCommand()
cmd.addCommand(Jump(role))
cmd.addCommand(Squat(role))
invoker.setCommand(cmd).action()
elif (strCmd == "A"):
invoker.setCommand(Attack(role)).action()
elif (strCmd == "LU"):
cmd = MacroCommand()
cmd.addCommand(Left(role))
cmd.addCommand(Up(role))
invoker.setCommand(cmd).action()
elif (strCmd == "LD"):
cmd = MacroCommand()
cmd.addCommand(Left(role))
cmd.addCommand(Down(role))
invoker.setCommand(cmd).action()
elif (strCmd == "RU"):
cmd = MacroCommand()
cmd.addCommand(Right(role))
cmd.addCommand(Up(role))
invoker.setCommand(cmd).action()
elif (strCmd == "RD"):
cmd = MacroCommand()
cmd.addCommand(Right(role))
cmd.addCommand(Down(role))
invoker.setCommand(cmd).action()
elif (strCmd == "LA"):
cmd = MacroCommand()
cmd.addCommand(Left(role))
cmd.addCommand(Attack(role))
invoker.setCommand(cmd).action()
elif (strCmd == "RA"):
cmd = MacroCommand()
cmd.addCommand(Right(role))
cmd.addCommand(Attack(role))
invoker.setCommand(cmd).action()
elif (strCmd == "UA"):
cmd = MacroCommand()
cmd.addCommand(Up(role))
cmd.addCommand(Attack(role))
invoker.setCommand(cmd).action()
elif (strCmd == "DA"):
cmd = MacroCommand()
cmd.addCommand(Down(role))
cmd.addCommand(Attack(role))
invoker.setCommand(cmd).action()
elif (strCmd == "JA"):
cmd = MacroCommand()
cmd.addCommand(Jump(role))
cmd.addCommand(Attack(role))
cmd.addCommand(Squat(role))
invoker.setCommand(cmd).action()
elif (strCmd == "Q"):
exit()
testGame()
应用场景
- 你希望系统发送一个命令(或信号),任务就能得到处理时。如 GUI 中的各种按钮的点击命令,再如自定义一套消息的响应机制。
- 需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互时。
- 需要将一系列的命令组合成一组操作时,可以使用宏命令的方式。