개발 & 데이터베이스/CS

좋은 객체 지향 설계의 5원칙 SOLID 정의

K.두부 2023. 2. 19. 15:08
반응형

객체 지향 언어에는 Java, C++, 파이썬 등이 있다.

이 언어들로 설계를 할 때 지켜줘야 할 소프트웨어 개발 원칙 5개를 SOLID 원칙이라고 부른다.

 

  • SRP (Single Responsibility Principle) 단일 책임 원칙
  • OCP (Open Closed Priciple) 개방 폐쇄 원칙
  • LSP (Listov Substitution Priciple) 리스코프 치환 원칙
  • ISP (Interface Segregation Principle) 인터페이스 분리 원칙
  • DIP (Dependency Inversion Principle) 의존 역전 원칙

 

좋은 설계란 시스템에 변화가 생겼을 때 영향을 받는 범위가 적은 것을 말한다.

즉, SOLID 설계 원칙을 적용한다면 코드를 확장하고 유지 보수 관리하기 쉬워지며, 불필요한 복잡성을 제거해 리펙토링에 소요되는 시간을 줄임으로써 프로젝트 개발의 생산성을 높일 수 있다.

 

SRP (Single Responsbility Principle) - 단일 책임 원칙

class Restaurant {
    void cook();  // 요리
    void order(); // 주문
    void eat();   // 식사
}

단일 책임 원칙은 "하나의 클래스는 하나의 책임만 가져가야한다." 를 뜻한다. 여기서 중요한 건 변경이 이루어질 때다. 위처럼 요리사와 손님의 역할을 Restaurant 클래스에 함께 넣어두면 손님에 관련된 변경 사항이 생겼을 때 요리사의 기능에도 불가피한 변경이 생길 수 있다.

 

class Chef {
    void cook();
}

class Guest {
    void order();
    void eat();
}

Restaurant 클래스를 요리사 (Chef) 클래스와 손님 (Guest) 클래스로 분리했다. 이처럼 분리하게 되면 변경 사항이 생겼을 때 수정할 대상이 명확해진다. 시스템의 규모가 커질수록 단일 책임 원칙의 중요성은 극대화된다.

 

OCP (Open Closed Priciple) - 개방 폐쇄 원칙

interface Car {
    go();
    stop();
}

class Bus implements Car {
    public void go() {}
    public void stop() {}
}
    
class Taxi implements Car {
    public void go() {}
    public void stop() {}
}

개방 폐쇄 원칙은 "확장에 열려있어야하며, 수정에는 닫혀있어야한다." 를 뜻한다. 기능 추가 요청이 오면 클래스 확장을 통해 구현하면서 확장에 따른 클래스 수정은 최소화 되도록 작성해야한다.

 

[변경에 닫혀있음] - 클라이언트는 교통 수단(Bus, Taxi)가 변경되더라도 내부 함수에 대해서 영향을 받지 않는다.

[확장에 열려있음] - 또 다른 교통 수단이 생겼을 경우 인터페이스를 통해서 기능을 추가할 수 있으며 다른 차량 클래스에는 영향을주지 않는다.

 

LSP (Listov Substitution Priciple) - 리스코프 치환 원칙

interface Car {
    void go();
    void stop();
}
    
class Bus implements Car {
    public void go() {}
    public void stop() {}
        
    // 인터페이스에 없는 기능 구현
    public void repair() {}
}

리스코프 치환 원칙은 "서브 타입은 언제나 기반(부모) 타입으로 교체할 수 있어야한다." 를 뜻한다. 이는 무분별한 오버라이딩을 줄이기 위한 원칙이므로 오버라이딩을 할 경우에 상위 타입의 기능을 온전히 구현 후에 새로운 기능을 추가하는 게 바람직하다.

 

ISP (Interface Segregation Principle) - 인터페이스 분리 원칙

interface Restaurant {
    void cook();  // 요리
    void order(); // 주문
    void eat();   // 식사
}

ISP 원칙은 "인터페이스가 각각 사용에 맞게 끔 잘 분리되어 있어야한다." 를 뜻한다. SRP 원칙은 클래스의 단일 책임을 강조했다면 ISP 원칙은 인터페이스의 단일 책임을 강조한다.

 

interface Chef {
    void cook();
}

interface Guest {
    void order();
    void eat();
}

따라서 위에서 얘기했던 것처럼 클라이언트를 기준으로 분리시켜주면 된다. 인터페이스의 정책 개념으로 ISP 원칙의 주의해야할 점은 한 번 인터페이스를 분리하여 생성한 후에 수정 사항이 생겨서 또 한 번 인터페이스를 분리하면 안된다. 

 

DIP (Dependency Inversion Principle) - 의존 역전 원칙

interface Car {  
    void go();
    void stop();
}

class sportCar implement Car {
    public void go() {}
    public void stop() {}
}

class K3 implement Car {
    public void go() {}
    public void stop() {}
}

DIP 원칙은 "참조해야 할 대상의 상위 요소 (추상 클래스 or 인터페이스)로 참조해야한다." 를 뜻한다. 위처럼 K3 클래스를 생성할 때 sportCar 클래스를 참조해야하는 상황이 생기면 구현 클래스 sportCar 가 아닌  sportCar 의 상위 요소인 인터페이스 Car 에 의존하라는 뜻이다.

 

의존 관계를 맺으려고 할 때 변화하기 쉽고 자주 변할 수 있는 구현 클래스보다는 변화하기 어렵고 거의 변화가 없는 인터페이스에 의존하라는 뜻을 가지고 있다.

 

 

반응형