계속지나가기 2020. 9. 12. 10:05
반응형

SOLID 원칙

SOLID(S.O.L.I.D)

SOLID 원칙이란?

: Rober C. Martin이 2000년에 논문에서 발표한 내용

  • 이해하기 쉽고 유연하며, 유지 보수가 쉬운 SW 개발을 위한 다섯가지 SW 설계 원칙
  • 단, 다섯가지 원칙을 지키다 보면 서로 상충되는 경우가 발생할 수도 있음
약어 원칙 한글 명칭
SRP Single Responsibility Principle 단일 책임 원칙
OCP Open-Closed Principle 개방-폐쇄 원칙
LSP Liskov Substitution Principle 리스코프 치환 원칙
ISP Interface Segregation Principle 인터페이스 분리 원칙
DIP Dependency Inversion Principle 의존 역전 원칙

01. SRP 원칙

Single Responsibility Principle : 단일 책임 원칙

  • 같은 이유로 변경된 것들을 모아 클래스를 만들고, 다른 이유로 변경되는 것은 분리하여 만들어라
  1. 클래스가 변경되어야 하는 이유는 한가지로만 구성 즉
  2. 즉 한 클래스에는 역할을 한가지로 구성 : 재사용상, 유지보수를 좋게 하기 위해서
  3. 사용자와의 관계에 대해서 고민해야 함
  • 문제점
    : 클래스에 기능이 너무 많으면 유지보수가 어려워짐

SRP의 예

  1. Book 클래스 메소드 기능 설명

  • load() : 파일에서 북 정보를 읽어서 멤버 변수들에 저장
  • show() : 콘솔 화면에 해당 객체의 정보를 보임
  • 프로그램을 더 이상 고치지 않는다면 이대로 SRP를 지키는 설계가 될 수 있음
  1. 변경되는 부분들이 생긴다면 SRP를 다시 고려해봐야 함
  • 만약 파일이 아니라 데이터베이스에서 책 데이터를 읽어서 저장하는 Load()함수를 만든다면?
  • 콘솔 화면이 아니라 GUI화면에 책 내용을 출력하는 show()함수를 만든다면?

  1. SRP를 지키기 위해 위 기능에서 바꾸어야 하는 점
  • Book 클래스에는 북에 대한 정보들만 저장하는 것으로 바꿈
  • BookManager 클래스를 따로 만들어 load,show() 함수들을 이 클래스로 편성
  • Book, BookManager는 Aggregation(집합)관계
  • Aggregation(집합)관계란?
    : 여러 개의 독립적인 클래스들이 하나의 클래스를 구성하는 경우로 다이아몬드 형태가 붙어있는 쪽이 전체를 나타내는 클래스이다
    : 여기서는 BookManager가 Book을 소유함

02. OCP 원칙

Open-Closed Principle : 개방-폐쇄 원칙

  • 기존 코드를 변경하지 않고 확장할 수 있도록 만들어야 함
  1. 문을 여는 프로그램을 가정
  2. 세 가지 종류의 문이 있음
  • Sliding door
  • Knob door
  • Automatic Door

버전1.

1. if문으로 door의 종류에 따라 다르게 열도록 함

: 이렇게 할 경우 새로운 door가 추가되면 해당 코드 수정 불가피

if (door instanceof AutomaticDoor)
    client.pressOpen(door);
else if (door instanceof KnobDoor) 
    client.twistOpen(door);
else if (door instanceof SlidingDoor)
    client.slideOpen(door);

버전2.

  1. 다형성 사용

  • door.open();
  1. 새로운 문이 추가되면 새로운 클래스를 추가하고 open() 함수를 오버라이딩

03. LSP 원칙

Liskov Substitution Principle : 리스코브 치환 원칙

  • Subclasses should be substitutable for their base classes
  1. 자식 클래스는 부모 클래스를 대체 할 수 있어야 함
  2. 부모 클래스 객체 대신 자식 클래스 혹은 후손 클래스 객체를 사용했을 때 문제 없이 프로그램이 동작해야함

예: 사각형과 정사각형

  1. 정사각형은 사각형의 특별한 종류
  2. 상속으로 처리
  • Rectangle Class
class Rectangle {
    private int width;
    private int height;

    public Rectangle(int w, int h) {
        width = w;
        height = h;
    }
    public int getPerimeter() {
        return 2 * (width + height);
    }
    public void setWidth(int w) { width = w; }
    public void setHeight(int h) { height = h; }
}
  • Square Class
class Square extends Rectangle {
    public Square(int w) {
        super(w, w);
    }
    public void setWidth(int w) { 
        super.setWidth(w);
        super.setHeight(w);
    }
    public void setHeight(int h) { 
        super.setWidth(h);           
        super.setHeight(h);
    }
}
  • Main Class
class Main {
    public static void main(String[] args) {
        Rectangle r = new Rectangle(3, 5);
        System.out.println(r.getPerimeter());
        Square s = new Square(3);
        System.out.println(s.getPerimeter());
        r = s;
        r.setWidth(3);
        r.setHeight(5);
        System.out.println(r.getPerimeter());        
    }
}
  • 이 경우 Square은 Rentangle을 완벽히 대체하지 못함
  • 즉, LSP을 위배하게 됨

4. ISP 원칙

Interface Segregation Principle : 인터페이스 분리 원칙

- Many client specific interfaces are better than one general purpose interface

일반화된 인터페이스 한 개를 가진 경우

  1. 여러 개 클라이언트에 필요한 기능을 가지고 있는 일반화된 인터페이스보다는 각 클라이언트에 특화되어 있는 인터페이스를 사용
  2. 예: (JAVA에서는 해당되지 않음)
  • CDManager, BookManager, MP3Manager라는 클래스가 있을 때, DB를 로드해주는 인터페이스가 IDBloader 하나 일 경우 -> 즉, 일반화된 인터페이스 -> ISP(x)
  • ICDDBloader, IMP3DBloader, IBookDBloader 로 인터페이스를 각 클래스에 특화되어있게 분리 ->ISP(o)
  • 맨 첫번째 경우처럼 코드를 짤 경우 book에 대한 로드방법만 바꾸고 싶어도 IDBloader를 바꾸게 되므로 전체 클래스가 컴파일을 다시해야함
  1. 예: (자바에 해당되는 예)
  • IDBloader 인터페이스에는 getBookName(), getCDName(), load() 두 개의 함수가 있음
  • 만약 해당 인터페이스를 BookManager, CDManager가 구현해야한다면 두 클래스는 각각 getCDName(), getBookName() 서로에게 필요없는 함수까지 구현해야함 -> ISP(x)
  • 이 경우, 각 클래스마다 각 클래스에 특화되어있는 인터페이스 IBookDBloader ,ICDDBloader 두 개를 구현해주는 것이 맞음

각 클라이언트에 특화되어 있는 인터페이스들을 가진 경우

5. DIP 원칙

Dependency Inversion Principle : 의존 역전 원칙Depend upon Abstactions.

- Depend upon Abstactions. Do not depend upon Concretions

  1. 기능을 직접 구현한 구체 클래스 또는 함수보다는 추상 클래스나 인터페이스를 사용하는 코드를 작성하라
  2. 기능을 직접 구현한 클래스나 함수는 변경될 가능성이 높다

각 기능을 직접 구현한 클래스 사용한 경우
추상 클래스를 사용한 경우

반응형