Strategy pattern
08 Nov 2016 | python patternStrategy pattern
알고리즘군을 정의하고 각각 캡슐화하여 바꿔쓸 수 있게 만든 패턴. 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘이 변경 가능하다.
어떻게쓰나?
다수의 interface를 가지는 abstract class가 존재하고. 해당 class를 상속받아서 class를 디자인하는 방법이다.
code
코드는 헤드퍼스트에 나온 Duck 예제를 python으로 바꿔서 비슷하게 만들어보았다. 최종 객체가 해야할 일은 다음과 같다.
- 디스플레이용 함수들
- performQuack
- performFly
- **위 세가지 함수 중 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!