객체지향설계 원칙 5가지(SOLID) 중 OCP와 DIP를 지키며 코드를 리팩토링한다
OCP(Open Closed Principle) : 개방 폐쇄 원칙
DIP(Dependency Inversion Principle) : 의존 역전 원칙
다형성과 객체지향 설계 원칙 5가지가 궁금하다면?
👉👉 다형성과 로버트 마틴의 5가지 원칙
기존 비즈니스 로직은 다음과 같은 상황이다.
(1) 배달기사
는 배송이 완료되면 고객에게 배송완료
를 알려야한다
(2) 연락 방법은 문자메세지(Message)와 카카오톡(Kakao) 두 가지가 존재한다
public class Message {
void sendMessage(Client client){};
}
public class Kakao {
void sendMessage(Client client){};
}
(3) 배달기사(Courier)는 카카오톡(Message) 클래스를 호출하여 고객에게 연락(sendMessage(client))한다
public class Courier {
Long courierID;
Kakao contact;
Courier(Long courierID, Kakao contact) {
this.courierID = courierID;
this.contact = contact;
}
void deliveryComplete(Client client){
// 고객에게 완료 메시지 전송
contact.sendMessage(client);
}
}
DIP, OCP 원칙을 준수하고 있는가?
(1) Courier의 인스턴스 생성 시 Kakao에 의존성을 갖고 있다.
(2) 연락하는 방법은 Kakao 외에도 Message가 존재하며, 추후 다른 방식들이 추가될 수 있다.
(3) 만약, 다른 연락 방법을 실행하긴 위해선 Courier의 클래스 필드 변수 타입을 교체해야한다.
다음과 같은 문제 상황이 발생했다고 가정하자
🐤문제상황 발생🐤
(1) 일시적인 장애로 인해 지금 즉시! 카카오톡(kakao)이 아닌 문자메세지(message)를 통해 고객에게 연락해야한다.
해당 문제를 해결하기 위해선, 현재 코드로는 간단해 보이지만 Courier 클래스의 클래스 필드 변수 타입을 교체해줘야 한다.(OCP 위배)
public class Courier {
Long courierID;
// Kakao contact;
Message contact;
Courier(Long courierID, Message contact) {
this.courierID = courierID;
this.contact = contact;
}
void deliveryComplete(Client client){
// 고객에게 완료 메시지 전송
contact.sendMessage(client);
}
}
인터페이스가 아닌 구현체에 의존하고 있기 때문에 발생한 문제다.
DIP 원칙에 따라, 구현체가 아닌 구현체의 상위 요소를 참조하면 된다.
public interface Contact {
void sendMessage(Client client);
}
public class Kakao implements Contact{
@Override
public void sendMessage(Client client) {}
}
public class Message implements Contact{
@Override
public void sendMessage(Client client) {}
}
연락 방법들의 상위 인터페이스(Contact)를 생성하고 하위에서 이를 상속받는 방법을 통해 해결할 수 있었다.
public class Courier {
Long courierID;
Contact contact;
public Courier(Long courierID, Contact contact) {
this.courierID = courierID;
this.contact = contact;
}
void deliveryComplete(Client client){
// 고객에게 완료 메시지 전송
contact.sendMessage(client);
}
}