[위키 link]

 

단일 책임의 원칙 (SRP, Single Responsibility Principle)

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

 

  • 어떤 코드를 어디에 두어야 하는가?를 결정할 때 많이 도움이 되는 원칙.
  • '그 클래스를 변경해야 하는 상황,원인,이유가 딱 한가지 인지' 를 보면, 단일 책임으로 제대로 분리되었는지를 확인할 수 있다.
  • 클래스는 그 책임을 완전히 캡슐화해서 제공해야 한다.
    • 어떤 클래스에 변경이 발생했을 때, 변경이 발생했다는 그 이유만으로 다른 클래스에도 변경이 발생해야하는 상황이 있어서는 안된다는 것이다. (어떤 사유로 내부 로직을 변경했다면, 거기서 끝나야 한다는 의미)
    • 지키지 않는 경우 3.8 산탄총 수술 문제가 발생한다.
  • 아무튼 가장 기본이 되는 원칙은 '함께 변경할 대상을 한데 모으는 것' 이다.

 

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

클라이언트 코드는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.

 

  • 이를 위해서는 프로그램을 작은 단위의 인터페이스들로 구성해야 한다.
    • 그래야 클라이언트가 자신이 필요한 인터페이스로 객체를 참조하여 사용할 수 있으니까. (= 필요 없는 메서드 의존 X)
  • 그래서, 특정 클라이언트를 위한 (작은) 인터페이스 여러 개가 범용 인터페이스 하나 보다 낫다.

 

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

  • 첫째, 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.
    • 예를 들어, 상위 클래스의 구현이 자식 클래스의 구현에 의존을 가지게 되면 안된다. 는 얘기로 보임.
    • 또는, 모듈이나 설계 전반적으로도 적용할 수 있는 원칙임.
  • 둘째, 추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.
    • 구체 클래스로 참조하지 말고, 인터페이스로 참조하자. 는 얘기로 보임.
  • 이름이 왜 의존성 역전 원칙이냐면...
    • 상위 계층이 하위 계층에 의존하는 전통적인 의존 관계를 반전 시킴으로써, 상위 계층이 하위 계층의 구현으로부터 독립하기 위한 원칙이기 때문.

 

개방 폐쇄의 원칙 (OCP, Open/Closed Principle)

소프트웨어 구성요소(모듈, 클래스, ...)는
확장에는 열려 있어야 하고(쉬운 확장),
변경에는 닫혀 있어야 한다.(내부 구조를 변경할 필요 X)

 

  • 예를 들어, 어떤 라이브러리가 인터페이스를 참조하고 있다면, 그 인터페이스를 구현한 클래스를 내가 직접 만들 수 있다.
    • 이런 설계가 확장에는 열려 있고, 내부 구조는 변경할 필요 없는 닫혀있는 구조다.

 

리스코프 치환의 원칙 (LSP, Liskov Substitution Principle)

  • 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
    • 다형성을 나타내는 말인데, 넓게는 "상속해서 하위 타입이면 상위 타입 변수로 치환될 수 있다." 의미라고 보면 된다.
    • 다형성, 공변성, 반공변성 같은 키워드와 관련이 있다.
  • 단순히 타입 치환 뿐만 아니라, 프로그램의 정확성을 깨뜨리지 않기 위한 몇 가지 제약조건이 있다.
    • 예시 : 직사각형을 상속한 정사각형
    • 정사각형은 직사각형이다. (true) 그러나 정사각형이 직사각형을 상속하는 상황을 생각해보면...
      • 정사각형의 width, height setter는 어떻게 될 것 같은가?
      • setter를 고려했을 때, 정사각형 인스턴스가 직사각형 변수에 담기면 어떻게 되는가?
    • 정사각형은 개념적으로는 직사각형이지만, 직사각형을 상속하면 LSP 위반 한다는 것을 알 수 있다.
      • 단, 정사각형, 직사각형이 불변 객체라면 이런 문제가 발생하지 않으므로 LSP 위반이 아니다.
  • 자식클래스에서 부모클래스의 메서드를 override 할 때, 더 느슨한 가시성 접근자로 open하는 것은 가능하지만, 더 엄격한 가시성 접근자를 사용하여 close하는 것은 불가능한 것은 이 때문이다.
    • https://stackoverflow.com/questions/17510152/why-cant-we-assign-weaker-privilege-in-subclass  
    • 만약 자식클래스에서 더 엄격한 가시성 접근자를 써서 닫을 수 있다고 가정하면...
      • ``java SuperClass cls = new SubClass()`` 처럼 담아, ``java cls.부모는_public_자식은_private()`` 호출하게 되면?
      • 실제 인스턴스는 자식클래스이기 때문에 private인 자식 클래스의 메서드가 호출되어야 한다. => private이지만 외부 호출이 가능하게 되므로 모순.