The Office Lover
의존 역전 원칙 - dependency inversion principle 본문
소개
단일 책임 원칙과 개방 폐쇄 원칙은 이론적으로는 이해하기 쉬울 수 있지만 실제로 사용하는 데 어려움이 있습니다. 반면 의존 역전 원칙은 사용하기는 쉬우나 이해하는데 어려울 수 있습니다.
2023.07.27 - [Design Patterns] - 단일 책임 원칙 - single responsibility principle, SRP
2023.06.08 - [Design Patterns] - 디자인 패턴 - 개방 폐쇄 원칙
의존성 주입과 의존 역전이란?
1. 의존성 주입(Dependency Injection)
- 의존성(Dependency)은 한 클래스나 모듈이 다른 클래스나 모듈에 의존하는 것을 의미합니다. 이것은 한 요소의 변경이 다른 요소에 영향을 미칠 수 있다는 것을 나타냅니다.
- 의존성 주입(Dependency Injection)은 특정한 프로그래밍 기술로써 이해하거나 적용하기 쉽고 매우 유용합니다.
- 의존성 주입을 한 문장으로 요약하면 new 예약어를 사용하여 클래스 내부에 종속되는 클래스의 객체를 생성하는 대신, 외부에서 종속 클래스의 객체를 생성한 후 생성자, 함수의 매개변수 등을 통해 클래스에 주입하는 것을 의미합니다.
2. 의존 역전(Dependency Inversion)
- 의존 역전(Dependency Inversion)은 상위 모듈이 하위 모듈에 의존하지 않도록 하며, 두 모듈 모두 추상화에 의존하도록 설계하는 원칙입니다. 즉, 상세한 구현이 아니라 추상화에 의존함으로써 모듈 간의 결합도를 낮추고 유연성을 높입니다.
- 상위 모듈과 하위 모듈의 구분은 간단히 말하자면 호출자는 상위 모듈에 속하고, 수신자는 하위 모듈에 속합니다.
- Tomcat을 예로 들어보면 Tomcat은 자바 웹 애플리케이션을 실행하기 위한 컨테이너입니다. 웹 애플리케이션 코드는 Tomcat 컨테이너에 배포만 하면 별도의 작업이 필요 없이 Tomcat 컨테이너에서 호출하고 실행할 수 있습니다. 여기서 상위 모듈이 Tomcat이고 하위 모듈이 웹 애플리케이션에 해당됩니다. 둘 사이에는 직접적인 의존성이 없고 동일한 추상인 서블릿 사양에 의존합니다.
[비효율적인 초기 코드 설계 예시]
class MessageSender {
public void sendMessage(String message) {
// 메시지 전송 로직
}
}
class MessageReceiver {
public String receiveMessage() {
// 메시지 수신 로직
}
}
class Application {
private MessageSender sender;
private MessageReceiver receiver;
public Application() {
sender = new MessageSender();
receiver = new MessageReceiver();
}
public void run() {
String message = receiver.receiveMessage();
sender.sendMessage(message);
}
}
위 예시에서는 Application 클래스가 MessageSender와 MessageReceiver에 의존하고 있습니다. 이는 의존성이 상세한 구현에 직접적으로 연결되어 있어 유연성이 떨어집니다.
[의존 역전을 적용한 코드 설계 예시]
interface MessageService {
void sendMessage(String message);
String receiveMessage();
}
class MessageSender implements MessageService {
@Override
public void sendMessage(String message) {
// 메시지 전송 로직
}
@Override
public String receiveMessage() {
throw new UnsupportedOperationException("Sender cannot receive messages");
}
}
class MessageReceiver implements MessageService {
@Override
public void sendMessage(String message) {
throw new UnsupportedOperationException("Receiver cannot send messages");
}
@Override
public String receiveMessage() {
// 메시지 수신 로직
}
}
class Application {
private MessageService service;
public Application(MessageService service) {
this.service = service;
}
public void run() {
String message = service.receiveMessage();
service.sendMessage(message);
}
}
위 예시는 Application 클래스가 MessageService 인터페이스에만 의존하도록 변경되었습니다. 이를 통해 상위 모듈(Application)과 하위 모듈(MessageSender, MessageReceiver) 간의 결합도가 줄어들었습니다.
결론
- 의존 역전 원칙을 따르는 것은 소프트웨어의 유지보수성과 확장성을 높이는 데에 큰 도움을 줍니다.
- 추상화와 인터페이스를 통해 모듈 간의 결합도를 낮추고 코드의 재사용성을 높이는 결과를 얻을 수 있습니다.
'Design Patterns' 카테고리의 다른 글
인터페이스 분리 원칙 - interface segregation principle, ISP (0) | 2023.07.28 |
---|---|
리스코프 치환 원칙 - Liskov Substitution Principle, LSP (0) | 2023.07.27 |
단일 책임 원칙 - single responsibility principle, SRP (0) | 2023.07.27 |
디자인 패턴 - 개방 폐쇄 원칙 (0) | 2023.06.08 |
디자인 패턴 - 팩토리 패턴(factory pattern) (0) | 2023.06.05 |