基于Python学习《Head First设计模式》第六章 命令模式

遥控器项目


实现思路



实现类图


再次梳理

代码实现

python 复制代码
class RemoteControl:
    """遥控器"""
    on_commands: List[Command]
    off_commands: List[Command]

    def __init__(self):
        self.on_commands = []
        self.off_commands = []
        no_command = NoCommand()
        for _ in range(7):
            self.on_commands.append(no_command)
            self.off_commands.append(no_command)

    def set_command(self, slot: int, on_command: Command, off_command: Command):
        self.on_commands[slot] = on_command
        self.off_commands[slot] = off_command

    def on_button_was_pushed(self, slot: int):
        self.on_commands[slot].excute()

    def off_button_was_pushed(self, slot: int):
        self.off_commands[slot].excute()

    def __str__(self):
        buffer_str = []
        for i in range(len(self.on_commands)):
            buffer_str.append(
                f'[卡槽{i + 1}]{self.on_commands[i].__class__.__qualname__}\t{self.off_commands[i].__class__.__qualname__}')
        return "\n".join(buffer_str)
python 复制代码
class LightOffCommand(Command):
    light: Light

    def __init__(self, light: Light):
        self.light = light

    def excute(self):
        self.light.off()

    def undo(self):
        pass
       

class StereoOnWithCDCommand(Command):
    stereo: Stereo

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.stereo.on()
        self.stereo.set_cd()
        self.stereo.set_volume(11)

    def undo(self):
        pass
python 复制代码
if __name__ == '__main__':
    remote_control = RemoteControl()
    living_room_light = Light("Living Room light")
    kitchen_light = Light("Kitchen light")
    stereo = Stereo("Living Room Stereo")

    living_room_light_on = LightOnCommand(living_room_light)
    living_room_light_off = LightOffCommand(living_room_light)

    kitchen_light_on = LightOnCommand(kitchen_light)
    kitchen_light_off = LightOffCommand(kitchen_light)

    stereo_on = StereoOnWithCDCommand(stereo)
    stereo_off = StereoOffWithCDCommand(stereo)

    remote_control.set_command(0, living_room_light_on, living_room_light_off)
    remote_control.set_command(1, kitchen_light_on, kitchen_light_off)
    remote_control.set_command(2, stereo_on, stereo_off)

    print(remote_control)
    print()

    remote_control.on_button_was_pushed(0)
    remote_control.off_button_was_pushed(0)

    remote_control.on_button_was_pushed(1)
    remote_control.off_button_was_pushed(1)

    remote_control.on_button_was_pushed(2)
    remote_control.off_button_was_pushed(2)

设计全貌

完整代码

与书上的代码略有不同,整体结构是一样的。书上是吊扇,我这里是音响。

python 复制代码
from abc import ABCMeta, abstractmethod, ABC
from typing import List


class Command(ABC):

    @abstractmethod
    def excute(self):
        pass

    @abstractmethod
    def undo(self):
        pass


class NoCommand(Command):

    def excute(self):
        pass

    def undo(self):
        pass


class Light:
    """电灯"""
    name: str

    def __init__(self, name):
        self.name = name

    def off(self):
        print(f'{self.name} is off.')

    def on(self):
        print(f'{self.name} is on.')


class LightOnCommand(Command):
    light: Light

    def __init__(self, light: Light):
        self.light = light

    def excute(self):
        self.light.on()

    def undo(self):
        print('撤销操作,', end='')
        self.light.off()


class LightOffCommand(Command):
    light: Light

    def __init__(self, light: Light):
        self.light = light

    def excute(self):
        self.light.off()

    def undo(self):
        print('撤销操作,', end='')
        self.light.on()


class Stereo:
    """音响"""
    name: str

    def __init__(self, name):
        self.name = name

    def off(self):
        print(f'{self.name} is off.')

    def on(self):
        print(f'{self.name} is on.')

    def set_cd(self):
        print(f'{self.name} is set for CD input.')

    def set_volume(self, volume: int):
        print(f'{self.name} volume set to {volume}.')


class StereoOnWithCDCommand(Command):
    stereo: Stereo

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.stereo.on()
        self.stereo.set_cd()
        self.stereo.set_volume(11)

    def undo(self):
        print('撤销操作,', end='')
        self.stereo.off()


class StereoOffWithCDCommand(Command):
    stereo: Stereo

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.stereo.off()

    def undo(self):
        print('撤销操作,', end='')
        self.stereo.on()


class RemoteControl:
    """遥控器"""
    on_commands: List[Command]
    off_commands: List[Command]
    undo_command: Command

    def __init__(self):
        self.on_commands = []
        self.off_commands = []
        no_command = NoCommand()
        for _ in range(7):
            self.on_commands.append(no_command)
            self.off_commands.append(no_command)
        self.undo_command = no_command

    def set_command(self, slot: int, on_command: Command, off_command: Command):
        self.on_commands[slot] = on_command
        self.off_commands[slot] = off_command

    def on_button_was_pushed(self, slot: int):
        self.on_commands[slot].excute()
        self.undo_command = self.on_commands[slot]

    def off_button_was_pushed(self, slot: int):
        self.off_commands[slot].excute()
        self.undo_command = self.off_commands[slot]

    def undo_button_was_pushed(self):
        self.undo_command.undo()

    def __str__(self):
        buffer_str = []
        for i in range(len(self.on_commands)):
            buffer_str.append(
                f'[卡槽{i + 1}]{self.on_commands[i].__class__.__qualname__}\t{self.off_commands[i].__class__.__qualname__}')
        return "\n".join(buffer_str)


if __name__ == '__main__':
    remote_control = RemoteControl()
    living_room_light = Light("Living Room light")
    kitchen_light = Light("Kitchen light")
    stereo = Stereo("Living Room Stereo")

    living_room_light_on = LightOnCommand(living_room_light)
    living_room_light_off = LightOffCommand(living_room_light)

    kitchen_light_on = LightOnCommand(kitchen_light)
    kitchen_light_off = LightOffCommand(kitchen_light)

    stereo_on = StereoOnWithCDCommand(stereo)
    stereo_off = StereoOffWithCDCommand(stereo)

    remote_control.set_command(0, living_room_light_on, living_room_light_off)
    remote_control.set_command(1, kitchen_light_on, kitchen_light_off)
    remote_control.set_command(2, stereo_on, stereo_off)

    print(remote_control)
    print()

    remote_control.on_button_was_pushed(0)
    remote_control.off_button_was_pushed(0)
    remote_control.undo_button_was_pushed()

    remote_control.on_button_was_pushed(1)
    remote_control.undo_button_was_pushed()
    remote_control.off_button_was_pushed(1)

    remote_control.off_button_was_pushed(2)
    remote_control.on_button_was_pushed(2)
    remote_control.undo_button_was_pushed()

"""运行结果:
[卡槽1]LightOnCommand	LightOffCommand
[卡槽2]LightOnCommand	LightOffCommand
[卡槽3]StereoOnWithCDCommand	StereoOffWithCDCommand
[卡槽4]NoCommand	NoCommand
[卡槽5]NoCommand	NoCommand
[卡槽6]NoCommand	NoCommand
[卡槽7]NoCommand	NoCommand

Living Room light is on.
Living Room light is off.
撤销操作,Living Room light is on.
Kitchen light is on.
撤销操作,Kitchen light is off.
Kitchen light is off.
Living Room Stereo is off.
Living Room Stereo is on.
Living Room Stereo is set for CD input.
Living Room Stereo volume set to 11.
撤销操作,Living Room Stereo is off.
"""

添加撤销操作

python 复制代码
from abc import ABCMeta, abstractmethod, ABC
from typing import List


class Command(ABC):

    @abstractmethod
    def excute(self):
        pass

    @abstractmethod
    def undo(self):
        pass


class NoCommand(Command):

    def excute(self):
        pass

    def undo(self):
        pass


class Stereo:
    """音响"""
    name: str
    HIGH = 90
    MEDIUM = 40
    LOW = 10
    OFF = 0
    _volume: int

    def __init__(self, name):
        self.name = name
        self._volume = Stereo.OFF

    def off(self):
        print(f'{self.name} is off.')

    def on(self):
        print(f'{self.name} is on.')

    def set_cd(self):
        print(f'{self.name} is set for CD input.')

    def set_volume(self, volume: int):
        self._volume = volume
        print(f'{self.name} volume set to {volume}.')

    def get_volume(self):
        return self._volume

    def volume_high(self):
        print(f'音量设置为{Stereo.HIGH}')
        self._volume = Stereo.HIGH

    def volume_medium(self):
        print(f'音量设置为{Stereo.MEDIUM}')
        self._volume = Stereo.MEDIUM

    def volume_low(self):
        print(f'音量设置为{Stereo.LOW}')
        self._volume = Stereo.LOW


class StereoOnWithCDCommand(Command):
    stereo: Stereo
    pre_volume: int

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.pre_volume = self.stereo.get_volume()
        self.stereo.on()
        self.stereo.set_cd()
        self.stereo.set_volume(Stereo.MEDIUM)

    def undo(self):
        print('撤销操作,', end='')


class StereoHighVolumeWithCDCommand(Command):
    pre_volume: int

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.pre_volume = self.stereo.get_volume()
        self.stereo.volume_high()

    def undo(self):
        print('撤销操作,', end='')
        if self.pre_volume == Stereo.HIGH:
            self.stereo.volume_high()
        elif self.pre_volume == Stereo.MEDIUM:
            self.stereo.volume_medium()
        elif self.pre_volume == Stereo.LOW:
            self.stereo.volume_low()
        else:
            self.stereo.off()


class StereoLowVolumeWithCDCommand(Command):
    pre_volume: int

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.pre_volume = self.stereo.get_volume()
        self.stereo.volume_low()

    def undo(self):
        print('撤销操作,', end='')
        if self.pre_volume == Stereo.HIGH:
            self.stereo.volume_high()
        elif self.pre_volume == Stereo.MEDIUM:
            self.stereo.volume_medium()
        elif self.pre_volume == Stereo.LOW:
            self.stereo.volume_low()
        else:
            self.stereo.off()


class StereoOffWithCDCommand(Command):
    stereo: Stereo

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.stereo.off()

    def undo(self):
        print('撤销操作,', end='')
        self.stereo.on()


class RemoteControlWithUndo:
    """遥控器"""
    on_commands: List[Command]
    off_commands: List[Command]
    undo_command: Command

    def __init__(self):
        self.on_commands = []
        self.off_commands = []
        no_command = NoCommand()
        for _ in range(7):
            self.on_commands.append(no_command)
            self.off_commands.append(no_command)
        self.undo_command = no_command

    def set_command(self, slot: int, on_command: Command, off_command: Command):
        self.on_commands[slot] = on_command
        self.off_commands[slot] = off_command

    def on_button_was_pushed(self, slot: int):
        self.on_commands[slot].excute()
        self.undo_command = self.on_commands[slot]

    def off_button_was_pushed(self, slot: int):
        self.off_commands[slot].excute()
        self.undo_command = self.off_commands[slot]

    def undo_button_was_pushed(self):
        self.undo_command.undo()

    def __str__(self):
        buffer_str = []
        for i in range(len(self.on_commands)):
            buffer_str.append(
                f'[卡槽{i + 1}]{self.on_commands[i].__class__.__qualname__}\t{self.off_commands[i].__class__.__qualname__}')
        return "\n".join(buffer_str)


if __name__ == '__main__':
    remote_control = RemoteControlWithUndo()
    stereo = Stereo('音响')
    stereo_off = StereoOffWithCDCommand(stereo)
    stereo_high_volume = StereoHighVolumeWithCDCommand(stereo)
    stereo_low_volume = StereoLowVolumeWithCDCommand(stereo)

    remote_control.set_command(0, stereo_high_volume, stereo_off)
    remote_control.set_command(1, stereo_low_volume, stereo_off)
    print(remote_control)

    remote_control.on_button_was_pushed(0)
    remote_control.off_button_was_pushed(0)
    remote_control.undo_button_was_pushed()

    remote_control.on_button_was_pushed(1)
    remote_control.undo_button_was_pushed()

"""运行结果:
[卡槽1]StereoHighVolumeWithCDCommand	StereoOffWithCDCommand
[卡槽2]StereoLowVolumeWithCDCommand	StereoOffWithCDCommand
[卡槽3]NoCommand	NoCommand
[卡槽4]NoCommand	NoCommand
[卡槽5]NoCommand	NoCommand
[卡槽6]NoCommand	NoCommand
[卡槽7]NoCommand	NoCommand
音量设置为90
音响 is off.
撤销操作,音响 is on.
音量设置为10
撤销操作,音量设置为90
"""

批量操作

使用宏命令

python 复制代码
from abc import ABCMeta, abstractmethod, ABC
from typing import List


class Command(ABC):

    @abstractmethod
    def excute(self):
        pass

    @abstractmethod
    def undo(self):
        pass


class NoCommand(Command):

    def excute(self):
        pass

    def undo(self):
        pass


class MacroCommand(Command):
    commands: List[Command]

    def __init__(self, commands: List[Command]):
        self.commands = commands

    def excute(self):
        for command in self.commands:
            command.excute()

    def undo(self):
        for command in self.commands:
            command.undo()


class Light:
    """电灯"""
    name: str

    def __init__(self, name):
        self.name = name

    def off(self):
        print(f'{self.name} is off.')

    def on(self):
        print(f'{self.name} is on.')


class LightOnCommand(Command):
    light: Light

    def __init__(self, light: Light):
        self.light = light

    def excute(self):
        self.light.on()

    def undo(self):
        print('撤销操作,', end='')
        self.light.off()


class LightOffCommand(Command):
    light: Light

    def __init__(self, light: Light):
        self.light = light

    def excute(self):
        self.light.off()

    def undo(self):
        print('撤销操作,', end='')
        self.light.on()


class Stereo:
    """音响"""
    name: str

    def __init__(self, name):
        self.name = name

    def off(self):
        print(f'{self.name} is off.')

    def on(self):
        print(f'{self.name} is on.')

    def set_cd(self):
        print(f'{self.name} is set for CD input.')

    def set_volume(self, volume: int):
        print(f'{self.name} volume set to {volume}.')


class StereoOnWithCDCommand(Command):
    stereo: Stereo

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.stereo.on()
        self.stereo.set_cd()
        self.stereo.set_volume(11)

    def undo(self):
        print('撤销操作,', end='')
        self.stereo.off()


class StereoOffWithCDCommand(Command):
    stereo: Stereo

    def __init__(self, stereo: Stereo):
        self.stereo = stereo

    def excute(self):
        self.stereo.off()

    def undo(self):
        print('撤销操作,', end='')
        self.stereo.on()


class RemoteControl:
    """遥控器"""
    on_commands: List[Command]
    off_commands: List[Command]
    undo_command: Command

    def __init__(self):
        self.on_commands = []
        self.off_commands = []
        no_command = NoCommand()
        for _ in range(7):
            self.on_commands.append(no_command)
            self.off_commands.append(no_command)
        self.undo_command = no_command

    def set_command(self, slot: int, on_command: Command, off_command: Command):
        self.on_commands[slot] = on_command
        self.off_commands[slot] = off_command

    def on_button_was_pushed(self, slot: int):
        self.on_commands[slot].excute()
        self.undo_command = self.on_commands[slot]

    def off_button_was_pushed(self, slot: int):
        self.off_commands[slot].excute()
        self.undo_command = self.off_commands[slot]

    def undo_button_was_pushed(self):
        self.undo_command.undo()

    def __str__(self):
        buffer_str = []
        for i in range(len(self.on_commands)):
            buffer_str.append(
                f'[卡槽{i + 1}]{self.on_commands[i].__class__.__qualname__}\t{self.off_commands[i].__class__.__qualname__}')
        return "\n".join(buffer_str)


if __name__ == '__main__':
    remote_control = RemoteControl()
    living_room_light = Light("Living Room light")
    kitchen_light = Light("Kitchen light")
    stereo = Stereo("Living Room Stereo")

    living_room_light_on = LightOnCommand(living_room_light)
    living_room_light_off = LightOffCommand(living_room_light)

    kitchen_light_on = LightOnCommand(kitchen_light)
    kitchen_light_off = LightOffCommand(kitchen_light)

    stereo_on = StereoOnWithCDCommand(stereo)
    stereo_off = StereoOffWithCDCommand(stereo)

    remote_control.set_command(0, living_room_light_on, living_room_light_off)
    remote_control.set_command(1, kitchen_light_on, kitchen_light_off)
    remote_control.set_command(2, stereo_on, stereo_off)

    party_on_macro = [living_room_light_on, kitchen_light_on, stereo_on]
    party_on = MacroCommand(party_on_macro)
    party_off = MacroCommand([living_room_light_off, kitchen_light_off, stereo_off])
    remote_control.set_command(3, party_on, party_off)

    print(remote_control)
    print()

    print('---Pushing Macro On---')
    remote_control.on_button_was_pushed(3)
    print()

    print('---Pushing Macro Off---')
    remote_control.off_button_was_pushed(3)

    print()
    print('---Pushing Macro Undo---')
    remote_control.undo_button_was_pushed()

"""运行结果:
[卡槽1]LightOnCommand	LightOffCommand
[卡槽2]LightOnCommand	LightOffCommand
[卡槽3]StereoOnWithCDCommand	StereoOffWithCDCommand
[卡槽4]MacroCommand	MacroCommand
[卡槽5]NoCommand	NoCommand
[卡槽6]NoCommand	NoCommand
[卡槽7]NoCommand	NoCommand

---Pushing Macro On---
Living Room light is on.
Kitchen light is on.
Living Room Stereo is on.
Living Room Stereo is set for CD input.
Living Room Stereo volume set to 11.

---Pushing Macro Off---
Living Room light is off.
Kitchen light is off.
Living Room Stereo is off.

---Pushing Macro Undo---
撤销操作,Living Room light is on.
撤销操作,Kitchen light is on.
撤销操作,Living Room Stereo is on.
"""

命令模式的用途

请求队列、日志请求

总结

相关推荐
xuhaoyu_cpp_java2 小时前
项目学习(三)分页查询
java·经验分享·笔记·学习
珺毅同学2 小时前
YOLO生成预测json标签迁移问题
python·yolo·json
骑士雄师2 小时前
18.4 长期记忆可修改版
python
~小先生~2 小时前
Python从入门到放弃(一)
开发语言·python
天佑木枫3 小时前
第2天:变量与数据类型 —— 让程序记住信息
python
小宋加油啊4 小时前
机械臂抓取物体 PVN3D算法调研学习
学习·算法·3d
Dust-Chasing4 小时前
Claude Code源码剖析 - Claude Code 上下文压缩机制
人工智能·python·ai
Xzh04234 小时前
AI Agent 学习路线(Java 后端方向)
java·人工智能·学习
Cloud_Shy6185 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 33 - 35)
开发语言·人工智能·笔记·python·学习方法
做cv的小昊5 小时前
计算机图形学:【Games101】学习笔记08——光线追踪(辐射度量学、渲染方程与全局光照、蒙特卡洛积分与路径追踪)
图像处理·笔记·学习·计算机视觉·游戏引擎·图形渲染·概率论