Strategy pattern

|

Strategy pattern

알고리즘군을 정의하고 각각 캡슐화하여 바꿔쓸 수 있게 만든 패턴. 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘이 변경 가능하다.

어떻게쓰나?

다수의 interface를 가지는 abstract class가 존재하고. 해당 class를 상속받아서 class를 디자인하는 방법이다.

overView.png

code

코드는 헤드퍼스트에 나온 Duck 예제를 python으로 바꿔서 비슷하게 만들어보았다. 최종 객체가 해야할 일은 다음과 같다.

  • 디스플레이용 함수들
    • performQuack
    • performFly
    • print
  • **위 세가지 함수 중 perform는 여러 객체들이 겹칠 수 있다.**
  • setFlyBehavior, setQuackBehavior로 행동을 바꿀 수 있다. (optional)

print 함수의 경우 모든 상속받은 class에서 다르게 구현되어야 하기에 interface로 빼지 않았다.

Interface

# FlyBehavior.py
from abc import ABCMeta, abstractmethod

class FlyBehavior:
    __metaclass__ = ABCMeta

    @abstractmethod
    def fly(self):
        pass

class FlyWithWings(FlyBehavior):
    def fly(self):
        print("I can fly!")

class FlyNoWay(FlyBehavior):
    def fly(self):
        print("I can't fly.....:(")
# QuackBehavior.py
from abc import ABCMeta, abstractmethod

class QuackBehavior:
    __metaclass__ = ABCMeta

    @abstractmethod
    def quack(self):
        pass

class Quack(QuackBehavior):
    def quack(self):
        print("Quack! Quack!")

class Mute(QuackBehavior):
    def quack(self):
        print(".....")

Abstract Class

# Duck.py
from abc import ABCMeta, abstractmethod

class Duck:
    __metaclass__ = ABCMeta

    def __init__(self):
        self._flyBehavior = None
        self._quackBehavior = None

    @abstractmethod
    def print(self):
        pass

    def performFly(self):
        self._flyBehavior.fly()

    def performQuack(self):
        self._quackBehavior.quack()

    def setFlyBehavior(self, flyBehavior):
        self._flyBehavior = flyBehavior

    def setQuackBehavior(self, quackBehavior):
        self._quackBehavior = quackBehavior

Classes

# RubberDuck.py
from Duck import Duck
from FlyBehavior import FlyNoWay
from QuackBehavior import Quack

class RubberDuck(Duck):
    def __init__(self):
        self._flyBehavior = FlyNoWay()
        self._quackBehavior = Quack()

    def print(self):
        print("I'm rubber duck!")

    def performFly(self):
        self._flyBehavior.fly()

    def performQuack(self):
        self._quackBehavior.quack()

# RealDuck.py
from Duck import Duck
from FlyBehavior import FlyWithWings
from QuackBehavior import Quack

class RealDuck(Duck):
    def __init__(self):
        self._flyBehavior = FlyWithWings()
        self._quackBehavior = Quack()

    def print(self):
        print("I'm real duck!")

    def performFly(self):
        self._flyBehavior.fly()

    def performQuack(self):
        self._quackBehavior.quack()

Test code

from RubberDuck import RubberDuck
from RealDuck import RealDuck

from FlyBehavior import FlyNoWay

if __name__ == "__main__":
    a = RealDuck()
    a.print()
    a.performFly()
    a.performQuack()

    a.setFlyBehavior(FlyNoWay()) # 동적으로 interface를 변경가능!!
    print("I'm wounded!")
    a.performFly()
    a.performQuack()

    print("====================")

    b = RubberDuck()
    b.print()
    b.performFly()
    b.performQuack()

Results

$ python main.py 
I'm real duck!
I can fly!
Quack! Quack!
I'm wounded!
I can't fly.....:(
Quack! Quack!
====================
I'm rubber duck!
I can't fly.....:(
Quack! Quack!