Python

[Python] SOLID 의존성 역전 원칙(DIP)

UnoCoding 2023. 2. 9. 13:11

SOLID  이란?

클린 코딩 디자인중 하나인 SOLID 원칙에 대해서 천천히 알아보자.

 

  • S: 단일 책임 원칙  
  • O: 개방/폐쇄의 원칙 
  • L: 리스코프 치환 원칙
  • I: 인터페이스 분리 법칙 👈 현위치
  • D: 의존성 역전 원칙 👈 현위치

 

의존성 역전

 

의존성 역전 원칙(Dependency Inversion Principle)는 코드가 깨지거나 손상되는 취약점으로 보호해준다.

 

의존성 원칙이란 쉽게 말해 "보다 고수준 모듈(클래스)은 보다 저수준 모듈(클래스)에 대해 의존하면 안된다는 것이고, 의존하지 않는다는 것은 저수준 모듈의 변경이나 추가 등에 있어서 변경점이 없어야 한다"

 

예제를 통해 알아보자

 

# DIP를 위반한 코드
class DBConnection:
    def __init__(self, db):
        self.db = db
        assert db is Mysql, "Only mysql is supported"

    def connect(self):
        self.db.connect()


class Mysql:
    def __init__(self, host, port, user, password):
        self.host = host
        self.port = port
        self.user = userㄴ
        self.password = password

    def connect():
        print("Connecting to mysql db")


class Postgres:
    def __init__(self, host, port, user, password):
        self.host = host
        self.port = port
        self.user = user
        self.password = password

    def connect():
        print("Connecting to postgres db")


db_conection1 = DBConnection(Mysql)
db_conection1.connect()
db_conection2 = DBConnection(Postgres)
db_conection2.connect()

실제로 예제코드 같은 상황은 드물겠지만 DIP를 이해를 돕기위해 작성되었으므로 이해 하길 바랍니다.

 

위 예제를 보면 DBConnection() 라는 고수준 클래스가 직접 Mysql이라는 저 수준의 크래스를 의존하고 있습니다.

 

코드를 실행해 보면 아래와 같은 결과가 나타나는 것을 볼 수 있습니다.

 

assert를 통해 강제성을 부여 하였기 때문에 발생한 에러지만, 실제 정적 언어에서는 에러가 발생합니다.

 

개선하기

from abc import abstractmethod


class DB:
    def __init__(self, host, port, user, password):
        self.host = host
        self.port = port
        self.user = user
        self.password = password

    @abstractmethod
    def connect(self):
        raise NotImplementedError("Subclass must implement abstract method")


class DBConnection:
    def __init__(self, db):
        self.db = db
        assert db in DB.__subclasses__(), "db must be a subclass of DB"

    def connect(self):
        self.db.connect()


class Mysql(DB):
    def connect():
        print("Connecting to mysql db")


class Postgres(DB):
    def connect():
        print("Connecting to postgres db")


db_conection1 = DBConnection(Mysql)
db_conection1.connect()
db_conection2 = DBConnection(Postgres)
db_conection2.connect()

DBConnection 클래스는 단지 DB 클래스와 관계를 가질뿐, 실제 구체적인 구현과는 의존성이 사라지게  됩니다.

 

위 코드를 실행 시키면 다음과 같이 동작함을 알 수 있습니다.

 

 

참고 사이트

DIP - https://doorbw.tistory.com/240