역할, 책임, 협력 관계에서 본 객체지향
책을 읽으며 밑줄을 그어놨던 부분만 모아놓으려고 한다.
밑줄을 그은 기준은 지극히 주관적으로 그저 좋았던 부분을 그어놨을 뿐이다.
01 협력하는 객체들의 공동체
시너지를 생각하라. 전체는 부분의 합보다 크다. -스티븐 코비(Stephen R. Covey)
- 객체는 다른 객체가 '무엇(what)'을 수행하는지는 알 수 있지만 '어떻게(how)' 수행하는지에 대해서는 알 수 없다.
- 메시지와 메서드의 분리는 객체의 협력에 참여하는 객체들 간의 자율성을 증진시킨다.
- 핵심은 적절한 책임을 수행하는 역할 간의 유연하고 견고한 협력 관계를 구축하는 것이다.
02 이상한 나라의 객체
객체지향 패러다임은 지식을 추상화하고 추상화한 지식을 객체 안에 캡슐화함으로써 실세계 문제에 내재된 복잡성을 관리하려고 한다. 객체를 발견하고 창조하는 것은 지식과 행동을 구조화하는 문제다. -레베카 워프스브록(Rebecca Wirfs-Brock)[Wirfs-Brock 1990]
- 상태를 이용하면 과거의 모든 행동 이력을 설명하지 않고도 행동의 결과를 쉽게 예측하고 설명할 수 있다.
- 모든 객체의 상태는 단순한 값과 객체의 조합으로 표현할 수 있다.
- "행동이 상태를 결정한다."
03 타입과 추상화
일단 컴퓨터를 조작하는 것이 추상화를 구축하고, 조작하고, 추론하는 것에 관한 모든 것이라는 것을 깨닫고 나면 (훌륭한) 컴퓨터 프로그램을 작성하기 위한 중요한 전제 조건은 추상화를 정확하게 다루는 능력이라는 것이 명확해진다. -키스 데블린(Keith Devlin)[Devlin 2003]
- 추상화의 수준, 이익, 가치는 목적에 의존적이다.
- 주변의 복잡한 객체들은 단지 몇 가지 개념의 인스턴스일 뿐이다.
- 어떤 객체를 어떤 개념으로 분류할지가 객체지향의 품질을 결정한다.
- 어떤 데이터에 어떤 연산자를 적용할 수 있느냐가 그 데이터의 타입을 결정한다.
- 객체의 타입을 결정하는 것은 객체의 행동뿐이다.
- 다형적인 객체들은 동일한 타입(또는 타입 계층)에 속하게 된다.
- 서브타입은 슈퍼타입을 대체할 수 있어야 한다.
04 역할, 책임, 협력
우리 모두를 합친 것보다 더 현명한 사람은 없다. -켄 블랜차드(Ken Blanchard)
- 객체지향 설계의 전체적인 품질을 결정하는 것은 개별 객체의 품질이 아니라 여러 객체들이 모여 이뤄내는 협력의 품질이다.
- GOF의 [디자인 패턴][GOF 1994] (디자인 패턴과 관련된 가장 유명한 패턴 책)
05 책임과 메시지
의도는 "메시징"이다. 훌륭하고 성장 가능한 시스템을 만들기 위한 핵심은 모듈 내부의 속성과 행동이 어떤가보다는 모듈이 어떻게 커뮤니케이션하는가에 달려있다. -앨런 케이[Kay 1998]
- 객체가 자율적이기 위해서는 객체에게 할당되는 책임의 수준 역시 자율적이어야 한다.
- 클래스를 정의하는 것이 먼저가 아니라 객체들의 속성과 행위를 식별하는 것이 먼저다.
- 객체 설계의 핵심은 객체를 두 개의 분리된 요소로 분할해 설계하는 것이다.
06 객체 지도
유일하게 변하지 않는 것은 모든 것이 변한다는 사실뿐이다. -헤라클레이토스(Heraclitus of Ephesus)
- 안정적인 객체 구조는 변경을 수용할 수 있는 유연한 소프트웨어를 만들 수 있는 기반을 제공한다.
- 도메인 모델은 이해관계자들이 바라보는 멘탈 모델(Mental Model)이다.
- 도메인 모델은 여러분이 기능을 구현할 때 참조할 수 있는 궁극적인 지도다.
- 유스케이스의 가치는 사용자들의 목표를 중심으로 시스템의 기능적인 요구사항들을 이야기 형식으로 묶을 수 있다는 점이다.
- 변경에 유연한 소프트웨어를 만들기 위해서는 유스케이스에 정리된 시스템의 기능을 도메인 모델을 기반으로 한 객체들의 책임으로 분배해야 한다.
- 책임-주도 설계 방법은 시스템의 기능을 역할과 책임을 수행하는 객체들의 협력 관계로 바라보게 함으로써 두 가지 기본 재료인 유스케이스와 도메인 모델을 통합한다.
- 인터페이스를 정의하는 추상 클래스와 인터페이스를 구현하는 구체적인 클래스 간의 상속 관계는 클래스 기반의 객체지향 언어에서 다형성을 구현하는 가장 기본적인 방법이다.
- 사람들이 동일한 용어와 동일한 개념을 이용해 의사소통하고 코드로부터 도메인 모델을 유추할 수 있게 하는 것이 도메인 모델의 진정한 목표다.
07 함께 모으기
코드와 모델을 밀접하게 연관시키는 것은 코드에 의미를 부여하고 모델을 적절하게 한다. -에릭 에반스(Eric Evans)[Evans 2003]
- 객체가 다른 객체에게 메시지를 전송하기 위해서는 먼저 객체에 대한 참조를 얻어야 한다.
- 객체의 속성은 객체의 내부 구현에 속하기 때문에 캡슐화돼야 한다.
- 최대한 변화에 안정적인 인터페이스를 만들기 위해서는 인터페이스를 통해 구현과 관련된 세부 사항이 드러나지 않게 해야 한다.
- 메서드의 구현과 속성의 변경은 원칙적으로 외부의 객체에게 영향을 미쳐서는 안 된다.
부록A 추상화 기법
- 대부분의 언어에서 한 객체는 오직 한 클래스의 인스턴스여야만 하며 동시에 두 개의 클래스의 인스턴스일 수는 없다.
- 대부분의 언어는 일단 클래스로부터 인스턴스를 생성한 후 클래스를 변경할 수 있는 방법을 제공하지 않는다. 즉, 객체의 타입을 변경할 수 없다.
- 대부분의 객체지향 프로그래밍 언어에서 동일한 범주에 속하는 객체는 동일한 클래스의 인스턴스여야 한다.
- 서브타이핑은 설계의 유연성이 목표인 반면 서브클래싱은 코드의 중복 제거와 재사용이 목적이다. 흔히 서브타이핑을 인터페이스 상속(interface inheritance)이라고 하고, 서브클래싱을 구현 상속(implementation inheritance)이라고 한다.
- 어떤 객체의 클래스가 수신된 메시지를 이해할 수 없다면 메시지를 클래스의 부모 클래스로 위임한다.
- 패키지는 내부에 포함된 클래스들을 감춤으로써 시스템의 구조를 추상화한다.