[파이썬] 행위 패턴과 객체 상호 작용

행위 패턴은 객체 지향 프로그래밍에서 중요한 개념 중 하나입니다. 이러한 패턴은 객체들의 상호 작용을 조직화하고, 유연하고 재사용 가능한 코드를 작성하는 데 도움을 줍니다. Python은 다양한 행위 패턴을 지원하며, 이를 활용하여 객체 간의 상호 작용을 효과적으로 구현할 수 있습니다.

1. Strategy Pattern (전략 패턴)

전략 패턴은 알고리즘을 캡슐화하고, 실행 시에 알고리즘을 선택할 수 있도록 하는 패턴입니다. 이 패턴은 같은 종류의 작업을 수행하는 다양한 알고리즘을 정의하고, 실행 시에 알고리즘을 변경할 수 있는 유연성을 제공합니다.

다음은 Strategy 패턴의 간단한 예시입니다. “전투”를 수행하는 Combat 클래스가 있고, 다양한 공격 방식을 제공하는 AttackStrategy 인터페이스와 그를 구현한 SwordAttackMagicAttack 클래스가 있습니다.

class AttackStrategy:
    def attack(self):
        pass

class SwordAttack(AttackStrategy):
    def attack(self):
        print("검으로 공격합니다.")

class MagicAttack(AttackStrategy):
    def attack(self):
        print("마법으로 공격합니다.")

class Combat:
    def __init__(self, attack_strategy):
        self.attack_strategy = attack_strategy

    def perform_attack(self):
        self.attack_strategy.attack()

# 사용 예시
combat = Combat(SwordAttack())
combat.perform_attack()  # 출력: "검으로 공격합니다."

combat = Combat(MagicAttack())
combat.perform_attack()  # 출력: "마법으로 공격합니다."

2. Observer Pattern (옵저버 패턴)

옵저버 패턴은 객체들 간에 일대다 의존 관계를 정의하고, 한 객체의 상태가 변경되면 이를 의존하는 객체들에게 알림을 보내는 패턴입니다. 이 패턴은 객체 간의 느슨한 결합을 제공하므로, 한 객체의 변경이 다른 객체들에게 영향을 미치는 것을 최소화할 수 있습니다.

다음은 Observer 패턴의 간단한 예시입니다. Subject 클래스는 상태를 갖고 있으며, 상태가 변경되면 Observer들에게 알림을 보냅니다.

class Subject:
    def __init__(self):
        self.observers = []

    def attach(self, observer):
        self.observers.append(observer)

    def detach(self, observer):
        self.observers.remove(observer)

    def notify(self):
        for observer in self.observers:
            observer.update()

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

    def update(self):
        print(f"{self.name}이(가) 상태 변경을 감지했습니다.")

# 사용 예시
subject = Subject()

observer1 = Observer("Observer 1")
observer2 = Observer("Observer 2")

subject.attach(observer1)
subject.attach(observer2)

subject.notify()  # 출력: "Observer 1이(가) 상태 변경을 감지했습니다."
                  #      "Observer 2이(가) 상태 변경을 감지했습니다."

subject.detach(observer1)

subject.notify()  # 출력: "Observer 2이(가) 상태 변경을 감지했습니다."

3. Command Pattern (커맨드 패턴)

커맨드 패턴은 작업을 객체로 캡슐화하고, 작업을 요청한 객체와 작업을 수행하는 객체를 분리하는 패턴입니다. 이 패턴은 작업을 실행, 취소, 재실행하는 등의 조작을 동적으로 관리하고자 할 때 유용합니다.

다음은 Command 패턴의 간단한 예시입니다. Command 인터페이스와 그를 구현한 LightOnCommandLightOffCommand 클래스가 있습니다. Invoker 클래스는 커맨드를 실행하는 역할을 합니다.

class Command:
    def execute(self):
        pass

    def undo(self):
        pass

class Light:
    def on(self):
        print("조명을 켭니다.")

    def off(self):
        print("조명을 끕니다.")

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light

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

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

class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light

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

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

class Invoker:
    def __init__(self):
        self.commands = []

    def add_command(self, command):
        self.commands.append(command)

    def execute_commands(self):
        for command in self.commands:
            command.execute()

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

# 사용 예시
invoker = Invoker()
light = Light()

light_on_command = LightOnCommand(light)
light_off_command = LightOffCommand(light)

invoker.add_command(light_on_command)
invoker.add_command(light_off_command)

invoker.execute_commands()  # 출력: "조명을 켭니다."
                            #      "조명을 끕니다."

invoker.undo_commands()     # 출력: "조명을 켭니다."
                            #      "조명을 끕니다."

결론

Python은 다양한 행위 패턴을 지원하여 객체 간의 상호 작용을 구현하는 데 유용합니다. 위에서 소개한 전략, 옵저버, 커맨드 패턴은 객체 지향 개발에서 핵심적인 패턴 중 일부입니다. 이러한 패턴을 활용하여 코드의 유지 보수성, 가독성, 재사용성을 향상시킬 수 있습니다.