Updated:

1. 개요

좋은 객체지향 설계를 위한 SOLID라고 불리는 5가지 원칙이 있다. SRP(단일 책임 원칙), OCP(개방-폐쇄 원칙), LSP(리스코프 치환 원칙), ISP(인터페이스 분리 원칙), DIP(의존관계 역전 원칙)의 앞 글자를 따서 SOLID라는 이름이 붙었는데, 좋은 객체지향 설계를 위한 SOLID원칙에 대해 알아보도록 하자.

2. 단일 책임 원칙 (Single Responsibility Principle)

“하나의 클래스는 하나의 책임만을 가져야 한다.”

책임의 기준은 변경이다. 새로운 기능을 추가하거나 기존의 기능을 변경할 시, 영향을 받는 부분(수정해야 하는 부분)이 적으면 단일 책임 원칙을 잘 따른 것이라고 볼 수 있다. 즉 응집도는 높고 결합도는 낮은 설계를 한 경우 단일 책임 원칙을 잘 지켰다고 볼 수 있다.

EX) 상품 주문과 관련된 기능을 변경한다고 할 때, 상품 주문을 담당하는 클래스의 변경만 있어야 한다. 회원 정보와 같이 상품 주문과 상관없는 클래스의 변경이 필요한 경우 단일 책임 원칙을 따르지 않은 것이다.

3. 개방-폐쇄 원칙 (Open/Closed Principle)

“소프트웨어 요소는 확장에는 열려있지만, 변경에는 닫혀있어야 한다.”

기존의 코드는 변경하지 않으면서(Closed) 새로운 기능을 추가(Open)할 수 있는 설계가 되어야 한다는 원칙을 말한다. OCP를 위해 주로 인터페이스를 사용하는데, 인터페이스를 구현하는 클래스를 추가하면, 기존의 코드를 변경하지 않더라도 얼마든지 기능을 확장할 수 있다.

EX) 금액 할인만 가능한 상태에서 비율 할인 정책을 추가한다고 할 때, 인터페이스를 구현하는 새로운 클래스를 추가하여 해당 클래스를 주입해주면 기존의 코드를 변경하지 않더라도 비율 할인 정책을 추가할 수 있다.

[기존 코드 - 금액 할인 정책만 존재]

1
2
3
4
5
6
7
8
9
10
11
12
public interface DiscountPolicy {

    int getAmountAfterDiscount(int price);
}

public class AmountDiscountPolicy implements DiscountPolicy {

    @Override
    public int getAmountAfterDiscount(int price) {
        return price - 1000;
    }
}

[추가 코드 - 비율 할인 정책 추가]

1
2
3
4
5
6
7
public class RateDiscountPolicy implements DiscountPolicy {

    @Override
    public int getAmountAfterDiscount(int price) {
        return price * 0.9;
    }
}

4. 리스코프 치환 원칙 (Liskov Substitution Principle)

“자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다.”

객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다. 다형성을 위해 인터페이스 구현체를 믿고 사용하려면 LSP가 반드시 지켜져야 한다.

EX) 돈을 송금하기 위한 인터페이스를 구현한다고 할 때, 어느 구현체를 사용하더라도 돈을 보내는 사람의 잔액이 감소하고 돈을 받는 사람의 잔액이 증가해야 한다.

5. 인터페이스 분리 원칙 (Interface Segregation Principle)

“하나의 큰 인터페이스보다 여러개로 분리된 인터페이스가 낫다.”

인터페이스 분리를 통해 의존성을 낮춰서 코드 변경 시 자신과 상관없는 코드가 변경되지 않도록 해야한다.

EX) 메신저라는 하나의 인터페이스를 채팅 인터페이스와 파일 전송 인터페이스로 분리한 경우, 채팅 기능을 수정했을 때 파일 전송 기능에 영향을 주지 않는다.

6. 의존관계 역전 원칙 (Dependency Inversion Principle)

“의존 관계를 맺을 때, 자주 변화하는 것이 아니라 변화가 거의 없는 것에 의존해야 한다.”

구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 의미이다. 인터페이스에 의존한 경우 기능의 확장을 통한 유연한 설계가 가능하다.

EX) 3. 개방-폐쇄 원칙 (Open/Closed Principle)의 예제코드와 같이 인터페이스에 의존한 경우, Dependency Injection(의존성 주입)을 통해 런타임 시점에 자유롭게 구현 클래스를 바꿀 수 있다.

Updated:

Leave a comment