๋ฐ์ํ
Strategy Pattern
์คํธ๋ํฐ์ง ํจํด(Strategy Pattern)์ ํ์ ํจํด(Behavioral Pattern)์ ์ผ์ข ์ผ๋ก, ์๊ณ ๋ฆฌ์ฆ ๊ตฐ์ ์ ์ํ๊ณ , ๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ์บก์ํํ๋ฉฐ, ์ด๋ค์ ์ํธ ๊ตํ ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ํจํด์ ๋๋ค.
- ์ฆ, ์๊ณ ๋ฆฌ์ฆ์ ํด๋ผ์ด์ธํธ์์ ๋ถ๋ฆฌํ์ฌ ๋ ๋ฆฝ์ ์ผ๋ก ๋ณ๊ฒฝํ ์ ์๊ฒ ํฉ๋๋ค.
- ์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ ์ฝ๋์ ๋ณ๊ฒฝ ์์ด ์๊ณ ๋ฆฌ์ฆ์ ์ฝ๊ฒ ๊ต์ฒดํ ์ ์์ต๋๋ค.
- Runtime ์ค์ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ๊ฒ ํฉ๋๋ค.
- ํ๋์ ์๊ณ ๋ฆฌ์ฆ์ ์ง์ Implementing ํ๋ ๋์ ์ด๋ ํ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ ์ง Runtime Instruction์ ๋ฐ์ต๋๋ค.
- Animal์ ๋ฐ์์ Speaking์ ์ํค๋ ํจ์
- ๋๋ฌผ์ ๊ณ ์์ด ํน์ ์ฌ์
- ๊ณ ์์ด๊ฐ ๋ค์ด์ค๋ฉด “meow”
- ์ฌ์๊ฐ ๋ค์ด์ค๋ฉด “roar”
- ํจ์๋ ์ด ์ํ๋ก ๊ณ ์ ์ด ๋ ์ํ์ด๋ฉฐ ์ด๋ค ๋๋ฌผ์ด ์ด๋ค๋ง์ ํ์ง๋ Runtime์ ๊ฒฐ์ ๋ฉ๋๋ค.
class Animal:
def speak(self):
pass
class Cat(Animal):
def speak(self):
print("meow")
class Lion(Animal):
def speak(self):
print("roar")
def makeSpeak(animal: Animal):
animal.speak()
def createAnimal(input_str: str) -> Animal:
if input_str == "cat":
return Cat()
elif input_str == "lion":
return Lion()
- Animal class
- Base Interface
- speak ํจ์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- Cat class
- Animal ์์๋ฐ๊ณ
- speak๋ฅผ ํตํด "meow" ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
- Lion class
- Animal ์์๋ฐ์
- speak๋ฅผ ํตํด "roar" ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
- makeSpeak()
- argument๋ก Animal Interface ๋ฅผ ๋ฐ์ต๋๋ค.
- Animal.speak()๋ฅผ ํตํด ๋ง์ ํ๊ฒ ํฉ๋๋ค.
- createAnimal()
- argument๋ก string ํํ์ input_str ๋ฐ๊ณ Animal object return ํฉ๋๋ค.
- input_str์ด "cat"์ผ ๊ฒฝ์ฐ Cat object return
- input_str์ด "lion"์ผ ๊ฒฝ์ฐ Lion object return
# ์ฌ์ฉ ์์
input_str = input('choose animal: ')
animal = createAnimal(input_str)
makeSpeak(animal)
# ์คํ ๊ฒฐ๊ณผ
# choose animal: cat
# meow
# choose animal: lion
# roar
- ์ฌ์ฉ ์์
- Runtime์ input์ ๋ฐ์ ์ ์๋ ๋ณ์์ธ input_str
- createAnimal์ ํตํด input_str์ ๋ฐ๋ผ animal์ ์์ฑํฉ๋๋ค.
- ๊ทธ ๋ค์ animal์๊ฒ makeSpeak์ ํตํด ๋ง์ ๊ฒ๋๋ค.
- ์๋จ ์ฝ๋ ์คํ์ํค๋ฉด Runtime ์ค์ ์ด๋ค ๋๋ฌผ์ ๋ฐ์์ง ๋ฌผ์ด๋ด ๋๋ค.
- ๊ฒฐ๊ณผ
- input_str์ด "cat"์ด๋ฉด "meow"
- input_str์ด "lion"์ด๋ฉด "roar"
- ๋ฐํ์ ์ค์ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ์ฌ ๊ฐ์ฒด ๋์์ ์ค์๊ฐ์ผ๋ก ์ ์ฉํ ์ ์์ต๋๋ค.
- ์ ๋ต์ด๋ ๊ธฐ๋ฅ, ๋์, ์๊ณ ๋ฆฌ์ฆ ๋ฑ ํน์ ํ ๋ชฉํ๋ฅผ ์ํํ๊ธฐ ์ํ ํ๋์ ์๋ฏธํฉ๋๋ค.
- ์๊ณ ๋ฆฌ์ฆ ๋ณ๊ฒฝ์ด ๋น๋ฒํ๊ฒ ํ์ํ ๊ฒฝ์ฐ์ ์ ํฉํฉ๋๋ค.
- Strategy: ์ ๋ต์ ์ด์ฉํ๊ธฐ ์ํ APi๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
- ConcreteStrategy: API๋ฅผ ์ค์ ๋ก ๊ตฌํํ๋ฉฐ, ์ฌ๊ธฐ์ ๊ตฌ์ฒด์ ์ธ ์ ๋ต (์์ , ๋ฐฉ์ฑ , ๋ฐฉ๋ฒ, ์๊ณ ๋ฆฌ์ฆ)์ ์ค์ ๋ก ํ๋ก๊ทธ๋๋ฐํฉ๋๋ค.
- Context: Strategy๋ฅผ ๋ด์๋ด๊ณ ์ด์ฉํ๋ ์ญํ ์ ํ๋๋ฐ, ConcreteStrategy์ ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ํ์์ ๋ฐ๋ผ ๊ทธ๊ฒ์ ์ด์ฉํฉ๋๋ค.
from abc import *
class IStrategy(metaclass=ABCMeta):
@abstractmethod
def doSomething(self):
pass
class ConcreteStrategyA(IStrategy):
def doSomething(self):
print("do something using A")
class ConcreteStrategyB(IStrategy):
def doSomething(self):
print("do something using B")
class Context:
def __init__(self):
self.strategy = 0 # ์ถ์ํ๋ ์ ๋ต์ ๊ฐ์ง๊ณ ์์
def setStrategy(self, stgy: IStrategy):
self.strategy = stgy # ์ค์ ๋ ์ ๋ต์ ๋ฐ๋ผ ํ๋ํจ
def do(self):
self.strategy.doSomething()
# ํด๋ผ์ด์ธํธ ์ฝ๋
context = Context()
context.setStrategy(ConcreteStrategyA())
context.do()
context.setStrategy(ConcreteStrategyB())
context.do()
- ์ ๋ต ์๊ณ ๋ฆฌ์ฆ์ ์ฌ๋ฌ ๋ฒ์ ๋๋ ๋ณํ์ด ํ์ํ ๋ ํด๋์ค๋ฅผ ํตํด ๊ด๋ฆฌํฉ๋๋ค.
- ์๊ณ ๋ฆฌ์ฆ์ ์ฝ๋๊ฐ ๋ ธ์ถ ๋์ด์๋ ์๋๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํฉ๋๋ค.
- ์๊ณ ๋ฆฌ์ฆ์ ๋์์ด ๋ฐํ์์ ์ค์๊ฐ์ผ๋ก ๊ต์ฒด๋์ด์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
Strategy Pattern์ ์ฌ์ฉํ์ง ์์ ์ฌ๋ก
weapon = {
"SWORD": 0,
"SHIELD": 1,
"CROSSBOW": 2
}
class TakeWeapon:
def __init__(self):
self.state = 0
def setState(self, state):
self.state = state
def attack(self):
if self.state == weapon["SWORD"]:
print("๊ฒ์ ํ๋๋ฅด๋ค")
elif self.state == weapon["SHIELD"]:
print("๋ฐฉํจ๋ก ๋ฐ์น๋ค")
elif self.state == weapon["CROSSBOW"]:
print("์๊ถ์ ์๋ค")
# ํ๋ ์ด์ด ์์ ๋ฌด๊ธฐ ์ฐฉ์ฉ ์ ๋ต์ ์ค์
hand = TakeWeapon()
# ํ๋ ์ด์ด๊ฐ ๊ฒ์ ๋ค๋๋ก ์ ๋ต ์ค์
hand.setState(weapon["SWORD"])
hand.attack() # "๊ฒ์ ํ๋๋ฅด๋ค"
# ํ๋ ์ด์ด๊ฐ ๋ฐฉํจ๋ฅผ ๋ค๋๋ก ์ ๋ต ๋ณ๊ฒฝ
hand.setState(weapon["SHIELD"])
hand.attack() # "๋ฐฉํจ๋ก ๋ฐ์น๋ค"
# ํ๋ ์ด์ด๊ฐ ์๊ถ์ ๋ค๋๋ก ์ ๋ต ๋ณ๊ฒฝ
hand.setState(weapon["CROSSBOW"])
hand.attack() # "์๊ถ์ ์๋ค"
- TakeWeapon ํด๋์ค๋ ํ์ ๋ฉ์๋(ํจ์)์ ์์กด๋์ด ์์ผ๋ฉฐ, ๊ณต๊ฒฉ ๋ฐฉ๋ฒ์ด ์ถ๊ฐ๋๋ฉด TakeWeapon ํด๋์ค๋ ์์ ํด์ผ ํ๋ฏ๋ก if else ๊ตฌ๋ฌธ์ด ๋ง์์ง ์ ์์ต๋๋ค.
Strategy Pattern์ ์ฌ์ฉํ ์ฌ๋ก
# Strategy pattern implementation using DIP and polymorphism
class TakeWeaponStrategy:
def __init__(self):
self.weapon = 0
def setWeapon(self, weapon: Weapon):
self.weapon = weapon
def attack(self):
self.weapon.offensive()
# Abstract Weapon class
from abc import *
class Weapon(metaclass=ABCMeta):
@abstractmethod
def offensive(self):
pass
# Concrete Weapon classes implementing the abstract Weapon class
class Sword(Weapon):
def offensive(self):
print("์นผ์ ํ๋๋ฅด๋ค")
class Shield(Weapon):
def offensive(self):
print("๋ฐฉํจ๋ก ๋ฐ์น๋ค")
class CrossBow(Weapon):
def offensive(self):
print("์๊ถ์ ์๋ค")
# Setting the strategies for the player
hand = TakeWeaponStrategy()
hand.setWeapon(Sword())
hand.attack() # ์นผ์ ํ๋๋ฅด๋ค
hand.setWeapon(Shield())
hand.attack() # ๋ฐฉํจ๋ก ๋ฐ์น๋ค
hand.setWeapon(CrossBow())
hand.attack() # ์๊ถ์ ์๋ค
- Dependency Inversion Principle(DIP) ๋ฐ ๋คํ์ฑ์ ํตํ ์ค์๊ฐ ๊ณต๊ฒฉ ์ ๋ต์ ๊ต์ฒด๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- TakeWeaponStrategy ํจ์ ์์ ์ด ํ์ ์์ต๋๋ค.
์คํ์ค์ ๊ต์ฒด๋ ๊ฐ๋ฅ
- Strategy ํจํด์ ์ฌ์ฉํ๋ฉด ํ๋ก๊ทธ๋จ์ ๋์ ์ค์ ConcreteStrategy ์ญํ ์ ํด๋์ค๋ฅผ ๊ต์ฒดํ ์๋ ์์ต๋๋ค.
- ๊ฐ๋ น, ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ์ ํ๊ฒฝ์์๋ Slow but Less Memory Strategy๋ฅผ ์ฌ์ฉํ๊ณ , ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ง์ ํ๊ฒฝ์์๋ Fast but More Memory Strategy๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ ์๊ฐํด๋ณผ ์ ์์ต๋๋ค.
- ๋๋ ๋ณต์กํ ๊ณ์ฐ์ด ํ์ํ ํ์คํฌ๊ฐ ์๋ค๊ณ ๊ฐ์ ํ ๋,
- ๋ฒ๊ทธ๊ฐ ์์์ง๋ ๋ชจ๋ฅด๋ ๊ณ ์์ ์๊ณ ๋ฆฌ์ฆ vs ์ ์์ด์ง๋ง ํ์คํ ๊ณ์ฐ์ ์คํํ๋ ์๊ณ ๋ฆฌ์ฆ ์ ๋๋ค.
์ผ๋ถ๋ฌ Strategy Pattern์ ๋ง๋ค ํ์๊ฐ ์์๊น?
๋ณดํต ํ๋ก๊ทธ๋๋ฐ์ ํ ๋ ๋ฉ์๋ ๋ด๋ถ์ ๋ํ๋ ํํ๋ก ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํ๊ธฐ ์ฝ์ต๋๋ค.
- ๊ทธ๋ฌ๋, Strategy ํจํด์์๋ ์๊ณ ๋ฆฌ์ฆ์ ๋ถ๋ถ์ ๋ค๋ฅธ ๋ถ๋ถ๊ณผ ์์์ ์ผ๋ก ๋ถ๋ฆฌํด์ ์๊ณ ๋ฆฌ์ฆ์ API๋ถ๋ถ๋ง์ ๊ณ ์ ํฉ๋๋ค.
- ๊ทธ๋ฆฌ๊ณ , ํ๋ก๊ทธ๋จ์์ ์์์ ์ํด ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํฉ๋๋ค.
- ์ด๊ฒ์ ํ๋ก๊ทธ๋จ์ ๋ณต์กํ๊ฒ ๋ง๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ์ค์ ๋ก๋ ๊ทธ๋ ์ง ์์ต๋๋ค.
- ์๋ฅผ ๋ค์ด, ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ๋ํด์ ์กฐ๊ธ ๋ ๋น ๋ฅด๊ฒ ํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด๋ณด๋ฉด, Strategy ํจํด์ ์ฌ์ฉํ๋ฉด Strategy ์ญํ ์ API๋ฅผ ๋ณ๊ฒฝํ์ง ์๋๋ก ์ฃผ์ํ๊ณ ConcreteStrategy์ ์ญํ ๋ง์ ์์ ํ๋ฉด ๋ฉ๋๋ค.
- ๋์ฑ์ด ์์์ด๋ผ๋ ๋์จํ ์ฐ๊ฒฐ์ ์ฌ์ฉํ๊ณ ์์ผ๋ฏ๋ก ์๊ณ ๋ฆฌ์ฆ์ ์ฉ์ดํ๊ฒ ๊ตํํ ์ ์๊ณ , ๊ฐ๋ น ์๋์ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๊ฐ์ ํ ์๊ณ ๋ฆฌ์ฆ์ ์๋๋ฅผ ๋น๊ตํ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ๊ฐ๋จํ๊ฒ ๊ต์ฒดํด์ ์ํํ ์ ์์ต๋๋ค.
๋ฐ์ํ
'๐บ๏ธ Design Pattern' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Design Pattern] Chain of Responsibility (0) | 2024.06.09 |
---|---|
[Design Pattern] Command Pattern - ์ปค๋งจ๋ ํจํด (0) | 2024.06.09 |
[Design Pattern] Composite Pattern - ์ปดํฌ์งํธ ํจํด (0) | 2024.06.08 |
[Design Pattern] Flyweight Pattern - ํ๋ผ์ด์จ์ดํธ ํจํด (0) | 2024.06.06 |
[Design Pattern] Bridge Pattern - ๋ธ๋ฆฟ์ง ํจํด (0) | 2024.06.06 |