-
[파이썬] 전략 패턴, 의존성 주입Python/이것저것 파이썬 2022. 8. 16. 10:26반응형
0.
'기차는 레일로 이동하고,
버스는 차로로 이동한다.'
는 결과를 만들기 위해
다음과 같이 코드를 작성했습니다.from abc import ABCMeta, abstractmethod class Vehicle(metaclass=ABCMeta): @abstractmethod def move(self): pass class Train(Vehicle): def move(self): print("레일로 이동") class Bus(Vehicle): def move(self): print("차로로 이동") train = Train() bus = Bus() train.move() bus.move()
그런데 버스가 하늘을 나는 시대가 된다면...
다음과 같이 수정을 해야겠죠?class Bus(Transport): def move(self): print("하늘로 이동")
이렇게 수정하지 않고
시스템을 확장해서
처리할 방법은 없을까요?이런 경우에 전략 패턴을 사용합니다.
전략 패턴은
여러 알고리듬을
각각의 클래스 안에 넣어서
교체하기 쉽도록 만들어진
패턴입니다.위 예제에서는 이동 방법이
알고리듬에 해당되겠죠.1.
각 운송 수단(Vehicle)에 코딩되어 있던 이동 방법(move())을
TransportStrategy(운송 전략)이라는 클래스로 묶어내고,
SkyTransport 클래스를 추가합니다.from abc import ABCMeta, abstractmethod class TransportStrategy(metaclass=ABCMeta): @abstractmethod def move(self): pass class RailRoadTransport(TransportStrategy): def move(self): print("레일로 이동") class RoadTransport(TransportStrategy): def move(self): print("도로로 이동") class SkyTransport(TransportStrategy): def move(self): print("하늘로 이동")
2.
각 운동 수단의 move() 메서드를
Vehicle(운송수단) 클래스에 묶어 내고
운송 전략을 설정하는 메서드
(set_transport_strategy())를 만듭니다.class Vehicle: def __init__(self): self._transport_strategy = None def set_transport_strategy(self, transport_strategy: TransportStrategy): self._transport_strategy = transport_strategy def move(self): self._transport_strategy.move() class Train(Vehicle): pass class Bus(Vehicle): pass
3.
전체 코드
from abc import ABCMeta, abstractmethod class TransportStrategy(metaclass=ABCMeta): @abstractmethod def move(self): pass class RailRoadTransport(TransportStrategy): def move(self): print("레일로 이동") class RoadTransport(TransportStrategy): def move(self): print("도로로 이동") class SkyTransport(TransportStrategy): def move(self): print("하늘로 이동") class Vehicle: def __init__(self): self._transport_strategy = None def set_transport_strategy(self, transport_strategy: TransportStrategy): self._transport_strategy = transport_strategy def move(self): self._transport_strategy.move() class Train(Vehicle): pass class Bus(Vehicle): pass train = Train() bus = Bus() train.set_transport_strategy(RailRoadTransport()) bus.set_transport_strategy(RoadTransport()) train.move() # 레일로 이동 bus.move() # 도로로 이동 bus.set_transport_strategy(SkyTransport()) bus.move() # 하늘로 이동
4.
전략 패턴 = 의존성 주입.
객체 지향 프로그래밍에서는,
객체의 상호 작용을 통해 프로그램을 만듭니다.그렇기 때문에
객체 간의 의존성이 발생할 수 밖에 없습니다.의존성 주입은
이 의존성을 약하게(=결합도를 느슨하게) 만들어
프로그램을 유연하게 만듭니다.의존성 주입이란,
구체적인 클래스에 의존하지 않고,
인터페이스에 의존하도록 만드는 것입니다.위 코드에서...
Vehicle 클래스가 TransportStrategy 클래스에 의존성이 있지만,
Vehicle 클래스는 TransportStrategy의 구체적인 클래스에 의존하지 않고,
TransportStrategy 클래스의 인터페이스(파이썬에서는 추상 클래스)에 의존합니다.다른 표현으론....
외부에서 Vehicle과
구체적인 TransportStrategy
(RailRoadTransport, RoadTransport, SkyTransport)
의 의존 관계를 설정할 수 있도록 만드는 것(=의존의 역전)이
의존성 주입입니다.5.
장점
기존 클래스의 내부를 수정하지 않아도 됩니다,
클래스의 추가로 기능을 추가할 수 있습니다.=> 최소한의 수정으로 기능을 추가할 수 있습니다
=> 유연합니다.
주된 제어 흐름에서 세부적인 요소까지 설정할 수 있습니다.
=> 가독성이 좋아집니다.
==> 유지보수가 편리해집니다.
------------------------------------------------
엄격한 객체 지향 방법론은 아니지만,
제 개인 프로젝트라면 이 정도로...from typing import Callable # 함수의 타입 어노테이션(type annotation)을 위해 class TransportStrategy: @staticmethod def rail(): print("레일로 이동") @staticmethod def road(): print("도로로 이동") @staticmethod def sky(): print("하늘로 이동") class Vehicle: def __init__(self, transport_strategy_method: Callable): # 함수도 일등 시민 self._move = transport_strategy_method def move(self): self._move() class Train(Vehicle): pass class Bus(Vehicle): pass train = Train(TransportStrategy.rail) # 함수도 일등 시민 bus = Bus(TransportStrategy.road) train.move() bus.move() bus = Bus(TransportStrategy.sky) bus.move()
전략 패턴에서는
다양한 전략(알고리듬)을 인수로 전달하여,
다양한 전략을 선택할 수 있도록 합니다.자바는 함수를 인수로 전달할 수 없기 때문에,
(알고리듬을 담고 있는) 함수를 담고 있는 클래스를
인수로 전달합니다.파이썬에서는 함수도 인수로 사용할 수 있습니다.
따라서,
알고리듬을 담고 있는 함수를 인수로 직접 전달하면
좀 더 단순하게 전략 패턴을 이용할 수 있습니다.반응형