✨ 경험·생각·독서

[오브젝트] 04 설계 품질과 트레이드오프 : 캡슐화

토심 2020. 3. 17. 10:43

[오브젝트] 04 설계 품질과 트레이드오프 요약과 나의 생각

 


<<04_02 설계 트레이드오프>>



데이터 중심 설계와 책임 중심 설계의 장단점을 비교하기 위해 

캡슐화, 응집도, 결합도를 사용.



#캡슐화 
상태와 행동을 하나의 객체 안에 모으는 이유는 

객체의 내부 구현을 외부로부터 감추기 위해서.

 

변경될 가능성이 높은 부분을 구현이라 하고 

상대적으로 안정적인 부분을 인터페이스라고 부른다. 

 

객체를 설계하기 위한 가장 기본적인 아이디어는 

변경의 정도에 따라 구현과 인터페이스를 분리하고 

외부에서는 인터페이스에만 의존하도록 관계를 조절하는 것이다.


캡슐화는 외부에서 알 필요가 없는 부분을 감춤으로써 

대상을 단순화 하는 추상화의 한 종류다.

 

캡슐화가 중요한 이유는 

불안정한 부분과 안정적인 부분을 분리해서 

변경의 영향을 통제할 수 있기 때문이다. 

 

정리하면 캡슐화란 변경 가능성이 높은 부분을 

객체 내부로 숨기는 추상화 기법이다. 

 

객체 내부에 무엇을 캡슐화해야하는가? 

변경될 수 있는 어떤 것이라도 캡슐화해야 한다. 

 

 



#응집도와 결합도
응집도와 결합도는 

구조적 설계 방법이 주도하던 시대에 

소프트웨어의 품질을 측정하기 위해 소개된 기준이지만 

객체지향의 시대에서도 여전히 유효하다.

응집도는 모듈에 포함된 내부 요소들이 연관돼 있는 정도를 나타낸다.


모듈 내의 요소들이 하나의 목적을 위해 

긴밀하게 협력한다면 

그 모듈은 높은 응집도를 가진다.


모듈 내의 요소들이 

서로 다른 목적을 추구한다면 

그 모듈은 낮은 응집도를 가진다.


객체지향의 관점에서 응집도는 

객체 또는 클래스에 얼마나 관련 높은 책임들을 할당했는지를 나타낸다.

결합도는 의존성의 정도를 나타내며 

다른 모듈에 대해 얼마나 많은 지식을 갖고 있는지를 나타내는 척도다.


어떤 모듈이 다른 모듈에 대해 

너무 자세한 부분까지 알고 있다면 

두 모듈은 높은 결합도를 가진다.


어떤 모듈이 다른 모듈에 대해 

꼭 필요한 지식만 알고 있다면 

두 모듈은 낮은 결합도를 가진다.


객체지향의 관점에서 결합도는 

객체 또는 클래스가 협력에 필요한 

적절한 수준의 관계만을 유지하고 있는지를 나타낸다.

좋은 설계란 

오늘의 기능을 수행하면서 

내일의 변경을 수용할 수 있는 설계다.


그리고 좋은 설계를 만들기 위해서는 

높은 응집도와 낮은 결합도를 추구해야 한다.

그것이 설계를 변경하기 쉽게 만들기 때문이다.


변경의 관점에서 응집도란 

변경이 발생할 때 

모듈 내부에서 발생하는 변경의 정도로 측정할 수 있다. 


하나의 변경을 수용하기 위해 

모듈 전체가 함께 변경된다면 

응집도가 높은 것이고 

 

모듈의 일부만 변경된다면 

응집도가 낮은 것이다.


응집도가 높을수록 

변경의 대상과 범위가 명확해지기 때문에 

코드를 변경하기 쉬워진다.


결합도가 높을수록 

함께 변경해야 하는 모듈의 수가 늘어나기 때문에 

변경하기 어려워진다.

 

캡슐화의 정도가

응집도와 결합도에 영향을 미친다.


캡슐화를 지키면 

모듈 안의 응집도는 높아지고 

모듈 사이의 결합도는 낮아진다.


캡슐화를 위반하면 

모듈 안의 응집도는 낮아지고 

모듈 사이의 결합도는 높아진다. 


따라서 응집도와 결합도를 고려하기 전에 

먼저 캡슐화를 향상시키기 위해 노력하라.

 

 

 


<<04_설계품질과 트레이드오프_03_데이터 중심의 영화 예매 시스템의 문제점>>
#캡슐화 위반
나는 이게 캡슐화 위반인지 몰랐다.

public class Movie { 
private Money fee; 

  public Money getFee() { 
      return fee; 
  } 

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


직접 객체 내부에 접근할 수 없으니까 캡슐화인 줄 알았는데 이런다고 캡슐화가 아니라고 한다.


getFee 메서드와 setFee 메서드는 

Money 내부에 Money 타입의 fee 라는 이름의 인스턴스 변수가 존재한다는 사실을 

퍼블릭 인터페이스에 노골적으로 드러낸다.

캡슐화의 원칙을 어기게 된 근본적인 원인은 

객체가 수행할 책임이 아니라 

내부에 저장할 데이터에 초점을 맞췄기 때문이다. 

 

이처럼 접근자와 수정자에 과도하게 의존하는 설계 방식을 

추측에 의한 설계 전략 이라고 

앨런 홀럽(Allen Holub)이 명했다. 

 

이 전략은 객체가 사용될 협력을 고려하지 않고 

다양한 상황에서 사용될 수 있을 것이라는 

막연한 추측을 기반으로 설계를 진행한다.


결과적으로 대부분의 내부 구현이 

퍼블릭 인터페이스에 그대로 노출될 수 밖에 없는 것이다.

그 결과 캡슐화의 원칙을 위반하는 변경에 취약한 설계를 얻게 된다.

 

 

 

 


<<04_설계 품질과 트레이드오프_04_자율적인 객체를 향해>>
#캡슐화를 지켜라
객체는 

자신이 어떤 데이터를 가지고 있는지를 

내부에 캡슐화하고 외부에 공개해서는 안된다.


객체는 

스스로의 상태를 책임져야 하며 

외부에서는 

인터페이스에 정의된 메서드를 통해서만 

상태에 접근할 수 있어야 한다.


속성의 가시성을 private로 설정했다고 해도 

접근자와 수정자를 통해 

속성을 외부로 제공하고 있다면 

캡슐화를 위반하는 것이다.

ㅇㅇㅇ와 ㅁㅁㅁ를 변경하는 코드가 필요하다면 

아마도 그 곳에서 getㅇㅇㅇ와 getㅁㅁㅁ를 호출해서 

ㅇㅇㅇ와 ㅁㅁㅁ를 가져온 후 

수정자 메서드를 이용해 값을 설정하는 

유사한 코드가 존재할 것이다. 

 

코드 중복은 악의 근원이다. 

 

 


#스스로 자신의 데이터를 책임지는 객체
객체는 단순한 데이터 제공자가 아니다. 

객체 내부에 저장되는 데이터보다 

객체가 협력에 참여하면서 

수행할 책임을 정의하는 오퍼레이션이 더 중요하다.


따라서 객체를 설계할 때 

"이 객체가 어떤 데이터를 포함해야 하는가?"라는 질문은 

다음과 같은 두 개의 개별적인 질문으로 분리해야 한다.

 

- 이 객체가 어떤 데이터를 포함해야 하는가?
- 이 객체가 데이터에 대해 수행해야 하는 오퍼레이션은 무엇인가?


데이터를 처리하는 데 필요한 메서드를 

데이터를 가지고 있는 객체 스스로 구현하고 있다.


따라서 이 객체들은 스스로를 책임진다고 말할 수 있다.

 

 

 

 


<<04_설계 품질과 트레이드오프_05_하지만 여전히 부족하다>>

04_데이터중심으로 구현하는 영화 예매 프로그램을

책을 보면서 직접 짜면서 만들었는데

계속 잘못된점이 있다고 하는게 너무 웃긴다. 
수정해도 수정해도 잘못되었다.

숨기고 숨겼는데 아직 덜 숨겼다. 

 


캡슐화의 진정한 의미.

 

이 예제는 캡슐화가 

단순히 객체 내부의 데이터를 외부로부터 감추는 것 

이상의 의미를 가진다는 것을 잘 보여준다.


사실 캡슐화는 변경될 수 있는 어떤 것이라도 감추는 것을 의미한다. 
내부 속성을 외부로부터 감추는 것은 

'데이터 캡슐화'라고 불리는 캡슐화의 한 종류일 뿐이다.


다시 한번 강조하지만 캡슐화란 변할 수 있는 어떤 것이라도 감추는 것이다. 


그것이 속성의 타입이건, 

할인 정책의 종류건 상관 없이 

내부 구현의 변경으로 인해 

외부의 객체가 영향을 받는다면 

캡슐화를 위반한 것이다.

 


설계에서 변하는 것이 무엇인지 고려하고 변하는 개념을 캡슐화해야 한다.[고프]
이것이 캡슐화라는 용어를 통해 말하고자 하는 진정한 의미다.
정리하면 캡슐화는 변하는 어떤 것이든 감추는 것이다.
그것이 무엇디은 구현과 관련된 것이라면 말이다.

#높은 결합도
현재 상황은 DiscountCondition 객체와 Movie 객체와 결합도가 높다. 두객체 결합도가 높다.
#낮은 응집도
응집도가 낮은 이유는 캡슐화를 위반했기 때문이다.

 

 

 

 


<<04_설계 품질과 트레이드오프_06_데이터 중심 설계의 문제점>>


데이터 중심의 설계는 본질적으로

너무 이른 시기에 데이터에 관해 결정하도록 강요한다. 

 

데이터 중심의 설계에서는

협력이라는 문맥을 고려하지 않고

객체를 고립시킨 채 오퍼레이션을 결정한다.

결론적으로 데이터 중심의 설계는 

너무 이른 시기에 

데이터에 대해 고민하기 때문에 

캡슐화에 실패하게 된다.

올바른 객체지향 설계의 무게 중심은 항상 

객체의 내부가 아니라 

외부에 맞춰져 있어야 한다. 

 

객체가 내부에 어떤 상태를 가지고 

그 상태를 어떻게 관리하는가는 부가적인 문제다. 

 

중요한것은 객체가 다른 객체와 협력하는 방법이다.


데이터 중심 설계는 

객체의 구현이 이미 결정된 상태에서 

다른 객체와의 협력 방법을 고민하기 때문에 

이미 구현된 객체의 인터페이스를 억지로 끼워맞출수밖에 없다.


객체의 인터페이스에 

구현이 노출돼 있었기 때문에 

협력이 구현 세부사항에 종속돼 있고 

 

그에따라 내부 구현이 변경됐을때 

협력하는 객체 모두가 영향을 받을 수밖에 없었던 것이다.

 

 

 


04_설계 품질과 트레이드오프 Fin.

 

 

 

 

 

 

 

 

 

 


커피 한 잔 후원하기