응집도와 결합도

응집도와 결합도

응집도

모듈 내부 요소가 연관된 정도.
모듈의 내부 요소가 한 목적을 위해 긴밀하게 협력하는 정도.

높을 수록 좋다.

좀더 구체적으로 설명하면,

하나의 변경이 발생할 때 모듈 내부에서 발생하는 변경의 정도
하나 바꾸려고 할 때, 모듈 전체를 바꿔야 되면 응집도가 높은 것.

하나의 변경이 일어날 때, 모듈 하나만 바꿔서 해결 가능하면, 응집도가 높은 것.

즉 특정 요구 사항을 변경하려고 한다면,
요구 사항과 관련된 코드는 하나의 모듈에 모여있어야 한다.

그 요구 사항과 관련된 코드를 찾기 위해 소스 코드 전체를 구석구석 찾으면 안된다!!

결합도

한 모듈이 다른 모듈에 대해 얼마나 많은 정보를 갖고 있는지.
의존성 정도를 나타냄.

다른 모듈에 대해서는 최소한의 정보만 가지고 있는게 좋다.
낮을 수록 좋다.

좀더 구체적으로 설명하면,

한 모듈이 변경하려 할 때 다른 모듈도 바뀌어야 하는 정도.
하나 바꾸려고 하는데 다른 애들도 다 바꿔줘야되면 결합도가 높은거다.
(구현된 클래스에 의존하지 말고 인터페이스에 의존하라는 말도 결합도를 낮추기 위해서 등장한다.)

물론 바꿀 일이 거의 없는 객체는 결합도가 높아도 괜찮다.

캡슐화와 관계

캡슐화는 변할 수 있는 내용은 외부에서 알 수 없게 감추는 것이다.

일반적으로 응집도와 결합도의 문제는 캡슐화를 잘 설계하면 동시에 해결된다.

캡슐화가 잘된 걸까? (public Getter, setter)

1
2
3
4
5
6
7
8
9
10
11
public class Movie {
private Money free;

public Money getFee() {
return fee;
}

public void setFree(Money fee) {
this.fee = fee;
}
}

이렇게 private 매개변수를 해놓고, getter, setter를 해놓으면 캡슐화가 잘 된걸까?

답은 아니다!!!

게터 세터는 객체 내부 상태에 어떤 정보도 캡슐화하지 못한다. 사실상 그냥 public으로 열어둔거나 다름없다.
외부에서 Movie 객체를 접근할 때 이미 Money 객체가 있다는 걸 알게된다.

이런 경우는 객체가 가지는 데이터에 중점적으로 설계해서 이런 일이 생긴다.
객체는 문맥을 고려한 책임을 기반으로 설계되어야 한다.

높은 결합도

결합도는 하나의 모듈을 변경하려 할 때 다른 모듈도 다 바뀌어야 하는 정도이다.

캡슐화를 지키지 못해서 결합도가 높아지는 경우를 보자.

1
2
3
4
5
6
7
8
9
10
public class ReservationAgency {
public Reservation reserve(Screening screening, Customer customer, int audienceCount) {
...
Money fee; //Money에 의존
if (discountable) {
fee = movie.getFee().minus(discountAmount).times(audienceCount);
}
...
}
}

다음 예시에선 Money타입의 fee에 요금 정보를 저장하고 있다.
근데 만약 Money가 아닌 다른 타입에 fee를 저장하고 싶으면 어떻게 되는가?

Money 대신 다른 타입을 수행할 수 있도록,
getFee()를 수정하고 -> minus()를 수정하고 -> times()를 수정해야 한다

Money를 바꿀 뿐인데 다른 객체의 메서드들이 다 변해줘야 한다.

이는 movie의 getFee()가 사실상 객체에 fee와 관련된 내용이 있음을 알리는, 즉 캡슐화 하지 못해서 생긴 사례다.

낮은 응집도

변경되는 이유가 각자 다른 코드들을 하나의 모듈 안에 뭉쳐 놓으면, 변경과 관련없는 코드도 영향을 받을 수 있다.

할인 정책을 선택하는 코드와 할인 조건을 검증하는 코드가 한 모듈에 있다고 하자.
할인 정책을 추가하려고 하면, 할인 조건을 검증하는 코드는 변경과 큰 상관은 없지만 영향을 받는다.

응집도가 낮으면 변경 하나를 하려고 할 때 코드 구석구석을 고쳐야 할 수 있다.

응집도가 낮다는 건 자신과 관련있는 코드가 다른 엉뚱한 곳에 있을 수 있다는 의미이기도 하기 때문이다.

단일 책임 원칙

한 클래스가 변경되려면, 하나의 이유여야 한다는 것이다.
즉 응집도 있게 설계해서 그 클래스가 엉뚱한 일에도 영향 받지 않도록 설계되어야 함을 의미한다.

Share