이 글은 헤드 퍼스트 디자인 패턴을 읽고 정리한 것입니다.
커맨트 패턴은 객체 지향 디자인 패턴을 통해 요청을 하는 객체와 요청을 받고 실행하는 객체를 분리한 패턴으로 요청자(invoker)와 수신자(receiver)가 decoupling 되어 있다.
setCommand()
를 실행한다.execute()
만 노출 시킨다. execute()
메소드가 실행 되었다는 것만 안다.예시
리모컨으로 불을 켜는 것에 대한 책의 예시를 파이썬으로 작성 했다.
from abc import *
# The example from the Head First Design Pattern
"""
Receiver: Some appliances
"""
class Light:
def on(self):
print("on")
def off(self):
print("off")
"""
Command: on, off
"""
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self):
raise NotImplementedError()
class LightOnCommand(Command):
def __init__(self, light: Light):
self.light = light
def execute(self) -> None:
self.light.on()
"""
Invoker: RemoteControl
"""
class RemoteControl:
def __init__(self, command: Command):
self.slot = command # A kind of setter in Java
def button_pressed(self) -> None:
self.slot.execute()
# Usage
class RemoteControlTest:
@classmethod
def run(cls):
light = Light()
light_on = LightOnCommand(light=light)
remote = RemoteControl(command=light_on)
remote.button_pressed() # on
execute()
실행시 리스트에 들어 있는 커맨드들이 하나씩 실행되도록 만들면 된다.예시
책의 예시를 파이썬으로 바꾸어 작성해 보았다.
# The example from the Head First Design Pattern
"""
Receiver: Some appliances
"""
from abc import ABCMeta, abstractmethod
from typing import List
class Light:
def on(self, type: str):
on_by_types = {
"living_room": "living_room_light_on",
"bath_room": "living_room_light_on",
}
print(on_by_types.get(type))
def off(self, type: str):
on_by_types = {
"living_room": "living_room_light_off",
"bath_room": "living_room_light_off",
}
print(on_by_types.get(type))
class Stereo:
def on(self):
print("on")
def off(self):
print("off")
def set_cd(self):
print("CD in")
"""
Command: on, off
"""
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self):
raise NotImplementedError()
class LightOnCommand(Command):
"""Light"""
def __init__(self, light: Light, type: str):
self.light = light
self.type = type
def execute(self) -> None:
self.light.on(self.type)
class LightOffCommand(Command):
"""Light"""
def __init__(self, light: Light, type: str):
self.light = light
self.type = type
def execute(self) -> None:
self.light.off(self.type)
class StereoOnWithCDCommand(Command):
"""Stereo"""
def __init__(self, stereo: Stereo):
self.stereo = stereo
def execute(self) -> None:
self.stereo.on()
self.stereo.set_cd()
"""
Invoker: RemoteControl
"""
class RemoteControl:
def __init__(self, on_commands: List[Command], off_commands: List[Command]):
self.on_commands = on_commands # A kind of setter in Java
self.off_commands = off_commands # A kind of setter in Java
def on_button_pressed(self, slot: int) -> None:
self.on_commands[slot].execute()
def off_button_pressed(self, slot: int) -> None:
self.off_commands[slot].execute()
# Usage
class RemoteLoader:
@classmethod
def run(cls):
light = Light()
stereo = Stereo()
on_commands = [
LightOnCommand(light=light, type="living_room"),
StereoOnWithCDCommand(stereo=stereo),
]
off_commands = [
LightOffCommand(light=light, type="living_room"),
StereoOnWithCDCommand(stereo=stereo),
]
remote = RemoteControl(on_commands=on_commands, off_commands=off_commands)
length_of_commands = len(on_commands)
for slot in range(length_of_commands):
remote.on_button_pressed(slot=slot)
execute()
메소드가 불리기 이전의 상태로 되돌리면 된다.execute()
만 실행하면 되며, 이 메소드는 각각의 이벤트에 대한 커맨트를 실행한다.