의존관계 역전 원칙

김지민·2023년 5월 29일
0

Solid

목록 보기
5/5

의존관계 역전 원칙 (Dependency Inversion Principle)

상위 계층 클래스들은 하위 계층 클래스들에 의존해서는 안됩니다

개념

객체에서 어떤 Class를 참조해서 사용하는 상황이 발생한다면 그 Class를 직접 참조하는 것이 아닌 그 대상의 상위요소(추상클래스 or 인터페이스)로 참조해야 한다

일반적으로 클래스는 다음 두 계층으로 분류가 가능하다

  • 하위 계층 클래스들은 디스크의 작업, 네트워크 통신 등과 같은 기본 작업을 구현한다
  • 상위 계층 클래스들은 하위 계층 클래스들이 무언가를 하도록 지시하는 복잡한 비즈니스 로직을 포함한다

새 시스템에서 개발을 시작할때 보통은 하위 계층 클래스들은 먼저 디자인 한 다음 상위 계층 클래스들을 디자인 하기 시작한다
이는 해당 시점에 하위 계층 기능들이 구현되지 않았거나 명확하지 않기 때문에 상위 계층에서 무엇이 가능한지 확신할 수 없기 때문이다
이러한 접근 방식은 비즈니스 로직 클래스들이 하위 계층 클래스들에 의존하게 되는 경향이 있다
이렇게 될 경우 하위 계층에 변화가 있을 때마다 클라이언트 혹 상위 계층의 코드를 자주 수정해야 한다

의존관계 역전 원칙은 이러한 의존 관계의 방향을 바꾸는 것이다

1. 상위계층 클래스가 의존하는 하위계층 작업의 인터페이스를 되도록 비즈니스 용어를 사용해 설명해야 한다
2. 구상 하위 계층 클래스 대신 이러한 인터페이스에 의존하는 상위 계층 클래스들을 만들 수 있다
3. 하위 계층 클래스들이 이러한 인터페이스들을 구현하면 이들은 비즈니스 로직 계층에 의존하게 되어 원래 의존관계의 
   방향이 역전된다

코드 예시

잘못된 예시

class Bus { 
	var str = "버스"
}

class Commute {
	var bus: Bus?
    
	func boarding(bus: Bus) {
    	self.bus = bus
    }
    
    func goToWork() {
    	if let bus = bus {
    		print("\(bus.str)을(를) 타고 출근")
        } else {
        	print("걸어서 출근")
        }
    }
}

위 상황에서 Commute(상위계층)은 Bus(하위계층)라는 구체적인 객체에 의존하고 있다
만약 버스를 놓쳐서 택시를 타는경우 Commute 클래스를 수정해줘야 한다

class Bus {
	var str = "버스"
}

class Taxi {
	var str = "택시"
}

class Commute {
	var bus: Bus?
    var taxi: Taxi?
    
    func boarding(bus: Bus) {
    	self.bus = bus
    }
    
    func boarding(taxi: Taxi) {
    	self.taxi = taxi
    }
    
    func goToWork() {
    	if let bus = bus {
        	print("\(bus.str)을(를) 타고 출근")
        } else if let taxi = taxi {
			print("\(taxi.str)을(를) 타고 출근")
        } else {
        	print("걸어서 출근")
        }
    }
}

Commute라는 상위계층 클래스가 변하기 쉬운 하위계층에 의존하게 되면 하위계층 변화의 영향에 직접적으로 노출된다
따라서 탈 수 있는 대중교통이 늘때마다 Commute클래스는 계속해서 수정될것이다

옳게된 예시

protocol PublicTransport {
	var str: String { get }
}

class Bus: PublicTransport {
	var str = "버스"
}

class Taxi: PublicTransport {
	var str = "택시"
}

class Commute {
	var publicTransport: PublicTransport?
    
    func boarding(publicTransport: PublicTransport) {
    	self.publicTransport = publicTransport
    }
    
    func goToWork() {
    	if let pt = publicTransport {
        	print("\(publicTransport.str)을(를) 타고 출근")
        } else {
        	print("걸어서 출근")
        }
	}
}

더이상 Commute 클래스는 구체적인 객체들에 의존하지 않는다
대신 PublicTransport라는 추상적인 개념에 의존하고 있다

이제 탈수있는 대중교통이 늘더라도 하위계층 클래스가 PublicTransport를 채택하고 있는 이상 Commute 객체를 수정하지 않더라도 문제가 없을것이다

의존관계 역전 원칙은 종종 개방/폐쇄 원칙과 함께 진행된다
당신은 하위 계층 클래스를 확장하여 기존 클래스들을 손상하지 않고 다른 비즈니스 로직 클래스들과 함께 사용할 수 있다


하위 계층의 클래스가 상위 계층의 추상화에 의존하는것이 의존관계 역전 원칙의 핵심이다

profile
iOS 신입으로 일하고 있습니다

0개의 댓글