객체 지향 설계 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) {
        
    }
}

섞지 않는 추첨방식을 손쉽게 확장했습니다.

+ Recent posts