관리 메뉴

생각해보기

오브젝트(조영호) 책 정리 -5- 본문

객체지향

오브젝트(조영호) 책 정리 -5-

정한_s 2021. 11. 15. 13:21

우리는 데이터 중심의 설계보다 책임 중심의 설계를 해야 한다. 데이터 중심의 설계는 협력보다 객체의 상태를 중요시하기 때문에 객체끼리 협력하기가 어렵다. 따라서 협력안에서 객체의 책임을 결정하고, 객체의 책임을 행동으로 나타내야 한다. 

 

책임에 초점을 맞춰서 설계할 때 가장 큰 어려움 중 하나는 어떤 객체에 어떤 책임을 할당할지 결정하는 것이다.  GRASP 패턴을 통해 다양한 기준에 따라 책임을 할당하는 방법을 생각해보자

 

GRASP 패턴은 "General Responsibility Assignment Software Pattern(일반적인 책임 할당 소프트웨어 패턴)"의 약자로 객체에게 책임을 할당할 때 지침으로 삼을 수 있는 원칙들의 집합을 패턴 형식으로 정리한 것이다

 

(들어가기 앞서, 고민해야 할 부분)

어떤 책임을 할당해야 할 때 가장 먼저 고민해야 하는 후보가 도메인 개념이다. 도메인 개념들을 책임 할당의 대상으로 사용하면 코드에 도메인의 모습을 투영하기가 수월해진다

설계를 시작한는 단계에서 개념들의 의미나 관계가 정확하거나 완벽해질 필요가 없다. 도메인의 개념을 정리하는 데 너무 많은 시간을 들이지 말고 빠르게 설계와 구현을 진행하라.

 

INFORMATION EXPERT(정보 전문가) 패턴 

객체는 자신의 상태를 스스로 처리하는 자율적인 존재여야한다. 객체의 책임과 책임을 수행하는 데 필요한 상태는 동일한 객체 안에 존재해야 한다. 따라서 객체에게 책임을 할당하는 원칙은 책임을 수행할 정보를 알고 있는 객체에게 책임을 할당하는 것이다. 즉, 책임을 수행하는 데 필요한 정보를 가지고 있는 객체에게 책임을 할당한다.

* "메시지를 전송할 객체는 무엇을 원하는 가?", "메시지를 수신할 적합한 객체는 누구인가?"

 

LOW COUPLING(낮은 결합도) 패턴 & HIGH COHESION(높은 응집도) 패턴

설계의 전체적인 결합도가 낮게, 응집도는 높게 책임을 할당해야 한다. 여러 설계 대안이 있을 때 낮은 결합도와 높은 응집도를 유지할 수 있는 설계를 선택한다

* "어떻게 하면 의존성을 낮추고 변화의 영향을 줄이며 재사용성을 증가시킬 수 있을까? (낮은 결합도)?"

* "어떻게 복잡성을 관리할 수 있는 수준으로 유지할 것인가? (높은 응집도)" 

 

CREATOR 패턴

 패턴의 의도는 어떤 방식으로든 생성되는 객체와 연결되거나 관련될 필요가 있는 객체에 해당 객체를 생성할 책임을 맡기는 것이다. 객체 A를 생성해야 할 때, 아래의 조건을 최대한 만족하는 B에게 객체 생성 책임을 할당한다. 

  • B가 A 객체를 포함하거나 참조한다.
  • B가 A 객체를 기록한다.
  • B가 A 객체를 긴밀하게 사용한다.
  • B가 A 객체를 초기화하는 데 필요한 데이터를 가지고 있다( 즉, B가 A에 대한 정보 전문가이다)

 클래스 응집도 판단하기

응집도가 낮다는 것은 서로 연관성이 없는 기능이나 데이터가 하나의 클래스 안에 뭉쳐서 있다는 것을 의미한다. 따라서 변경의 이유에 따라 클래스를 분리해야 한다. 변경의 이유를 파악할 수 있는 방법은 "인스턴스 변수가 초기화되는 시점 살펴보기", "메스드들이 인스턴스 변수를 사용하는 방식 살펴보기" 등이 있다.

* 정리

  • 클래스가 하나 이상의 이유로 변경돼야 한다면 응집도가 낮은 것이다. 변경의 이유를 기준으로 클래스를 분리한다
  • 클래스의 인스턴스를 초기화하는 시점에, 경우에 따라 서로 다른 속성들을 초기화하고 있다면 응집도가 낮은 것이다. 초기화되는 속성의 그룹을 기준으로 클래서를 분리한다.
  • 매서드 그룹이 속성 그룹을 사용하는지 여부로 나뉜다면 응집도가 낮은 것이다. 이들 그룹을 기준으로 클래스를 분리한다.

POLYMORPHISM(다형성) 패턴

객체의 타입에 따라 변하는 행동이 있다면 타입을 분리하고 변화하는 행동을 각 타입에 다형적으로 행동하는 책임을 할당해야 한다. 예를 들어, 객체의 타입을 검사해서 타입에 따라 여러 대안들을 수행하는 조건적인 논리를 사용하는 것보다 다형성을 이용해 변화를 다루기 쉽게 확장하는 것이다.

* "객체의 타입에 따라 변하는 로직이 있을 때 변하는 로직을 담당할 책임을 어떻게 할당해야 하는가?"

 

PROTECTED VARIATIONS(변경 보호) 패턴

변화가 예상되는 불안정한 지점들을 식별하고 그 주위에 안정된 인터페이스를 형성하도록 책임을 할당하는 것이다. 설계에서 변하는 것이 무엇인지 고려하고 변하는 개념을 캡슐화하는 것이다.

* "변경될 가능성이 높은가? (캡슐화 하라)"

* "객체, 서브시스템, 시스템을 어떻게 설계해야 변화와 불안정성이 다른 요소에 나쁜 영향을 미치지 않도록 방지할까?"

 

하나의 클래스가 여러 타입의 행동을 구현하는 것처럼 보인다면 클래스를 분해하고 다형성 패턴에 따라 책임을 분산시켜야 한다. 예측 가능한 변경으로 인해 여러 클래스가 불안정해진다면 변경 보호 패턴에 따라 안정적인 인터페이스 뒤로 변경을 캡슐화한다.

 

설계를 주하는 것은 변경이다. 변경을 대비할 수 있는 두 가지 방법이 있다. 첫 번째는 코드를 이해하고 수정하기 쉽도록 단순하게 설계하는 것이다. 두 번째는 코드를 수정하지 않고도 변경을 수용할 수 있도록 코드를 더 유연하게 만드는 것이다. 

 

적절한 책임과 객체를 선택하는 것은 힘든 일이다. 만약 설계가 어렵다면 목적한 기능을 수행하는 코드를 작성하고, 리팩터링을 통해 코드를 개선하라

 

리팩터링

이해하고 수정하기 쉬운 소프트웨어로 개선하기 위해 겉으로 보이는 동작을 바꾸지 않은 채 내부 구조를 변경하는 것이다. 리팩터링을 통해 캡슐화를 향상하고 응집도는 높이고, 결합도는 낮춰야 한다. 긴 매서드를 작은 매서드로 분할해서 매서드의 응집도를 높이고 객체를 자율적으로 만드는 등 적절한 리팩터링 방법을 사용해야 한다.

 

*... 리팩터링을 하는 이유(긴 매서드의 단점)

더보기
  • 어떤 일을 수행하는지 한눈에 파악하기 어렵기 때문에 코드를 전체적으로 이해하는 데 너무 많은 시간이 걸린다
  • 하나의 매서드 안에서 너무 많은 작업을 처리하기 때무에 변경이 필요할 때 수정해야 할 부분을 찾기 어렵다
  • 매서드 내부의 일부 로직만 수정하더라도 매서드의 나머지 부분에서 버그가 발생할 확률이 높다
  • 로직의 일부만 재상용하는 것이 불가능하다
  • 코드를 재사용하는 유일한 방법은 원하는 코드를 복사해서 붙여넣는 것뿐이므로 코드 중복을 초래하기 쉽다.

 

 

 

 

Comments