소프트웨어에 대한 모든 것

[디자인패턴][SOLID] 의존성 역전 법칙 본문

시스템 설계 및 디자인/객체지향 SOLID

[디자인패턴][SOLID] 의존성 역전 법칙

앤테바 2022. 3. 24. 08:16
반응형

의존성 역전 법칙 (Dependency Inversion Principle)

  • 고차원 모듈은 저차원 모듈에 의존하지 말아야한다. --> 상위클래스는 하위 클래스에 의존해서는 안된다는 원칙
  • 변경이 잦은 Concrete 클래스에 의존하지 말고 인터페이스나 추상 클래스에 의존 관계를 맺도록 설계

의존성 역전 법칙은 클래스들 사이에 abstraction layer를 생성해서 클래스 사이의 커플링을 줄이는 것을 목표로 한다.

 

의존성 역전 법칙 예시

외환 거래 예시를 통해서 의존성 역전 법칙에 대해서 알아 봅니다.

 

class FXConverter:
    def convert(self, from_currency, to_currency, amount):
        print(f'{amount} {from_currency} = {amount*1.2} {to_currency}')
        return amount *1.2


class App:
    def start(self):
        converter = FXConverter()
        converter.convert('EUR', 'USD', 100)


app = App()
app.start()

App과 FXConverter 클래스 두 개가 존재합니다.

App은 start() 함수를 제공하고 start() 함수를 호출하면 FXConverter() 인스턴스를 생성해서 'EUR'을 'USD'로 변환하는 함수를 호출합니다. FXConverter은 convert() 함수를 제공하며 통화와 양에 따라 적절한 금액으로 환전금 금액을 리턴하는 함수를 제공합니다. FXConvert는 외환 거래 API를 제공하는 서비스라고 보시면 될 것 같습니다.

 

만약 미래에 FX's API가 변경 된다면 코드를 수정해야 하며 이는 App 클래스의 변경도 유발하게 됩니다. 이를 방지하려면 FXConverter 클래스가 App 클래스에 적응하도록 의존성을 반전해야 합니다.

 

CurrencyConverter 추상 클래스를 추가하고, App은 CurrencConverter 추상 클래스에 의존하면 FXConverter는 CurrencyConverter를 상속 받는 구조로 변경합니다. 기존에는 App에서 FXConverter에 의존하는 화살표가 하나 있었지만 바뀐 디자인에서는 App도 CurrencyConverter에 의존하고, FXConverter에 의존하는 (화살표가 한 방향이 아닌 동시에 CurrencyConverter를 향하는) 의존성 역전 법칙을 준수하는 모양입니다.

from abc import ABC, abstractmethod


class CurrencyConverter(ABC):
    @abstractmethod
    def convert(self, from_currency, to_currency, amount):
        pass


class FXConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount):
        print(f'{amount} {from_currency} = {amount*1.2} {to_currency}')
        return amount *1.2


class App:
    def __init__(self, converter):
        self.converter = converter

    def start(self):
        self.converter.convert('EUR', 'USD', 100)


converter = FXConverter()
app = App(converter)
app.start()

 

환전에 대한 새로운 요구 사항이 발생해도 CurrencyConverter를 상속받은 AlphaConverter를 추가하면 되기 때문에 App 클래스는 변경이 발생하지 않습니다.

from abc import ABC, abstractmethod


class CurrencyConverter(ABC):
    @abstractmethod
    def convert(self, from_currency, to_currency, amount):
        pass


class FXConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount):
        print('FX API')
        print(f'{amount} {from_currency} = {amount* 1.2} {to_currency}')
        return amount * 1.2


class AlphaConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount):
        print('Alpha API')
        print(f'{amount} {from_currency} = {amount*2.5} {to_currency}')
        return amount * 2.5


class App:
    def __init__(self, converter):
        self.converter = converter

    def start(self):
        self.converter.convert('EUR', 'USD', 100)


converter = AlphaConverter()
app = App(converter)
app.start()

요약

  • 구체 클래스가 아닌 상위 수준 모듈을 만들어 코드를 더욱 강력하게 만들어라
  • 의존 관계를 맺을 때 변화화기 쉬운 또는 자주 변화되는 것 보다는 변화하기 어렵고 거의 변화가 없는 것에 의존하라는 원칙 (추상 클래스에 의존하라!)

참고 자료

Python Dependency Inversion Principle

SOLID(4) - 의존 역전 원칙, DIP

반응형
Comments