참조
훨씬 좋은 내용이 많습니다. 많이 배웠습니다 감사합니다. 저자님
왜?
객체 지향적으로 짠다는 것은 무엇을까? 한번 생각해 보는 시점이 되었다.
어떻게 하면 더 좋은 코드를 짤수있을까?
예를 들면, request.checkValidation() 를 하는것이 좋은것인가?, 아니면, checkValidation(request)의 형태를 만드는 것이 더 객체 지향 스러운것인가? 너무 궁금헀다. => 결과적으론 이 문제는 상황마다 다르다라는 것이 정답이였다.(꼭 객체 지향이 좋은것도아님)
- 객체의 자율성을 보장한다면, instance.checkValidation()
- 하지만 여러 객체에서 쓰인다면, Validation 클래스에 뺴고, valid 역할 위임 이 적절할 것이다.
해당 질문에 고려해야할 부분
DTO의 밸리데이션은 비즈니스인가 아닌가, 밸리데이션이 모델들에 대해 공통화가 가능한가?
- 밸리데이션이 널체크면 비즈니스 아님
- (비즈니스) 어떤 커맨드만 요청이 가능하다, 어떤 커맨드는 이런 부수정보가 필요하다
하여튼 이제부터 책 리뷰를 써보자
핵심 요약
- 책임, 역할, 협력을 항상 생각하자
- 메세지가 책임을 결정한다.(설계의 시작점 = 메세지)
- 클래스가 아니라 행위, 속성에 대해 생각해보고, 타입(=개념)으로 분류하여, 설계하자
- 도메인 모델, 유스케이스 만들자
객체 지향이란?
- 클래스가 아니라 객체를 바라보는 것
- 객체를 독립적인 존재가 아니라 기능을 구현하기 위해 협력하는 공동체의 존재
- 협력에 참여하는 객체들에게 얼마나 적절한 역할과 책임을 부여
- 앞에서 설명한 개념들을 프로그래밍 언어라는 틀에 흐트러짐 없이 담아낼 수 있는 기술 활용
큰 목차
- 협력하는 객체들의 공동체
- 이상한 나라의 객체
- 타입과 추상화
- 역할, 책임, 협력
- 책임과 메시지
- 객체 지도
- 함께 모으기
협력하는 객체들의 공동체
협력하는 객체들의 공동체
역할: 협력하는 과정 속에 특정한 역할이 존재한다. 책임이나 의무를 의미한다.
책임: 역할에 포함되고, 특정 역할이 정해지면, 특정 책임이 있다.
협력: 요청과 응답을 통해 협력한다.
다른 객체에 요청을 통해 도움을 요청하고 → 받은 객체는 책임을 다해 응답한다!
특정 역할과 적합한 책임에 특징에 관하여
여러 사람이 동일한 역할을 수행할수있다. 손님입장에서 아무 캐시어든 상관없는것처럼(대체가능)
동일한 요청을 받아서 서로 다른 방식으로 응답할 수 있는 능력을 다형성
어떤 객체도 섬이 아니다 → 반드시 협력, 책임, 역할이있다.
객체 지향 설계 == 적절한 객체에게 적절한 책임을 할당하는것이다
역할 == 관련성 높은 책임의 집합이다.
- 역할은 대체 가능성을 의미한다
- 각 객체는 책임을 수행하는 방법을 자율적으로 선택(다형성)할수있다.
- 하나의 객체가 동시에 여러 역할을 수행할 수 있다.
협력의 참여하는 주체는 객체의 특징
- 객체는 충분히 협력적이여야한다. 모든것을 스스로 처리하는 전지전능한 god object는 복잡도자멸!
- 객체는 충분히 자율적이여야한다. 자기 스스로의 원칙에 따라 어떤 일을 하거나, 통제하여 절제하는것. 요청 받고 일에 스스로 책임진다. 누구에게 요청을 할지, 자신이 어떤 방식으로 처리할지 누가 정해주지않는다. 자율적으로 일을 판단, 책임진다.
객체는 흔히 상태와 행동을 함께 지닌 실체라고 정의한다. 객체는 조리법을 이미 알고있고, 필요한 상태와 행동을 알고있다.
객체 지향은 데이터와 프로세스를 하나의 객체라는 틀안에 묶어 놓으므로서 객체의 자율성을 보장한다
객체는 메세지로 서로 통신하며, 송신사, 수신자로 구별된다.
수신자는 먼저 수신된 메세지를 이해할 수 있는지 판단후, 미리 정해진 자신의 방법으로 메시지를 처리한다. 이를 메서드라고 부른다. 즉, 객체가 실행 시간에 적절한 메서드를 선택할 수 있다.
메세지와 메서드가 분리된것은 객체의 자율성을 높이며, 캡슐화 개념과 연관이 깊다
객체를 지향하라
- 객체지향의 핵심은 적절한 책임을 수행하는 역할 간의 유연하고 견고한 협력 관계를 구축하는 것이다. 클래스는 협력에 참여하는 객체를 만드는 데 필요한 구현 메커니즘일 뿐니다.
- 클래스의 구조와 메서드가 아니라 객체의 역할, 책임, 협력에 집중하자
- 객체는 행위에 따라 변할 수 있는 상태를 가지고있다
이상한 나라의 객체
- 객체는 결국 상태(state), 행동(behavior), 식별자(identity)를 갖고있다.
- 구별될수있고, 상태, 행동을 가진다.
- 상태를 가진이유는, 행동의 여부가 상태에 의존하기때문이다.(20cm이하만 통과하는 메서드 생각해보자)
- 앨리스와 객체
- 객체의 상태를 구성하는 모든 특징들을 통틀어 객체의 프로퍼티라고한다.(일반적으로 프로퍼티는 정적이다) 엘리스의 키, 위치, 음료
- 반면 프로퍼티(property)의 값은 동적이다 엘리스의 키, 위치, 음료 값은 계속 바뀔수있다.
- 객체의 프로퍼티는 속성과 링크의 두가지 조합으로 표현된다
- 객체와 객체 사이의 의미 있는 연결을 링크⇒ 객체의 링크(link)를 통해서만 메세지를 주고받을수있다.
- 객체가 참조값으로 가진 객체 식별자인 링크와 달리 객체를 구성하는 단순한 값은 속성(attribute) 이다
- 상태는 특정 시점에 객체가 가지고있는 정보의 집합으로 객체의 구조적 특징을 표현한다.
- 상태는 객체에 존재하는 정적인 프로퍼티와 동적인 프로퍼티 값으로 구성된다.
은유와 객체
- 객체의 세상과 지금의 세상은 다르다. 하지만 은유로서 쉽게 사용자를 설득할수있다.
- 현실세상에서의 메뉴는 자신의 행동을 직접할수없지만, 객체에서의 메뉴는 자율적 행동이 가능하다.
타입과 추상화
추상화를 통한 복잡성 극복
- 추상화가 되어 같은 타입(=개념)정의 하면, 인간이 쉽게 인지가능하다.
- 에스프레소, 아메리카노, 라떼 등을 음료수라는 타입으로 정의하면? 공통된 특성과 역할이 한번에 보인다. 또한 추상화된 음료수라는 타입은 단순하고, 빵이라는 타입과는 분류된다.
- 타입은 개념이다.
타입과 계층
개념
- 심볼: 개념을 가르키는 간략한 이름
- 자동차
- 내연: 개념의 완전한 정의를 나타내며, 내연의 의미를 이용해 객체가 개념에 속하는지 여부 확인가능
- 바퀴 4개, 이동, -> 자동차
- 외연: 개념에 속하는 모든 객체의 집합(set)
- 포르쉐, 람보르기니
- 심볼: 개념을 가르키는 간략한 이름
분류
- 분류란 객체에 특정한 개념을 적용하는것, 자동차-> 람보르기니, 포르쉐 등등 포함된다.
- 어떤 객체를 어떤 개념으로 분류할지가 객체지향의 품질을 결정한다.(유지보수관점, 변경 용이, 정신적인 지도)
- 결국 추상화를 위한도구다!
- 구체적인 객체의 공통점만 취하고, 일반화를 하고 단순화한다.
- 부분을 강조하기 위해불필요한 세부 사항을 제거해 단순화하는것이다.
- 객체는 복잡하기 떄문에 분류, 개념으로 추상화해야한다.
객체는 행동이 우선이다
- 객체는 어떤 행동을 하느냐에 따라 객체의 타입이 결정된다
- 객체의 내부 표현 방식이 다르더라도, 어떤 객체들이 동일하게 행동한다면, 그 객체들은 동일한 타입에 속한다 = 동일한 책임을 수행하는 일련의 객체는 동일한 타입에 속한다
- 같은 타입은 다른 데이터를 가져도, 행동만 동일하면 된다. 같은 메세지를 받아서 처리할수있는 책임이잇는것이다
- 다형성 = 동일한 요청에 대해 서로 다른 방식으로 응답할수있는 능력!
- 외부에 행동만을 제공하고 데이터는 행동 뒤로 감춘다 = 캡슐화
- 공용 인터페이스 뒤로 데이터를 캡슐화하라!
타입은 개념이다.
- 타입의 정의는 개념의 정의와 완전히 동일하다. 공통점을 기반으로 객체를 묶는 틀이다.
- 동일하게, 심볼, 내연, 외연을 이용해 서술하고, 타입에 속하는 객체 역시 타입의 인스턴스라고한다.
- 타입의 정의는 개념의 정의와 완전히 동일하다. 공통점을 기반으로 객체를 묶는 틀이다.
일반화와 특수화 관계
- 특수화 : 탈것 -> 자동차 -> 포르쉐
- 일반화: 포르쉐 -> 자동차 -> 탈것
슈퍼타입과 서브타입
- 주의할것은 두 타입간의 관계가 행동에 의해 결정되는것이다. 행위적 호환성 여부
- 서브타입은 슈퍼타입의 행위와 호환되기 떄문에 서브타입은 슈퍼타입을 대체할수있어야한다
일반화는 추상화를 위한 도구다
정적 모델
- 타입의 목적
- 쉽게 인지
- 시간에 따라 동적으로 변하는 상태의 변화를 동일한 타입으로 인지 가능
- 엘리스의 키가 100, 30, 40 cm 계속 바뀌는데 동일한 앨리스로 생각한다. (시간에 독립적인 타입)
- 타입 = 추상화
- 동적 모델과 정적 모델
- 클래스 (타입을 구현하는 가장 보편적인 방법)
책임의 분류
- 객체의 책임은 하는것과 아는것 로 구성된다. -> 공용 인터페이스로 구성가능 -> 캡슐화
역할 , 책임, 협력
협력
- 서로가 필요할 때, 요청 응답을 하며, 책임을 다하는 전체모습
책임
- 메세지가 정해지면, 메세지를 처리할 적절한 객체에게 책임을 부여한다.
역할
- 같은 역할을 하는 객체들을 서로 대체가 가능하다.
- 판사, 피고인, 피의자 의 역할이 있다면, 어떤 판사, 피고인, 피의자를 대려다 놓아도 똑같이 법정이 돌아가게된다.
객체의 모양을 결정하는 협력
객체지향 설계 기법
책임과 메세지
자율적인 책임
- 재판하라 -> 증언하라는 자율적이다
- 재판하라 -> 목격장면을 떠올려라 , 떠오르는 기억을 말해라, 말로 간결하게 표현하라 3가지를 같은 객체에게 물어보는건 자율적이지않다
- 증인은 증언할 책임이있는거지, 구체적인 방법과 절차는 자유다.
- 어떻게 가 아니라 무엇을 해야하는지 설명하는 것이 책임
메세지와 메서드
메세지를 따라라
- 메세지에는 무엇이 나온다.
- 메세지는 송신자와 수신자를 약하게 연결하게한다. -> 유연하고, 확장 가능하고, 재사용가능하게한다
- 메세지에서 What, Who를 적절히 선택한다. 무엇을 누가 처리할지!!! 설계하자
- 수신자가 잘 처리할것이라고 믿자.객체는 다른 객체의 상태를 묻지 말아야한다. 자율성 보장
- 상태를 묻지말고, 시켜라
객체 인터페이스
- 메세지가 인터페이스를 결정한다.
- 인터페이스는 객체가 수신할 수있는 메세지의 목록이다.
인터페이스와 구현의 분리(반드시)
- 추상적인 인터페이스(=자율적인 책임을 보장하라(증언하라 끝!))
- 최소 인터페이스(외부에서 필요없으면 노출 하지마라)
- 인터페이스와 구현간 분리하기(=캡슐화)
책임의 자율성이 협력의 품질을 결정한다
객체 지도
기능 설계 VS 구조 설계
도메인 모델(안정적인 구조)
- 사용자가 프로그램을 사용하는 대상 분야를 도메인이라고한다
- 도메인 모델이란 사용자가 프로그램을 사용하는 대상 영역에 관한 지식을 선택적으로 단순화하고 의식적으로 구조화한 형태다. 개념간의 관계, 규칙 제약 을 추상화
- 최종 제품은 사용자의 관점을 반영해야한다. 도메인 모델은 사용자들이 도메인을 바라보는 관점이며 설계자가 시스템의 구조를 바라보는 관점, 코드 모습 그자체 모두 일치화시키자
유스케이스(불안정한 기능)
- 기능은 항상 확장성을 가지고 있다
- 사용자들의 목표를 중심으로 시스템의 기능적인 요구사항을 이야기 형식으로 묶을수있다.(시나리오)
- 유스케이스는 여러 시나리오의 집합이다.
- 유스케이스는 단순한 기능 목록과 다르다
- 유스케이스는 사용자 인터페이스와 관련된 세부 정보를 포함하면안되고, 본직적인 유스케이스만 기록한다
- 유스케이스는 내부 설계와 관련된 정보를 포함하지않는다.
기능 변경흡수가능한 구조(도메인 모델 + 유스케이스)
- 도메인 모델과 유스케이스를 반드시 작성하자
함께 모으기
- 개념관점(도메인 모델) -> 명세관점(인터페이스 무엇?) -> 구현관점(어떻게? 클래스, 메서드 추가)
- 도메인 설정 -> 설계하고 구현하기 -> 코드와 세 가지 관점 -> 끝!
- 도메인을 설정
- 필요한 메세지들을 정함
- 메세지를 처리할 적절한 객체를 찾아 책임 부여
- 이를 인터페이스로 추상화
- 구현제에서 어떻게 처리할건지 구체화