티스토리 뷰

728x90
반응형

좋은 부분이 너무 많아서 책을 많이 옮겨왔는데 혹시 문제가 된다면 말씀해주세요-!

제가 조금 재구성한 부분이 있기때문에 꼭 책을 읽어보시는 것을 추천드립니다.


 

[1] 클래스의 응집도를 판단하는 세가지 방법

 

1. 변경의 이유

 

서로 연관성이 없는 기능이나 데이터가 하나의 클래스안에 뭉쳐 있으면 응집도가 낮은 것이다.

클래스가 하나 이상의 이유로 변경돼야한다면 응집도가 낮은 것이다.

변경의 이유에 따라 클래스를 분리하라

 

2. 인스턴스 변수가 초기화되는 시점

 

클래스의 속성이 서로 다른 시점에 초기화되거나 일부만 초기화된다는 것은 응집도가 낮다는 증거다.

응집도가 높은 클래스는 인스턴스를 생성할 때 모든 속성을 함께 초기화한다.

반면 응집도가 낮은 클래스는 객체의 속성 중 일부만 초기화되고 일부는 초기화되지 않은 상태로 남겨진다. 

함께 초기화되는 속성을 기준으로 코드를 분리해야한다

 

3. 메서드들이 인스턴스 변수를 사용하는 방식

 

모든 메소드가 객체의 속성을 사용한다면 클래스의 응집도는 높다. 반면 메서드들이 사용하는 속성에 따라 그룹이 나뉜다면 클래스의 응집도가 낮다고 볼 수 있다. 속성그룹과 해당그룹에 접근하는 메서드 그룹을 기준으로 코드를 분리해야한다 

 

 

< 예제 > 

 

영화예매시스템에는 기간 조건과 순번 조건이 있는데

그것을 표현하는 클래스입니다. 

public enum DiscountConditionType {
  SEQUENCE, // 순번 조건
  PERIOD  // 기간 조건
}

public class DiscountCondition {
  private DiscountConditionType type;
  
  // 순번조건
  private int sequence;
  
  // 기간조건
  private DayOfWeek dayOfWeek;
  private LocalTime startTime;
  private LocalTime endTime;
  
  public boolean isSatisfiedBy(Screening screening) {
    if (type == DisCountConditionType.PERIOD) {
      return isSatisfiedByPeriod(screening);
    }
    
    return isSatisfiedBySequence(screening);
  }
  
  private boolean isSatisfiedByPeriod(Screenig screening) {
    return screening.getWhenScreened()과 dayOfWeek, startTime, endTime을 비교하는 조건문
  }
  
  private boolean isSatisfiedBySequence(Screening screening) {
     return sequence == screening.getSequence();
  }
}

 

위의 클래스에는 낮은 응집도를 암시하는 세가지 징후가 다 들어있다. 

 

 

1. 변경의 이유

 

DiscountCondition 안에 구현된 isSatisisSatisfiedByPeriod 메서드와 isSatisfiedBySequence 메서드는 서로 다른 이유로 변경된다.

 

- isSatisisSatisfiedByPeriod 메서드: 순번 조건에 대한 요구사항이 달라졌을 때 구현이 변경됨

- isSatisfiedBySequence 메서드: 기간 조건에 대한 요구사항이 달라졌을 때 구현이 변경됨

 

DiscountCondition은 서로 다른 이유로 서로 다른 지점에 변경될 확률이 높은 응집도 낮은 클래스이다. 

 

응집도를 높이기 위해, 변경의 이유에 따라 클래스를 분리해야한다. 

 

 

2. 인스턴스 변수가 초기화 되는 시점

 

DiscountCondition이 순번 조건을 표현하는 경우 sequence는 초기화되지만 dayOfWeek, startTime, endTime은 초기화되지않는다.

반대로 기간 조건을 표현하는 경우 dayOfWeek, startTime, endTime는 초기화되지만 sequence는 초기화되지 않는다.

 

응집도를 높이기 위해, 함께 초기화되는 속성을 기준으로 코드를 분리해야한다. 

 

 

3. 메서드들이 인스턴스 변수를 사용하는 방식

 

isSatisfiedBySequence 메서드는 sequence는 사용하지만 dayOfWeek,  startTime, endTime 은 사용하지 않는다.

반대로 isSatisisSatisfiedByPeriod 메서드는 dayOfWeek,  startTime, endTime만 사용하고 sequence를 사용하지 않는다. 

 

응집도를 높이기 위해, 속성 그룹과 해당 그룹에 접근하는 기준으로 코드를 분리해야한다.

 

 

[2] 다형성 POLYMORPHISM

 

다형성(polymorphism)은 그리스어에서 '많은' 을 의미하는 'poly'와 '

형태'를 의미하는 'morph'의 합성어로 많은 형태를 가질 수 있는 능력을 의미한다.

 

다형성이란 동일한 메세지를 수신했을 때 객체의 타입에 따라 다르게 응답할 수 있는 능력을 의미한다. 

즉 하나의 추상 인터페이스에 대해 서로 다른 구현을 연결할 수 있는 능력을 의미한다.

 

<예제>

 

위의 예제에서 DiscountCondition을 개선할때 협력의 문맥안에서 생각합니다. 

 

Movie 입장에서보면 SequenceCondition(순번 조건)과 PeriodCondition(기간조건)은 아무 차이도 없다. 

둘 모두 할인 여부를 판단하는 동일한 책임을 수행하고 있을 뿐이다. 할인 가능여부를 반환해 주기 만 하면 Movie는 객체가 SequenceCondition의 인스턴스인지, PeriodCondition의 인스턴스인지 상관하지 않는다. 

 

 

그래서 이렇게 코드를 분리시키는 결정을 하게 됩니다.

 

public interface DiscountCondition {
  boolean isSatisfiedBy(Screening screening);
}

public class PeriodCondtion implements DiscountCondition { ... }
public class SequenceCondition implements DiscountCondition { ... }

 

이제 Movie는 협력하는 객체의 구체적인 타입을 몰라도 상관없다.

협력하는 객체가 DiscountCondition 역할을 수행할 수 있고 isSatisfiedBy 메시지를 이해할 수 있다는 사실만 알고 있어도 충분히다. 

 

즉 Moview와 DiscountCondition 사이의 협력은 다형적이다. 

 

 

 

 

[3] 개방-폐쇄 원칙 (Open-Closed Principle, OCP)

 

"소프트웨어 개체(클래스, 모듈, 함수 등)은 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야한다" 

 

여기서 키워드는 확장과 수정이다.

확장은 애플리케이션 동작의 관점을,

수정은 애플리케이션 코드의 관점을 반영한다.

 

- 확정에 대해 열려 있다 : 애플리케이션의 요구사항이 변경될 때 이 변경에 맞게 새로운 '동작'을 추가해서 애플리케이션의 기능을 확장할 수  있다.

- 수정에 대해 닫혀 있다: 기존의 '코드'를 수정하지 않고도 애플리케이션의 동작을 추가하거나 변경할 수 있다.

 

개방 폐쇄 원칙은 사실 런타임 의존성과 컴파일타임 의존성에 관한 이야기이다. (🤭🤭)

개방 폐쇄 원칙을 따르는 설계란 컴파일 타임 의존성을 수정하지 않고도 런타임 의존성을 쉽게 변경할 수 있는 구조이다. 

 

위의 예제에서 

Movie 클래스의 컴파일 타임 의존성: DiscountCondition

Movie 클래스의 런타임 타임 의존성: DiscountCondition를 implements 하는 친구들

 

2번에서의 수정으로 이 원칙을 따르게 된 것이다.  

 

 

 

728x90
반응형
댓글
댓글쓰기 폼