11 Nov 2016
|
python
pattern
Command 요청과 실행을 분리하자!
Command의 요청, 실행을 분리하면서 의존성을 크게 낮춘 모델. command를 abstract class 또는 interface
로 만들고 concrete command
를 구현한다.
Receiver
는 실제 Action을 가지고있는 객체이며 command
는 이를 사용하여 Action을 만든다. Client가 Invoker
에게 command
를 세팅하면 추후에 Invoker
에게 실행을 요청하며 실행된다.
Overview
Code
from abc import ABCMeta, abstractmethod
# Receiver
class Light:
def on(self):
print("Light On")
def off(self):
print("Light Off")
# Command
class Command:
__metaclass__ = ABCMeta
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
# Concrete Command
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.on()
def undo(self):
self.light.off()
# Invoker
class SimpleRemoteControl:
def SetCommand(self, command):
self.slot = command
def ButtonPressed(self):
self.slot.execute()
if __name__ == '__main__':
controller = SimpleRemoteControl()
controller.SetCommand(LightOnCommand(Light()))
controller.ButtonPressed()
10 Nov 2016
|
python
용법의 차이
- str : 사용자가 보기 쉬운 형태로 보여줄 때 사용하는 것
- repr : 시스템(python interpreter)이 해당 객체를 인식할 수 있는 공식적인 문자열로 나타내 줄 때 사용하는 것
호출 경로
print(a)
하면 __str__
이 불린다.
print([a])
하면 __repr__
이 불린다.
__repr__
만 만들면 __str__
이 호출될 시에 __repr__
이 불린다. 이는 __str__
의 기본 구현이 __repr__
을 부르는 구조라서 그렇다고한다.
쓰는 경우
나의 경우 __str__
은 디버깅용 로그를 작성할 때, __repr__
은 위의 용법에 최대한 맞추되, list를 가진 class이거나 한 경우 그냥 디버깅용으로 쓴다. 이 부분은 더 공부가 필요해보인다.
class dataSchema(object):
def __init__(self, name: str, age: int):
self.setProperty(name, age)
def setProperty(self, name: str, age: int):
self.name = name
self.age = age
def getProperty(self):
if self.age == -1:
raise Exception('not setted.')
return {'name': self.name, 'age': self.age}
def __str__(self):
return "(name : {}, age : {})".format(self.name, self.age)
def __repr__(self):
return "{}(\"{}\", {})".format(self.__class__.__name__, self.name, self.age)
10 Nov 2016
|
python
pattern
Decorator Pattern ?
주어진 상황에 따라 동적으로 어떤 객체에 책임을 붙일 수 있는 패턴으로, 상속 대신 쓸 수 있는 대안이 된다.
python에는 @decorator
를 통해 비슷한 일을 해줄 수 있다.
Overview
요렇게 생겼다.
- 최상위에 interface가 존재하며,
- concrete component들은 그 interface를 구현한 구현체이다.
- decorator는 interface를 상속받고 interface를 가진다.
- 그리고 자신의 abstract method들을 구현할 때 가지고있는 interface를 이용하여 구현한다.
말로 쓰니까 어려워보인다. 코드를 넣자!
코드
from abc import ABCMeta, abstractmethod
# Interface
class Widget:
__metaclass__ = ABCMeta
@abstractmethod
def draw(self):
pass
# 구현체
class ConcreteWindow(Widget):
def __init__(self, w : int, h: int):
self.mSize = (w, h)
def draw(self):
print("my draw size is {}".format(self.mSize))
# decorator
class Decorator(Widget):
def __init__(self, widget: Widget):
self.mChildWindow = widget
def draw(self):
self.mChildWindow.draw()
class VScrollDecorator(Decorator):
def draw(self):
self.mChildWindow.draw()
print("Draw Vertical Scrollbar")
class HScrollDecorator(Decorator):
def draw(self):
self.mChildWindow.draw()
print("Draw Horizontal Scrollbar")
if __name__ == '__main__':
testWindow = VScrollDecorator(HScrollDecorator(ConcreteWindow(200,100)))
testWindow.draw()
output
my draw size is (200, 100)
Draw Horizontal Scrollbar
Draw Vertical Scrollbar
09 Nov 2016
|
python
pattern
Overview
다음은 내맘대로 그려본 Observer pattern 의 시나리오이다.
생각해보니 MVC패턴에 적용하면 Controller를 Observable, View를 Observer로 놓을 수 있겠다.
다음은 코드이다.
class Observable(object):
def __init__(self):
self.observers = []
def register(self, observer):
if not observer in self.observers:
self.observers.append(observer)
def unregister(self, observer):
if observer in self.observers:
self.observers.remove(observer)
def unregister_all(self):
if self.observers:
del self.observers[:] # list의 모든 항목을 지우는 코드. list는 남는다.
def update_observers(self, *args, **kwargs):
for observer in self.observers:
observer.update(*args, **kwargs)
from abc import ABCMeta, abstractmethod
class Observer(object):
__metaclass__ = ABCMeta
@abstractmethod
def update(self, *args, **kwargs):
pass
from Observable import Observable
from Observer import Observer
class AmericanStockMarket(Observer):
def update(self, *args, **kwargs):
print("American stock market received: {0}\n{1}".format(args, kwargs))
class EuropeanStockMarket(Observer):
def update(self, *args, **kwargs):
print("European stock market received: {0}\n{1}".format(args, kwargs))
if __name__ == "__main__":
observable = Observable()
american_observer = AmericanStockMarket()
observable.register(american_observer)
european_observer = EuropeanStockMarket()
observable.register(european_observer)
observable.update_observers('Market Rally', something='Hello World')
08 Nov 2016
|
python
pattern
Strategy pattern
알고리즘군을 정의하고 각각 캡슐화하여 바꿔쓸 수 있게 만든 패턴.
알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘이 변경 가능하다.
어떻게쓰나?
다수의 interface를 가지는 abstract class가 존재하고. 해당 class를 상속받아서 class를 디자인하는 방법이다.
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!