⛳️ 인프런 - cs 지식의 정석 강의를 듣고 학습한 내용입니다.
A가 B에 의존한다는 것은,
import java.util.*;
class B {
public void go() {
System.out.println("B의 go()함수");
}
}
class A {
public void go() {
new B().go();
}
}
public class main{
public static void main(String args[]) {
new A().go();
}
}
위 코드에서, class B의 go() 메서드의 이름이 gorani()로 바뀐다면 class A의 코드를 new B().gorani()
로 수정해줘야 한다. 이런걸 의존한다고 함.
여러 하위 모듈들이 메인 모듈에 직접적으로 의존하지 않도록, 그 중간에 의존성 주입자를 넣어 하위 모듈들이 이 중간 모듈(주입자)에 의존하도록 만드는 것이다.
이를 통해 메인 모듈과 하위 모듈들간의 의존성을 조금 더 느슨하게 만들 수 있고, 쉽게 교체 가능한 구조로 만든다.
SOLID 원칙 중 D에 해당하는 부분이다.
의존성 역전 원칙은,
개발을 할 때 저수준 모듈은 빈번하게 변경되는데, 고수준 모듈이 저수준 클래스에 의존하고 있다면 고수준 클래스가 자주 영향을 받게 된다. 따라서 의존관계를 역전시켜야 하는데, 이를 의존성 역전이라고 한다.
예시를 통해 확인해보자.
import java.util.*;
// 하위 클래스
class BackendDeveloper {
// Backend 개발자는 Java 코드를 작성하는 메서드만 제공
public void writeJava() {
System.out.println("자바가 좋아 인터네셔널~");
}
}
class FrontEndDeveloper {
// Frontend 개발자는 JavaScript 코드를 작성하는 메서드만 제공
public void writeJavascript() {
System.out.println("자바스크립트가 좋아 인터네셔널~");
}
}
// 상위 클래스
public class Project {
// BackendDeveloper와 FrontEndDeveloper에 직접 의존
private final BackendDeveloper backendDeveloper;
private final FrontEndDeveloper frontEndDeveloper;
// 의존성을 직접 주입받음 (강하게 결합됨)
public Project(BackendDeveloper backendDeveloper, FrontEndDeveloper frontEndDeveloper) {
this.backendDeveloper = backendDeveloper;
this.frontEndDeveloper = frontEndDeveloper;
}
public void implement() {
backendDeveloper.writeJava(); //
frontEndDeveloper.writeJavascript();
}
// main
public static void main(String args[]) {
// Project가 구체적인 구현에 의존하며, 직접 개발자 객체를 생성
Project a = new Project(new BackendDeveloper(), new FrontEndDeveloper());
a.implement(); // Backend와 Frontend의 구현 메서드 호출
}
}
위의 경우,
이런 상황이니 확장과 유지보수가 어렵다.
의존성 역전 원칙을 적용하면 다음과 같이 코드를 개선할 수 있다.
import java.util.*;
// 개발자 인터페이스: 고수준 모듈이 의존하는 추상화
interface Developer {
void develop(); // 개발자가 수행해야 할 작업 정의
}
// Backend 개발자 클래스: Developer 인터페이스 구현
class BackendDeveloper implements Developer {
@Override
public void develop() {
writeJava();
}
public void writeJava() {
System.out.println("자바가 좋아~ 새삥새삥");
}
}
// Frontend 개발자 클래스: Developer 인터페이스 구현
class FrontendDeveloper implements Developer {
@Override
public void develop() {
writeJavascript();
}
public void writeJavascript() {
System.out.println("자바스크립트가 좋아~ 새삥새삥");
}
}
// 프로젝트 클래스: 고수준 모듈
public class Project {
private final List<Developer> developers; // 추상화(Developer 인터페이스)에 의존
// 의존성 주입: 개발자 목록을 생성자로 받아옴
public Project(List<Developer> developers) {
this.developers = developers;
}
public void implement() {
developers.forEach(Developer::develop); // 모든 개발자에게 develop() 호출
}
// main
public static void main(String args[]) {
List<Developer> dev = new ArrayList<>();
dev.add(new BackendDeveloper());
dev.add(new FrontendDeveloper());
// Project 객체 생성 (의존성 주입)
Project a = new Project(dev);
// 프로젝트 구현
a.implement();
// 자바가 좋아~ 새삥새삥
// 자바스크립트가 좋아~ 새삥새삥
}
}
1. 추상화 사용
Developer
라는 인터페이스를 도입하여 고수준 모듈인 Project
가 구체적인 구현에 의존하지 않게 설계2. 의존성 주입
class iOSDeveloper implements Developer {
@Override
public void develop() {
writeSwift();
}
public void writeSwift() {
System.out.println("스위프트가 좋아 새삥새삥");
}
}