객체 지향 설계 SOLID 원칙
두문자 | 약어 | 이름 | 개념 |
S | SRP | 단일 책임 원칙 Single Responsibility Principle |
한 클래스는 하나의 책임을 가져야 한다. |
O | OCP | 개방-폐쇄 원칙 Open-Closed Principle |
소프트웨어 개체(클래스, 모듈 등)는 확장에는 열려있으나, 수정에는 닫혀 있어야 한다. |
L | LSP | 리스코프 치환 원칙 Liskov Substitution Principle |
객체의 정확성을 깨뜨리지 않으면서 상위클래스의 객체를 하위클래스의 객체로 바꿀 수 있어야한다. |
I | ISP | 인터페이스 분리 원칙 Interface Segregation Principle |
범용적인 인터페이스보다 클라이언트를 위한 인터페이스 여러개가 더 낫다. |
D | DIP | 의존관계 역전 원칙 Dependency Inversion Principle |
추상화에 의존해야지, 구체화에 의존하면 안된다. |
OCP 개방-폐쇄 원칙이란
확장에는 열려있고, 수정에는 닫혀있어야 한다.
개방-폐쇄 원칙이란 기존의 코드를 변경하지 않으면서(Closed), 기능을 추가할 수 있도록(Open) 설계해야 한다는 원칙입니다.
개방-폐쇄 원칙의 예
추첨기를 만들어 보겠습니다.
1. OCP 적용 전
public class LotteryMachine {
private final RandomStrategy strategy;
public LotteryMachine(RandomStrategy strategy) {
this.strategy = strategy;
}
public User select(List<User> userList) {
if (strategy == 랜덤) {
Collections.shuffle(userList);
}
if (strategy == 오름차순) {
userList.sort(Comparator.comparingInt(User::getScore));
}
if (strategy == 내림차순) {
userList.sort((o1, o2) -> Integer.compare(o2.getScore(), o1.getScore()));
}
return userList.get(0);
}
}
이 추첨기에서 추첨방식을 추가한다면 기존의 코드를 수정하게 됩니다. 즉 OCP 위반입니다. 기존의 코드를 수정하지 않고 추첨방식을 추가하려면 어떻게 해야 할까요? 자바의 다형성을 이용하여 추첨방식을 추상화하여 사용하는 겁니다.
2. OCP 적용 후
public class LotteryMachine {
private final ShuffleStrategy strategy;
public LotteryMachine(ShuffleStrategy strategy) {
this.strategy = strategy;
}
public User select(List<User> userList) {
strategy.shuffle(userList);
return userList.get(0);
}
}
public interface ShuffleStrategy {
void shuffle(List<User> userList);
}
public class RandomStrategy implements ShuffleStrategy{
@Override
public void shuffle(List<User> userList) {
Collections.shuffle(userList);
}
}
public class AscStrategy implements ShuffleStrategy{
@Override
public void shuffle(List<User> userList) {
userList.sort(Comparator.comparingInt(User::getScore));
}
}
public class DescStrategy implements ShuffleStrategy{
@Override
public void shuffle(List<User> userList) {
userList.sort((o1, o2) -> Integer.compare(o2.getScore(), o1.getScore()));
}
}
추첨기는 인터페이스화된 ShuffleStrategy를 의존하도록 하고 생성자를 통해서 구현체를 주입해주었습니다.
이렇게 하면 추첨방식을 추가하더라도 기존의 추첨기 클래스의 수정이 일어나지 않습니다.
3. 추첨기의 확장
public class NoneStrategy implements ShuffleStrategy{
@Override
public void shuffle(List<User> userList) {
}
}
섞지 않는 추첨방식을 손쉽게 확장했습니다.