[F-Lab 챌린지 18일차] TIL : 객체지향 SOLID 원칙

성수데브리·2023년 7월 16일
0

f-lab_java

목록 보기
14/73

학습 목표

  • 객체지향 SOLID 원칙

객체 지향의 원칙 : SOLID

객체 지향의 특성을 올바르게 사용하기 위한 원칙들이다.

객체 지향 4대 특성을 발판으로 하고 디자인 패턴의 뼈대이며 스프링 프레임워크의 근간이기도 하다.

S : SRP (단일책임원칙)

어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다. -로버트 C.마틴-

  • 쉽게 말해 하나의 클래스에 너무 많은 역할을 부여하지 말란 뜻이다.
  • 단일 책임 원칙은 속성, 메서드, 패키지, 모듈, 컴포넌트, 프레임워크 등에도 적용할 수 있는 개념이다.
  • 단일 책임 원칙과 가장 밀접한 관련이 있는 객체지향의 특징은 추상화다.

O : OCP (개방폐쇄원칙)

소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야 한다.” - 로버트 C.마틴 -

  • 자신의 확장에는 열려 있고, 주변의 변화에 대해서는 닫혀 있어야 한다.

  • A 객체에서 B 객체를 참조하고 있고 B 객체에게 어떤 기능을 요청하는 부분이 있을때, B 클래스의 코드가 변경 되어도 A 클래스에서 영향을 받으면 안 된다.

  • 가장 좋은 예가 JDBC 다.

    https://docstore.mik.ua/orelly/java-ent/servlet/ch09_02.htm

    DB 의 확장에는 열여 있고 어플리케이션 쪽에서는 DB 확장에 영향받지 않는다.

L : LSP (리스코프 치환 원칙)

서브 타입은 언제나 자신의 기반 타입으로 교체할 수 있어야 한다. - 로버트 C.마틴 -

공변, 반공변 설명

LSP 규칙

  • 자료형 S 가 자료형 T 의 하위형이라면, 프로그램에서 자료형 T의 객체는 프로그램의 속성을 변경하지 않고 자료형 S 의 객체로 교체할 수 있어야 한다.

  • 시그니처에 관한 몇 가지 표준적인 요구사항

    • 하위형에서 리턴 타입의 공변성 하위형 타입에서 반환 타입은 공변해야 한다.
      Shape[] circleArray = new Circle[]{};
    • 하위형에서 메서드 매개변수의 반공변성 하위 타입 메서드 인수는 반공변성해야 한다. 반공변성은 상위타입이 하위 타입으로 대체될 수 있어야한다.
      // Using Comparator<? super T> for contravariance
      Comparator<Shape> shapeComparator = new Comparator<Shape>() {
          @Override
          public int compare(Shape shape1, Shape shape2) {
              return shape1.name.compareTo(shape2.name);
          }
      };
    • 하위형에서 메서드는 상위형 메서드에서 던져진 예외의 하위형을 제외하고 새로운 예외를 던지면 안된다.
  • 하위형이 만족해야 하는 행동 조건

    • Preconditions cannot be strengthened in the subtype.
      서브 타입에서 선행조건은 강화될 수 없다.

      서브 타입에서 오버라이딩한 메서드에서는 상위 타입보다 조건이 강화되어 부모 타입으로 대체할 수 없는 경우를 말한다.

      class Animal {
          public void eat() {
              System.out.println("Animal is eating.");
          }
      }
      
      class Dog extends Animal {
          @Override
          public void eat() {
              System.out.println("Dog is eating.");
          }
      }
      class Dog extends Animal {
          @Override
          public void eat() {
              if (hasFood()) {
                  System.out.println("Dog is eating.");
              } else {
                  System.out.println("Dog has no food.");
              }
          }
      
          private boolean hasFood() {
              // Check if dog has food
              // ...
          }
      }
    • Postconditions cannot be weakened in the subtype.

      서브 타입에서 후행조건은 약화될 수 없다.

    • Invariants must be preserved in the subtype.

      서브 타입에서 상위형의 불변조건은 반드시 유지되어야 한다.

      class Shape {
          protected double area;
      
          public double getArea() {
              return area;
          }
      }
      
      class Rectangle extends Shape {
          private double width;
          private double height;
      
          public Rectangle(double width, double height) {
              this.width = width;
              this.height = height;
              **this.area = calculateArea();**
          }
      
          **private** double calculateArea() {
              return width * height;
          }
      }
      class Square extends Rectangle {
          public Square(double side) {
              super(side, side);
          }
      }

I : ISP (인터페이스 분리 원칙)

클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안 된다. - 로버트 C.마틴 -

  • SRP 와 ISP 은 같은 문제에 대한 두 가지 다른 해결책이다.
  • 인터페이스 최소주의 원칙 : 인터페이스를 통해 메서드를 외부에 제공할 때는 최소한의 메서드만 제공하라는 것이다
  • 특별한 경우가 아니라면 단일 책임 원칙을 적용하는 것이 더 좋은 해결책이라고 할 수 있다.
  • 인터페이스는 그 역할에 충실한 최소한의 기능만 공개하라는 것이 객체 지향 스승들의 가르침이다.
  • 인터페이스는 ~ 할 수 있는 (is able to) 기준으로 만들어라

D : DIP (의존성 역전 원칙)

“추상화된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 한다.”
”자주 변경되는 구체 클래스에 의존하지 마라” - 로버트 C.마틴 -

OCP 사례에 소개된 JDBC 인터페이스도 DIP 역시 잘 지킨 사례다.

어플리케이션이 구체화된 DB Driver 에 바로 의존했다면 DB 변경에 영향을 크게 받을 것이다.
추상화된 JDBC 인터페이스에 의존함으로써 어플리케이션은 구체화된 DB Driver 변경에 영향을 받지 않는다.

1개의 댓글

comment-user-thumbnail
2023년 7월 17일

저도 개발자인데 같이 교류 많이 해봐요 ㅎㅎ! 서로 화이팅합시다!

답글 달기