text: # 오브젝트 책갈피
  
  ![https://wikibook.co.kr/object/](https://wikibook.co.kr/images/cover/l/9791158391409.jpg)
  
  [책](https://wikibook.co.kr/object/)은 기대만큼 너무나도 ~~좋다.~~ 좋을 것이다.(아직 다 본 건 아니므로..)
  
  학습 효과의 극대화를 위해 책갈피로 남겨두고 가능하다면 조금 다른 생각, 다른 표현도 곁들여보자.
  
  책의 내용은 다음과 같이 표시하고,
  
  >책 내용 (거의) 그대로
  
  덧붙이거나 다른 생각은 
  
  - 덧붙임
  - 다른 생각
  - 다른 표현
  
  으로 표시한다.
  
  격리를 위해 사용되는 일반적인 의미의 인터페이스는 `인터페이스`로, 자바의 interface는 `interface`로 표기한다.
  
  각 장 제목 바로 아래에 **굵은 글씨**는 장 내용 요약이 아니라 해당 장에서 내가 깨달은 것을 적었다.
  
  ## 01. 객체, 설계
  
  ### p13
  
  - `Theater.enter(Audience)` 보다는 `Theater.receive(Audience)`가 나을 듯
  
  ### p14
  
  #### 모듈의 3가지 기능?속성? by Robert C. Martin
  
    >- 실행 중 정상 동작
    >- 낮은 변경 비용
    >- 낮은 의사소통 비용
  
  #### 실행 중 정상 동작
  
    - 테스트로 보장
  
  #### 낮은 변경 비용
    - 불필요한 의존 관계 제거를 통해 달성
    - 의존의 반대말은 독립
    - 언제 독립 시키나? 믿을만한 자율성이 있을 때
    - 따라서 **객체에게 믿을만한 자율성을 줘야 독립시키고 불필요한 의존 관계를 제거할 수 있다.**
  
  #### 낮은 의사소통 비용
    - 관습, 규약, 패턴
    - 코드 리뷰
  
  ### p20
  
  #### 캡슐화
    
    >개념적이나 물리적으로 객체 내부의 세부적인 사항을 감추는 것을 **캡슐화(encapsulation)** 라고 부른다.
  
    - 캡슐화를 잘 하면 객체 내부 세부 사항이 감춰지는 효과가 나지만, 그렇다고 세부 사항을 감추는 것을 캡슐화라고 부르는 게 적절한가?
    - 이보다는 Holub on Patterns의 역자주 내용을 참고해서 캡슐화와 은닉을 구분하는 게 좋을 듯
      - 캡슐화(encapsulation)
        - 데이터와 연산을 한데 묶어서 스스로 처리하면서 **자율성 확보**
        - 흘러다니는 데이터의 양/종류와 결합도는 보통 비례하는데 **데이터와 연산을 한데 묶어서 결합도 증가를 막아주는 장치**
        - 주로 클래스와 관련이 깊다
      - 정보 감춤/숨김/은닉(information hiding)
        - 내부를 감춤으로써 자율성의 훼손을 방지하고
        - **자율성 훼손 방지를 통해 결합도 증가를 막아주는 장치**
        - 주로 접근 지정자(public, protected, private 등) 및 인터페이스와 관련이 깊다
  
  ### p25
  
  #### 객체 지향 설계 개선 방향
  
    >우리는 객체의 자율성을 높이는 방향으로 설계를 개선했다. 그 결과 이해하기 쉽고 유연한 설계를 얻을 수 있었다.
  
  ### p26
  
  #### 응집도
  
    >밀접하게 연관된 작업만을 수행하고 연관성 없는 작업은 다른 객체에게 위임하는 객체를 가리켜 응집도(cohesion)가 높다고 말한다.
    
    - 응집도에 위임 개념이 반드시 들어가야할까?
    - 객체 자신이 소유하고 있는 데이터를 많이 활용하면서 동작하는 객체는 위임하지 않더라도 응집도가 높다.
    - 소유하고 있지만 활용되지 않는 데이터가 많으면 응집도가 낮아지며, 이를 소유하지 않고 외부로 옮겨서 위임하면 응집도가 높아진다.
    - 객체 자신이 소유하고 있지 않은 데이터를 많이 활용하면서 동작하는, 다시 말해 다른 객체에게 데이터를 요구하는 방식으로 동작하는 객체는 결합도가 높다.
  
  #### 절차적 프로그래밍
  
    >프로세스와 데이터를 별도의 모듈에 위치시키는 방식을 절차적 프로그래밍이라 한다.
  
  #### 절차적 프로그래밍과 직관
  
    >일반적으로 절차적 프로그래밍은 우리의 직관에 위배된다. 우리는 관람객과 판매원이 자신의 일을 스스로 처리할 것이라고 예상한다.
  
    - 다른 관점에서 보면 절차적 프로그래밍은 우리의 직관에 위배되는 것이 아니라, 우리의 직관을 그대로 옮긴다.
      - 영화관 입장이라는 처리 흐름 관점에서는 관람객, 판매원, 극장 등의 자율성 있는 객체의 협력망을 떠올리기보다는 금액, 티켓, 차감 등 데이터와 동작을 처리 흐름에 따라 절차적으로 나열하는 것이 더 직관에 부합한다.
      - 또한 무생물인 극장, 매표소 등이 자율적으로 동작한다고 생각하는 것 역시 직관에 부합하지 않는다.
      - 이처럼 절차적 프로그래밍이 직관에 더 부합하기 때문에 객체 지향 프로그래밍보다 더 먼저 정립된 것이 아닐까.
  
  ### p27
  
  #### 객체지향 프로그래밍
  
    >데이터와 프로세스가 동일한 모듈 내부에 위치하도록 프로그래밍하는 방식을 객체지향 프로그래밍이라고 부른다.
  
    - **연관된 데이터와 프로세스를 하나의 자율적인 객체로 캡슐화해서 절차의 나열이 아니라 객체의 협력을 통해 문제를 해결하는 프로그래밍 방식을 객체지향 프로그래밍이라고 부른다.**
  
  ### p29
  
  #### 캡슐화와 정보 감춤
  
    >예제에서 결합도를 낮추기 위해 선택한 방법은 Theater가 몰라도 되는 세부사항을 Audience와 TicketSeller 내부로 감춰 캡슐화하는 것이다.
  
    - 어쩌면 이 책에서는 캡슐화와 정보 감춤(information hiding)을 일부러 캡슐화 하나로 퉁친 듯. 정보 감춤(또는 은닉, 숨김)이 용어 자체로도 불필요한 것을 감춘다는 의미를 더 구체적으로 전달하므로 캡슐화보다 전달력이 더 좋다고 생각.
  
  ### p34
  
  #### 객체지향은 실세계를 그대로 반영?
  
    >실세계에서는 생명이 없는 수동적인 존재라고 하더라도 객체지향의 세계로 넘어오는 순간 그들은 생명과 지능을 가진 싱싱한 존재로 다시 태어난다.
  
    - 객체지향은 실세계를 그대로 반영하지 않으며, 무생물을 자율적인 존재로 의인화하는 과정이 필요.
  
  ### p35
  
  #### 좋은 설계란?
  
    >오늘 요구하는 기능을 온전히 수행하면서 내일의 변경을 매끄럽게 수용할 수 있는 설계
  
  ### p36
  
  #### 좋은 객체지향 설계란?
  
    >협력하는 객체 사이의 의존성을 적절하게 관리하는 설계
  
    - 적절한 의존성에서의 적절은 양과 방향 관점으로 나눌 수 있다.
    - 객체의 자율성을 높이면 의존성의 양을 줄일 수 있다.
    - 의존성의 방향은 나중에 나올 듯
  
  
  
  
  
  ## 02. 객체지향 프로그래밍
  
  - **객체지향의 핵심은 스스로 상태를 관리하고, 판단하고, 행동하는 자율적인 객체들의 협력망을 구성하는 것이다.**
  - **추상화를 통해 세부 구현 내용 없이 정책 수준에서 애플리케이션의 협력 흐름을 단순화해서 표현할 수 있다.**
  - **구현 내용의 재사용을 위해 상속을 사용하는 것은 대부분 좋지 않은 선택이다.**
  - **상속이 잘못 사용되면 좋지 않은 이유는 abstract 등의 키워드를 통해 인터페이스를 공유하기 때문이 아니라, protected 등으로 서브클래스에게 공개하는 부분이 있고 이것이 정보 감춤을 위반하기 때문이다.**
  
  ### p41
  
  #### Object-oriented의 의미
  
    >진정한 객체지향 패러다임으로의 전환은 클래스가 아닌 객체에 초점을 맞출 때에만 얻을 수 있다.
    >
    >어떤 클래스가 필요한지를 고민하기 전에 어떤 객체들이 필요한지 고민하라. 클래스는 공통적인 상태와 행동을 공유하는 객체들을 추상화한 것이다. 따라서 클래스의 윤곽을 잡기 위해서는 어떤 객체들이 어떤 상태와 행동을 가지는지를 먼저 결정해야 한다.
    >
    >객체지향적으로 생각하고 싶다면 객체를 고립된 존재로 바라보지 말고 협력에 참여하는 협력자로 바라보기 바란다.
    >
    >객체들의 모양과 윤곽이 잡히면 공통된 특성과 상태를 가진 객체들을 타입으로 분류하고 이 타입을 기반으로 클래스를 구현하라.
  
    - 객체는 자율성을 갖고 있고 내/외부가 격리돼있지만, 그렇다고 서로 떨어져 고립된 채 살아가는 존재가 아니다.
    - 먼저 객체를 식별하고 객체를 바탕으로 타입을 도출한다.
  
  ### p44
  
  #### 객체지향의 핵심
  
    >객체지향의 핵심은 스스로 상태를 관리하고, 판단하고, 행동하는 자율적인 객체들의 공동체를 구성하는 것
    
    - **객체지향의 핵심은 스스로 상태를 관리하고, 판단하고, 행동하는 자율적인 객체들의 협력망을 구성하는 것**
  
  ### p45
  
  #### 접근 제어의 의의
  
    >변경될 가능성이 있는 세부적인 구현 내용을 private 영역 안에 감춤으로써 변경으로 인한 혼란을 최소화할 수 있다.
  
  ### p47
  
  #### 객체의 표현력
  
    >Long 타입은 변수의 크기나 연산자의 종류와 관련된 구현 관점의 제약은 표현할 수 있지만, Money 타입처럼 저장하는 값이 금액과 관련돼 있다는 의미를 전달할 수는 없다.  
    >또한 (Long 타입은) 금액 관련 로직이 (Long 안에 존재할 수 없으므로) 서로 다른 곳에 중복되어 구현되는 것을 막을 수 없다. 
    >**비록 하나의 인스턴스 변수만 포함하더라도 개념을 명시적으로 표현하는 것은 전체적인 설계의 명확성과 유연성을 높이는 첫걸음이다.**
  
  ### p49
  
  #### 메시지
  
    >객체가 다른 객체와 상호작용할 수 있는 유일한 바업은 메시지를 전송(send a message)하는 것뿐이다.
  
    - 객체가 다른 객체화 협력할 수 있는 유일한 의사소통 수단은 메시징이다.
  
  #### 메서드
  
    >메시지를 수신한 객체는 스스로의 결정에 따라 자율적으로 (받은) 메시지를 처리할 방법을 결정한다. 이처럼 수신된 메시지를 처리하기 위한 (객체) 자신만의 방법을 메서드(method)라고 부른다.
  
    - 앨런 케이의 설명에 따르면 메시지에는 메서드만 대응되는 게 아니라 데이터도 대응될 수 있다. [객체 지향 프로그래밍과 메시징](https://homoefficio.github.io/2019/07/04/객체-지향-프로그래밍과-메시징/) 참고
  
  ### p57
  
  #### 컴파일 시간 의존성과 실행 시간 의존성
  
    - 컴파일 시점(Compile time) 의존성과 실행 시점(Runtime) 의존성
  
  ### p59
  
  #### 코드의 의존성과 실행 시점의 의존성
  
    >코드의 의존성(컴파일 시점 의존성)과 실행 시점(Runtime)의 의존성은 동일하지 않을 수 있다.
  
    - 코드 상에서는 수퍼클래스에 의존하지만 실행 시점에서는 구체적 서브클래스에 의존한다. 이를 가능하게 하는 것이 다형성이다.
  
  ### p61
  
  #### 상속의 숨은 의의
  
    >상속이 가치 있는 이유는 부모 클래스가 제공하는 모든 인터페이스를 자식 클래스가 물려받을 수 있기 때문이다.
    >
    >인터페이스는 객체가 이해할 수 있는 메시지의 목록을 정의한다는 것을 기억하라. 결과적으로 자식 클래스는 부모 클래스가 수신할 수 있는 모든 메시지를 수신할 수 있기 때문에 외부 객체는 자식 클래스를 부모 클래스와 동일한 타입으로 간주할 수 있다.
  
    - 상속하면 보통 public, protected인 메서드나 필드를 물려받는 것을 떠올리는데, 정작 중요한 것은 인터페이스를 물려받는 다는 것
  
  ### p62
  
  #### Upcasting
  
    >자식 클래스가 부모 클래스를 대신하는 것을 업캐스팅(Upcasting)이라고 부른다.
  
  ### p63
  
  #### 다형성(Polymorphism)
  
    >다형성이란 동일한 메시지를 수신했을 때 객체의 타입에 따라 다르게 응답할 수 있는 능력을 의미한다.
  
    - 즉 어떤 받은 메시지에 대해 어떤 메서드를 통해 처리하고 응답할 지는 메시지를 실제로 받은 객체 스스로 결정한다.
  
  #### 동적 바인딩(Dynamic-binding), 지연 바인딩(Late-binding)
  
    >메시지와 메서드를 실행 시점에 바인딩하는 것
  
  #### 정적 바인딩(Static-binding), 초기 바인딩(Early-binding)
  
    >전통적인 함수 호출처럼 컴파일 시점에 실행될 함수나 프로시저를 결정하는 것
  
  ### p64
  
  #### 구현 상속과 인터페이스 상속
  
    >다형적인 협력을 위해 부모 클래스와 자식 클래스가 인터페이스를 공유할 수 있도록 상속을 이용하는 것을 인터페이스 상속(Interface inheritance) 또는 서브타이핑(Subtyping)이라고 부른다.
  
    - 동적 바인딩을 활용해서 다형적 협력을 구성하기 위해 인터페이스를 공유하는 상속을 인터페이스 상속 또는 서브타이핑이라고 부른다.
  
    >순수하게 코드를 재사용할 목적으로 상속을 사용하는 것을 구현 상속(Implementation inheritance) 또는 서브클래싱(Subclassing)이라고 부른다.
  
    - 인터페이스 공유가 필요한 부모 자식 관계가 아님에도 불구하고 그저 구현 내용을 상속을 통해 재사용하는 것을 구현 상속 또는 서브클래싱이라고 부른다.
  
  ### p65-p66
  
  #### 추상화의 힘
  
    >추상화 계층만 따로 떼어 놓고 살펴보면 요구사항의 정책을 높은 수준에서 서술할 수 있다.
    >
    >추상화를 사용하면 세부사항에 억눌리지 않고 상위 개념만으로도 도메인의 중요한 개념을 설명할 수 있게 한다.
    >
    >추상화를 이용한 설계는 필요에 따라 표현의 수준을 조정하는 것을 가능하게 해준다.
    >
    >추상화를 이용해 상위 정책을 기술한다는 것은 기본적인 애플리케이션의 협력 흐름을 기술한다는 것을 의미한다.
  
    - 추상화는 의사소통에 필요하지 않은 세부 내용을 덜어내고 단순화하는 것을 말한다. 덜어낸다는 것은 결국 보여지지 않게 감추는 효과가 있으므로 추상화 역시 정보 감춤의 장점인 자율성과 유연성을 확보하는 데 도움이 된다.
  
    - 추상화를 통해 세부 구현 내용 없이 정책 수준에서 애플리케이션의 협력 흐름을 단순화해서 표현할 수 있다.
  
  ### p67
  
  #### 겉보기에 예외로 보이는 상황 해결
  
    ```java
    public class Movie {
      public Money calculateMovieFee(Screening screening) {
        if (discountPolicy == null) {
          return fee;
        }
  
        return fee.minus(discountPolicy.cacluateDiscountAmount(screening));
      }
    }
    ```
    
    >할인 정책이 없는 경우에는 할인 금액이 0이라는 사실을 결정하는 책임이 DiscountPolicy가 아닌 Movie 쪽에 있다.
    >
    >책임의 위치를 결정하기 위해 조건문을 사용하는 것은 협력의 설계 측면에서 대부분의 경우 좋지 않은 선택이다.
  
    - 할인 정책이 없는 경우를 특별한 케이스로 취급해서 Movie에게 책임을 부과하는 것보다, 할인 정책이 없는 것 자체를 하나의 할인 정책(NoneDiscountPolicy)으로 정의해서 할인 금액이 없음을 결정하는 책임을 Movie에서 DiscountPolicy로 옮기는 것이 좋다.
  
    - 현실에서는 할인 정책 자체가 존재하지 않는 케이스지만 객체지향 설계에서는 정책이 없는 게 아니라 할인 금액이 없는 하나의 정책으로 취급한다. 이런 점도 의인화와 함께 객체지향이 현실 세계를 있는 그대로 반영하는 것이 아니라는 증거가 된다.
  
  ### p68
  
  - 이해가 잘 안 되는 부분
  
    >앞의 NoneDiscountPolicy 클래스의 코드를 자세히 살펴보면 getDiscountAmount() 메서드가 어떤 값을 반환하더라도 상관이 없다는 사실을 알 수 있다. (중략) NoneDiscountPolicy의 개발자는 getDiscountAmount()가 호출되지 않을 경우 DiscountPolicy가 0원을 반환할 것이라는 사실을 가정하고 있기 때문이다.
  
    - NoneDiscountPolicy 코드는 다음과 같은데 이 중 DiscountPolicy가 0원을 반환할 것이라는 사실을 가정하고 있는 부분이 있나?
  
      ```java
      public class NoneDiscountPolicy extends DiscountPolicy {
        @Override
        protected Money getDiscountAmount(Screening screening) {
          return Money.ZERO;
        }
      }
      ```
  ### p70
  
  - 잘 이해가 안 되는 상속이 캡슐화를 위반한다는 사례
  
    >상속의 가장 큰 문제점은 캡슐화를 위반한다는 것이다. 상속을 이용하기 위해서는 부모 클래스의 내부 구조를 잘 알고 있어야 한다. AmountDiscountMovie와 PercentDiscountMovie를 구현하는 개발자는 부모 클래스인 Movie의 calculateMovieFee 메서드 안에서 추상 메서드인 getDiscountAmount 메서드를 호출한다는 사실을 알고 있어야 한다.
  
    - 여기에서도 캡슐화와 정보 감춤을 퉁쳐서 캡슐화라고 쓰고 있다. 앞에서도 언급했지만 이런 문맥에서는 캡슐화와 정보 감춤을 엄밀하게 나눠서 상속이 정보 감춤을 위반한다고 하는 게 불필요한 혼선을 막는 데 더 도움이 될 것 같다.
  
    - 서브클래스 입장에서, 자기가 override하고 있는 메서드가 '수퍼클래스의 어디에선가 호출된다'는 사실을 알고 있는 걸 '서브클래스가 수퍼클래스의 내부 구조를 잘 알고 있다'라고 해석해야할 필요가 있나 싶다.
  
      - 서브클래스 입장에서는 상속에 의해 자기가 구현해야할 메서드가 강제된 것 뿐이고, 이는 상속이 아니라 인터페이스를 구현할 때도 마찬가지다. 다만 한 가지 차이점은 상속에서는 서브클래스가 구현하는 메서드를 수퍼클래스가 호출한다는 점을 서브클래스가 알 수 있다는 점이고, 인터페이스 구현에서는 구현한 메서드를 누가 호출할지 모른다는 점이다.
  
      - 그런데 누가 호출할지 안다고 해도 그저 수퍼클래스가 호출할지 안다는 것 뿐이고, 수퍼클래스에서 내부적으로 어떻게 호출되는 지는 알 수 없다. 즉, 서브클래스가 구현한 메서드를 c()라고 할 때, a() -> b() -> c()로 호출될지 a() -> c()로 호출될지 서브클래스는 알 수 없다.
  
      - 따라서 최소한 책에서 예로든 메서드 관점에서는 서브클래스가 부모클래스의 내부 구조를 잘 알고 있다고 결론 짓는 건 적절하지 않아 보인다.
  
    - 상속이 잘못 사용되면 좋지 않은 이유는 abstract 등의 키워드를 통해 인터페이스를 공유하기 때문이 아니라, protected 등으로 서브클래스에게 공개하는 부분이 있고 이것이 정보 감춤을 위반하기 때문이다.
  
  ### p72
  
  #### 상속의 적절한 사용 사례
  
    >코드를 재사용하는 경우에는 상속보다 합성을 선호하는 것이 옳지만,
    >다형성을 위해 인터페이스를 재사용하는 경우에는 상속과 합성을 함께 조합해서 사용할 수 밖에 없다.
  
    - 구현을 재사용하기 위한 목적으로 상속을 사용하는 것은 강한 결합을 유발하므로 좋지 않다.
    - 다형성을 사용한 문제 해결이 필요한 상황에서 인터페이스 공유를 위해 상속을 사용하는 것은 괜찮다.
      - 단 이 경우에도 정보 감춤 위반을 최소화해야 한다.
  
  
  
  
  
  ## 03. 역할, 책임, 협력
  
  - **Collaboration ---reference---> Role ---select from---> Object ---instance of---> Class**
  - **협력망 안에서 관련된 여러 책임을 한데 묶으면 역할이 되고, 이 역할을 교체 가능한 객체가 수행하며, 객체는 클래스의 인스턴스다.**
  
  ### p74
  
  #### 역할, 책임, 협력의 간결한 정의
  
    >객체들이 애플리케이션의 기능을 구현하기 위해 수행하는 상호작용을 **협력**이라고 한다.
    >
    >객체가 협력에 참여하기 위해 수행하는 로직은 **책임**이라고 부른다.
    >
    >객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 **역할**을 구성한다.
  
    - 역할과 책임을 구분해서 설명하기 참 어려운데, 책임들이 모여 역할을 구성한다고 하니 딱 좋다.
  
  ### p77
  
  #### 객체와 행동과 협력
  
    >Movie의 행동을 결정하는 것을 영화 예매를 위한 협력이다. 협력이라는 문맥을 고려하지 않고 Movie의 행동을 결정하는 것은 아무런 의미가 없다. 협력이 존재하기 때문에 객체가 존재하는 것이다.
  
    - Movie라는 객체의 책임은 단순히 현실에 존재하는 Movie에서 유추해서 도출할 수 있는 것이 아니다. 영화 예매라는 협력망 안에서 도출되어야 한다.
  
  #### 객체의 상태와 행동
  
    >객체의 행동을 결정하는 것이 협력이라면, 객체의 상태를 결정하는 것은 행동이다. 객체의 상태는 그 객체가 행동을 수행하는 데 필요한 정보가 무엇인지로 결정된다. 객체는 자신의 상태를 스스로 결정하고 관리하는 자율적인 존재이기 때문에 객체가 수행하는 행동에 필요한 상태도 함께 가지고 있어야 한다.
  
    - 객체지향에서 행동과 상태는 닭과 달걀이 아니라 언제나 행동이 상태보다 먼저고 우선이다.
  
  ### p78
  
  #### 책임과 행동
  
    >협력에 참여하기 위해 객체가 수행하는 행동을 책임이라고 부른다.
  
    - 미묘한 차이지만 '행동을 책임이라고 부른다'라고 표현하면 행동을 먼저 만들고 이를 책임이라고 부른다는 뉘앙스가 느껴진다.
    - 먼저 책임이 정립되고 그 책임을 완수하기 위해 그에 맞는 행동이 필요한 게 아닐까.
    - 책임은 설계 관점에 가까운 용어고, 행동은 구현 관점에 가까운 느낌이 든다.
    - 하지만 실질적으로는 동일한 것을 가리킨다고 봐도 무방할 것 같다.
      - 책에서 예로 들고 있는 DiscountPolicy는 할인 금액을 계산하는 책임을 가지고 있다. 그리고 할인 금액 계산이라는 책임을 완수하기 위해 서브클래스 AmountDiscountPolicy는 정액 할인이라는 행동을 가지고 있고, 또 다른 서브클래스 PercentDiscountPolicy는 정률 할인이라는 행동을 가지고 있다.
      - AmountDiscountPolicy의 정액 할인은 행동이자 책임이고, PercentDiscountPolicy의 정률 할인은 행동이자 책임이다.
  
  ### p81
  
  #### CRC 카드
    
    >설계 초기에 책임을 할당할 후보는 객체일 수도 있고 역할일 수도 있다. 중요한 것은 후보(Candidate)를 어떻게 구현할 것인가가 아니라 어떤 후보에게 어떤 책임을 할당할 것인가에 집중하는 것이다. C를 클래스로 보는 관점에서는 설계의 자연스러운 흐름을 방해하고 처음부터 구현 중심적인 사고로 빠지게 만들 위험이 도사리고 있다.
  
    - 설계 과정에서 클래스를 너무 일찍 등장시키면 협력과 책임에 대한 고민이 아니라 구현에 대한 고민에 빠지게 할 위험이 크다.
      - 클래스는 설계 과정에서 사용되는 등장 인물이 아니라 설계 결과로 나오는 결과물이라고 보는 게 좋다.
  
  #### 정보 전문가(Information Expert) 패턴
  
    >자율적인 객체를 만드는 가장 기본적인 방법은 책임을 수행하는 데 필요한 정보를 가장 잘 알고 있는 전문가(Information Expert, 사람이 아니라 객체를 의미)에게 그 책임을 할당하는 것이다. 이를 책임 할당을 위한 정보 전문가 패턴이라고 한다.
  
  ### p82 - p83
  
  #### 객체지향 설계 과정
  
    >객체지향 설계는 시스템의 책임을 완료하는 데 필요한 더 작은 책임을 찾아내고 이를 객체들에게 할당하는 반복적인 과정을 통해 모양을 갖춰간다.
  
  #### 시스템의 원초적인 책임 정의부터 설계 시작
  
    >시스템이 사용자에게 제공해야 할 기능은 영화를 예매하는 것이고 이 기능을 시스템이 제공할 책임으로 할당할 것이다.
  
  #### 협력은 메시지 정의로 시작
  
    >객체가 책임을 수행하게 하는 유일한 방법은 메시지를 전송하는 것이므로 책임을 할당한다는 것은 메시지의 이름을 결정하는 것과 같다. 이 예에서는 `예매하라`라는 이름의 메시지로 협력을 시작하는 것이 좋을 것 같다.
  
  #### 메시지 처리 담당 객체 선정
  
    >영화 예매와 관련된 정보를 가장 많이 알고 있는 객체(인 Screening)에게 책임을 할당하는 것이 바람직하다.
    >
    >Screening은 예매에 대해서는 정보 전문가일지 몰라도 영화 가격 자체에 대해서는 정보 전문가가 아니다. (따라서 Screening도 `가격을 계산하라`라는 메시지를 외부로 보내며 협력을 요청한다.
    >
    >가격 계산을 가장 잘 알고 있는 정보 전문가는 Movie이므로 Movie에게 가격 계산 책임을 할당한다.
  
  - 위 과정을 반복하면서 설계가 모습을 갖춰간다는 얘기
  
  ### p84 - p85
  
  #### 책임 주도 설계 방법
  
    >1. 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.
    >2. 시스템 책임을 더 작은 책임으로 분할한다.
    >3. 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.
    >4. 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.
    >5. 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.
  
  #### 메시지가 객체를 결정한다.
  
    >객체에게 책임을 할당하는 데 필요한 메시지를 먼저 식별하고 메시지를 처리할 객체를 나중에 선택했다는 것이 중요하다.  
    >다시 말해, 객체가 메시지를 선택하는 게 아니라 메시지가 객체를 선택하게 했다.
  
    - 그럼 메시지를 처리할 객체를 선택하는 기준은 무엇인가?
    - '선택'한다는 것은 최소한 그 후보군이 이미 존재한다는 얘기인데,
      - 이 후보군은 애초에 어떤 기준으로 만들어지는 건지에 대한 설명이 없는 것 같다.
        - ~~즉, 후보군이라고 할 수 있는, p41에 나오는 최초의 역할들(그림 2.3 제목에는 '타입들'이라고 써있는 예매, 상영, 영화, 할인 정책, 할인 조건 등)은 애초에 어떻게 도출된 것인가?~~
        - ~~아마도 도메인 전문가와 함께 고민하며 도출하는 것일텐데, 그 도출 기준은 무엇일까? 만약 그 도출 기준이 메시지라면 다음과 같은 모순이 발생한다.~~
          - ~~후보군이 메시지보다 먼저 존재해야 후보군 중에서 선정을 할 수 있는데, 후보군의 도출 기준이 또 메시지라면 모순이 아닌가?~~
        - ~~그렇다면 후보군의 도출 기준은 무엇인가?~~
        - **틀리다. 후보군은 역할들이 아니고, 정해진 역할을 수행할 수 있는 객체들이 후보군이다.**
        - **역할은 메시지와 선후 관계 없이 함께 도출된다.**
    - **메시지가 (이미 존재하는 객체 중에서) 객체를 선택한다기보다, 메시지에 대응하는 역할을 수행할 수 있는 객체와 그 객체가 협력에 참여할 수 있는 행동이 이 시점에 처음 만들어진다고 보는 게 낫지 않을까?**
      - 이렇게 보면 정보 전문가 패턴이라는 게 유효한 건지 모르겠다.
        - 메시지를 처리할 정보를 잘 아는 객체를 이 시점에서 판별할 수 있는건지 모르겠다. 왜냐하면 이 시점에서는 메시지와 역할이 존재할 뿐이고, 객체는 이제 설계하기 시작하는 시점이기 때문이다.
        - 따라서 어느 객체가 어떤 정보를 가지고 있는지 모르고, 심지어 어떤 객체가 존재하는지 마저 알 수 없는데 무슨 전문가가 존재하며 누굴 선택한다는 건가..
  
  #### 행동이 상태를 결정한다.
  
    >객체가 협력에 적합한지를 결정하는 것은 그 객체의 상태가 아니라 행동이다.
  
    - 상태가 먼저 존재하는 게 아니라 행동에 필요한 상태를 이 때 설계한다.
  
  ### p86
  
  #### 역할과 객체
  
    >협력을 모델링할 때는 객체에게 책임을 할당하는 게 아니라 역할에게 책임을 할당한다고 생각하는 게 좋다.
    >
    >`예매하라`라는 메시지를 처리하기에 적합한 객체로 Screening을 선택했다. 하나의 단계처럼 보이는 이 책임 할당 과정은 실제로는 (역할 정립과 역할에 맞는 객체의 선택이라는) 두 개의 독립적인 단계가 합쳐진 것이다.
  
    - 앞에 쓴 대로 Screening을 선택했다 라기보다 Screening을 이 시점에 설계한다 가 더 나을 듯.
    - 역할과 객체를 어떻게 구분해서 표현할 수 있을까 했는데 이처럼 명쾌할 수가 없다.
  
  ### p88
  
  #### 역할과 객체
  
    >역할은 두 종류의 객체를 교대로 바꿔 끼울 수 있는 일종의 슬롯으로 생각할 수 있다.
    >
    >역할은 두 종류의 구체적인 객체를 포괄하는 추상화라는 점에 주목하라.
  
  #### 역할과 책임
  
    >역할은 다른 것으로 교체할 수 있는 책임의 집합이다.
  
  #### 역할은 주어진 책임을 완수하도록 추상화된 슬롯이고, 객체는 이 슬롯에 끼워져서 주어진 책임을 완수한다.
  
  ### p89
  
  #### 역할의 구현
  
    >역할을 구현하는 가장 일반적인 방법은 추상 클래스와 인터페이스를 사용하는 것이다.
  
    - 추상 클래스와 인터페이스는 역할에 주어진 책임 완수를 위해 메시지가 오갈 수 있는 통로를 외부에 제공하고 책임 완수를 위한 로직을 내부로 캡슐화한다.
  
  ### p91
  
  #### 협력, 역할, 객체, 클래스의 관계
  
    >Collaboration ---reference---> Role ---select from---> Object ---instance of---> Class
  
  #### 무엇부터?
  
    >대부분의 경우 어떤 것이 역할이고, 어떤 것이 객체인지 또렷하게 드러나지는 않을 것이다. 특히나 설계 초반에는 결정을 내리기가 더욱 어렵다.
    >
    >설계 초반에는 적절한 책임과 협력의 큰 그림을 탐색하는 것이 가장 중요한 목표여야 하고 역할과 객체를 구분하는 것은 그렇게 중요하지는 않다.
    >
    >이에 대한 개인적인 견해는애매하다면 단순하게 객체로 시작하고 반복적으로 책임과 협력을 정제해가면서 필요한 순간에 객체로부터 역할을 분리해내는 것이 가장 좋은 방법이다.
  
    - 앞에서 처음에는 역할이 메시지와 선후관계 없이 함께 도출되고, 메시지에 의해 객체가 정의되므로,
    - 메시지가 이미 만들어진 객체를 선택한다기보다 메시지에 의해 객체가 처음 만들어진다고 보는 게 낫겠다는 자체 결론을 내렸는데, 
    - 이렇게 역할과 객체 구분이 초기에는 쉽지 않으니 일단 객체로 시작하고,
    - 책임을 완수하는 방법이 여러 개임이 드러났을 때 역할과 책임을 분리하는 게 좋은 방법이라고 하니, 
    - 메시지에 따라 객체를 '선택'한다는 말도 유효해졌다.
    - 하지만, 결과적으로 객체가 역할이 될 수도 있으니까 현실적으로 이런 방법을 취할 수도 있는 것이고,
    - 원론적으로는 여전히 그 시점에서는 메시지와 역할만이 존재한다고 보는 것이 맞다고 생각한다.
  
  ### p96
  
  #### 역할과 객체
  
    >객체는 다수의 역할을 보유할 수 있지만, 객체가 참여하는 특정 협력은 객체의 한 가지 역할만 바라볼 수 있다.
  
    - 객체는 다수의 인터페이스를 구현할 수 있고, 어느 협력에 참여하느냐에 따라 해당 협력과 관련한 인터페이스로 업캐스팅되면 해당 인터페이스의 역할만 수행할 수 있다.
  
  
  
  
  
  ## 04. 설계 품질과 트레이드 오프
  
  - **캡슐화를 일부 하더라도 인터페이스를 통해 새어나가는 세부사항이 여전히 남아있을 수 있다.**
  
  ### p97
  
  #### 객체지향 설계란?
  
    >올바른 객체에게 올바른 책임을 할당하면서 낮은 결합도와 높은 응집도를 가진 구조를 창조하는 활동이다.
  
  
  ### p98
  
  #### 데이터 중심 설계의 위험성
  
    >상태를 객체 분할의 중심축으로 삼으면 구현에 관한 세부사항이 객체의 인터페이스에 스며들게 되어 캡슐화의 원칙이 무너진다. 결과적으로 상태 변경은 인터페이스의 변경을 초래하며 이 인터페이스에 의존하는 모든 객체에게 변경의 영향이 퍼지게 된다.
  
    - 4장 내용에서 가장 큰 깨달음을 얻은 부분이다.
  
  ### p109
  
  #### 객체지향에서 가장 중요한 원리는 캡슐화
  
    >객체지향에서 가장 중요한 원리는 캡슐화다.
    >
    >객체지향 설계의 가장 중요한 원리는 불안정한 구현 세부사항을 안정적인 인터페이스 뒤로 캡슐화하는 것이다.
  
    - 정보 감춤도 캡슐화에 포함된다고 본다면 타당하다.
  
    >응집도, 결합도, 중복 (방지) 역시 훌륭한 코드를 규정하는 데 핵심적인 품질인 것이 사실이지만 캡슐화는 우리를 좋은 코드로 안내하기 때문에 가장 중요한 제1원리다.
  
    - 캡슐화를 잘 하면 응집도를 높아질 수 있고 결합도가 낮아질 수 있으므로 가장 중요한 원리는 캡슐화라는 말이 정말 맞는 것 같다.
  
  ### p110 - p111
  
  #### 응집도
  
    >모듈 내의 요소들이 하나의 목적을 위해 긴밀하게 협력한다면 그 모듈은 옾은 응집도를 가진다.
    >
    >응집도가 낮은 설계에서는 하나의 원인에 의해 변경해야 하는 부분이 다수의 모듈에 분산돼 있기 때문에 여러 모듈을 동시에 수정해야 한다.
  
    - 응집도 저하는 두 가지 상황에서 발생한다. 하나의 객체가 여러 책임을 가지고 있을 때, 하나의 책임이 여러 객체에 분산돼 있을 때.
    - 모듈 내의 요소 중에 긴밀하게 협력하지 않는 것이 있다면 응집도가 낮아지며, 이들은 잘못된 모듈 안에 자리잡고 있을 가능성이 크며 분리해야할 유력한 후보다.
    - 응집도는 하나의 모듈만 가지고도 측정이 가능한 설계 품질이다.
    - 하나의 변경을 반영하기 위해 여러 모듈을 변경해야 한다는 것은 하나의 책임이 여러 곳에 분산돼 있음을 의미하며 응집도가 낮다.
  
  #### 결합도
  
    >어떤 모듈이 다른 모듈에 대해 너무 자세한 부분까지 알고 있다면 두 모듈은 높은 결합도를 가진다.
  
    - '너무 자세한'이라는 말이 조금 모호하다.
      - TODO 결합도의 정의를 찾아보자.
    - 결합도는 하나의 모듈만 가지고는 측정이 불가능하고 협력망 차원에서 측정이 가능한 설계 품질이다.
  
    >결합도는 하나의 모듈을 수정할 때 얼마나 많은 모듈을 함께 수정해야 하는지를 나타낸다.
  
    - 이건 응집도와 표면적으로는 겹치는 설명이다. 다만 **응집도는 변경 자체의 본질적인 수용을 위해 동시에 함께 수정해야 하는 모듈의 양에 대한 얘기고, 결합도는 변경의 본질적인 반영 이후에 파생적으로 수정돼야 하는 모듈의 양에 대한 얘기다.**
  
    - 이 설명은 일반화하기에는 약점이 있다. A가 내부 구현을 드러내는 식으로 만들어져 있다고 하자. 그런데 비즈니스 컨텍스트에 따라 이 A에 의존하는 모듈이 하나일 수도 있고 여럿일 수도 있다. 여럿이 의존할 때는 결합도가 높지만, 하나만 의존할 때는 파생적으로 변경돼야 하는 것이 하나 밖에 없으므로 결합도가 낮다고 할 수 있을까?
  
  ### p113
  
  #### getter, setter 사용을 캡슐화라고 볼 수 없는 이유
  
    >안타깝게도 접근자와 수정자 메서드는 객체 내부의 상태에 대한 어떤 정보도 캡슐화하지 못한다. getFee 메서드와 setFee 메서드는 Movie 내부에 Money 타입의 fee라는 이름의 인스턴스 변수가 존재한다는 사실을 퍼블릭 인터페이스에 노골적으로 드러낸다.
  
  ### p115
  
  #### 데이터 중심 설계의 위험성
  
    >여러 데이터 객체들을 사용하는 제어 로직이 특정 객체 안에 집중되기 때문에 하나의 제어 객체가 다수의 데이터 객체에 강하게 결합된다는 것이다. 이 결합도로 인해 어떤 데이터 객체를 변경하더라도 제어 객체를 함께 변경할 수 밖에 없다.
  
    - 데이터 중심 설계는 판별 로직을 캡슐화하지 않으면서 자율성을 해치고, 판별에 필요한 데이터를 노출함으로써 판별 로직이 여러 곳에 중복되어 분산될 수 있고, 여러 객체의 판별 로직을 한 몸에 가지고 있는 제어 객체를 만들어낼 가능성이 높다.
  
  ### p126 - p127
  
  #### 자율성을 높여도 여전히 부족한 캡슐화 문제
  
    - **판별 로직을 개별 객체 내로 캡슐화시켜서 자율성을 높인다고 해도 여전히 캡슐화는 부족할 수 있다.**
      - 판별 로직을 객체 내로 캡슐화해도 **외부에 노출하는 인터페이스의 시그니처를 통해 여전히 세부 내용이 새어나갈 수 있다.**
      - 또한 **노출된 인터페이스 자체의 추상화가 부족하면 세부 내용이 새어나갈 수 있다.**
  
  ### p128
  
  #### 캡슐화의 진정한 의미
  
    >(p126 - p127) 예제는 캡슐화가 단순히 객체 내부의 데이터를 외부로부터 감추는 것 이상의 의미를 가진다는 것을 잘 보여준다.
    >
    >캡슐화란 (데이터뿐 아니라) 변하는 어떤 것이든 감추는 것이다.
  
    - 인터페이스를 통한 간접적인 정보 누출도 발생하지 않게 해야 진정한 캡슐화라고 할 수 있으며, 이는 변하는 어떤 것이든 감춰야만 가능하다.
  
  ### p131
  
  #### 데이터 중심 설계의 문제점
  
    >데이터를 처리하는 작업과 데이터를 같은 객체 안에 두더라도 데이터에 초점이 맞춰져 있다면 만족스러운 캡슐화를 얻기 어렵다. 데이터를 먼저 결정하고 데이터를 처리하는 데 필요한 오퍼레이션을 나중에 결정하는 방식은 데이터에 관한 지식이 객체의 인터페이스에 고스란이 드러나게 된다.
  
    - 지금까지는 판별에 필요한 데이터와 판별 로직을 같은 객체 안에 두는 것으로 캡슐화가 된다고 생각해왔고, 인터페이스를 통해 정보가 새어나갈 수 있다는 생각은 미처 못 했었는데 큰 깨달음을 얻었다.
  
  
  
  
  
  ## 05. 책임 할당하기
  
  - 책임 중심 설계
    - 도메인 전문가와 초기 도메인 개념, 도메인 모델을 도출하고,
    - 도메인 모델을 토대로 협력 구조와 메시지를 도출,
    - 메시지에 따라 객체를 선택. 이 때 도메인 개념이 객체 후보
  - 설계와 구현은 서로 피드백
    - 도메인 모델에서 초기 설계가 나오고,
    - 초기 설계는 구현을 통해 검증되며,
    - 구현 결과가 도메인 모델의 개선을 유도할 수 있다.
  - 추상화가 잘 된 public 메서드는 상위 수준의 명세를 읽는 느낌
  - 이름이 잘 지어진 작은 메서드는 주석을 읽는 느낌
  - 작은 메서드의 장점
    - 코드 자체가 주석 역할
    - 하나의 책임만 가지므로 재사용과 이동(리팩터링)이 쉽다ㅏ
  
  ### p135
  
  #### 협력에 적합한 책임이란
  
    >협력을 시작하는 주체는 메시지 전송자이기 때문에 협력에 적합한 책임이란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다.
    >
    >객체를 가지고 있기 때문에 메시지를 보내는 것이 아니다. 메시지를 전송하기 때문에 객체를 갖게 된 것이다.[Metz12]
  
    - 메시지 전송자도 객체이므로 메시지보다 객체가 먼저 결정돼 있어야 하는 거 아닌가 하는 생각도 든다. 최초의 메시지 전송자는 사실 사용자로 이미 정해져 있는 셈이다.
  
  ### p137
  
  #### GRASP
    - By Craig Larman
    - General Responsibility Assignment Software Pattern
  
  #### 도메인 개념, 객체의 후보
  
    >어떤 책임을 할당할 때 가장 먼저 고민해야 하는 유력한 후보는 바로 도메인 개념이다.
  
    - 그럼 도메인 개념은 어디서 도출되는가? 전통적인 설계에서 요구사항 기술서에 명사로 표현돼 있는 것들이 도메인 개념에 해당한다.
    - 하지만 여기서 주의할 점이 있다. **도메인 개념이 도출되면 그 개념과 관련 지을 수 있는 속성 후보를 도출하는 게 더 쉽고 자연스럽기 때문에 데이터 중심 설계로 흐를 위험이 있다.**
    - 도메인 개념이 도출되면 속성 후보도 함께 떠오르기 마련이지만 잠시 접어두고 협력과 메세지 설계를 시작해야 한다. **이 시점에서 떠오르는 속성 후보는 메시지를 처리할 정보 전문가를 선택하는 기준으로만 사용한다.**
  
  ### p143
  
  - 잘 이해가 안 되는
  
    >그림 5.1의 도메인 개념을 다시 살펴보자. 도메인 상으로 Movie는 DiscountCondition의 목록을 속성으로 포함하고 있다. Movie와 DiscountCondition은 이미 결합돼 있기 때문에 Movie를 DiscountCondition과 협력하게 하면 설계 전체적으로 결합도를 추가하지 않고도 협력을 완성할 수 있다.
  
    - 애초에 왜 Movie가 DiscountCondition의 목록을 속성으로 포함하도록 결정됐는가? 라는 의문이 떠오르는데, 이는 도메인 전문가와 함께 도출한 개념이므로 일단 맞다고 가정하고 가는 걸로 이해하고 넘어가자.
  
  #### Low Coupling 패턴
  
    - (도메인 전문가와 함께 도출한 도메인 개념을 토대로) 결합도를 증가시키지 않는 쪽으로 협력 관계를 설계하자.
  
  ### p144
  
  #### High Cohesion 패턴
  
    - (도메인 전문가와 함께 도출한 도메인 개념을 토대로) 응집도를 높이는 쪽으로 협력 관계를 설계하자.
  
  ### p145
  
  #### Creator 패턴
  
    - 어떤 객체 A의 생성 책임은 다음 조건을 최대한 만족하는 객체에게 할당한다.
      - A를 참조하거나 포함하는 객체
      - A를 기록하는 객체
      - A를 긴밀하게 사용하는 객체
      - A를 초기화하는 데 필요한 데이터를 가지고 있는 객체
    - 위와 같은 조건을 만족하는 객체는 도메인 개념 상으로도 이미 A와 결합돼 있을 가능성이 높으므로, 이 객체가 A를 생성하게 하면 결합도를 추가로 높이지 않는다는 관점에서는 Low Coupling 패턴의 한 형태라고 볼 수도 있겠다.
  
  #### 스케치와 설계
  
    >현재까지의 책임 분배는 설계를 시작하기 위한 대략적인 스케치에 불과하다. **실제 설계는 코드를 작성하는 동안 이뤄진다. 그리고 협력과 책임이 제대로 동작하는지 확인할 수 있는 유일한 방법은 코드를 작성하고 실행해 보는 것 뿐이다.**
  
    - 설계는 구현으로 검증할 수 있으므로, 설계와 구현이 명확하게 분리될 수 없는 이유이며, 설계와 구현을 Iterative하게 진행해야 하는 근거
  
  ### p146
  
  #### 인스턴스 변수 결정
  
    - 책임을 완수하는 데 필요한 정보
      - '영화 예매'라는 책임을 가진 '상영 영화' 객체가 책임을 완수하는데 필요한 영화, 상영관, 회차 등
      - '상영 영화' 객체를 설명하는 정보 라고 볼 수도 있지만, 책임 중심으로 바라보자.
    - 책임의 일부를 위임받을 객체
      - 관람료 계산을 위함받을 영화 객체
  
  ### p147
  
  #### 메서드 시그니처 결정
  
    - 메시지를 기반으로 책임의 일부를 위임받을 객체에 대한 충분한 사전 정보 없는 상태에서 위임받는 객체의 메서드 시그니처 결정
  
  ### p152
  
  #### 변경의 이유가 여러가지인 저응집도 객체 후보
  
    - 인스턴스 변수가 한 꺼번에 초기화되지 않고 초기화되는 시점이 다른 객체
    - 모든 메서드가 모든 인스턴스 변수를 고루 사용하지 않고 일부 메서드는 일부 인스턴스 변수만을 사용하는 객체
    - 순번 조건과 기간 조건을 한 몸에 가지고 있는 DiscountCondition
  
  ### p155
  
  #### 단순한 클래스 분리는 결합도 증가로 이어질 수 있다.
  
    - 순번 조건과 기간 조건으로 나눠서 각각 SequenceCondition과 PeriodCondition 객체로 나누면 응집도는 높아졌지만,
    - Movie는 기존에는 DiscountCondition 하나에만 의존하다가 이제는 SequenceCondition, PeriodCondition 두 개에 의존하게 되므로 결합도가 증가했다.
    - 또한 새로운 할인 조건이 추가된다면 Movie와 할인 조건 간의 결합도는 계속 증가한다.
  
  ### p158
  
  #### Polymorphism 패턴
  
    - 객체의 구체 타입을 검사하는 조건문 대신 동일한 메시지에도 구체 타입에 따라 다르게 동작하는 다형성을 이용하자.
    - 할인 조건 만족 여부를 SequenceCondition과 PeriodCondition의 타입을 검사해서 분기하는 대신에, 할인 조건 만족 여부라는 메시지를 처리하는 역할(하나의 클래스나 interface)을 정의하고 이 역할을 각자의 방법으로 수행(상속/구현)할 수 있는 다형성을 이용하면, 개별 객체가 아니라 하나의 역할에만 의존하게 되므로 결합도 증가를 막을 수 있다.
  
  ### p159
  
  #### Protected Variations 패턴
  
    - 변하는 부분을 캡슐화해서 변하지 않아도 되는 부분을 보호하자.
    - '회차 할인 조건', '기간 할인 조건'은 변하는 부분이며, 이를 '할인 조건 만족 여부 확인' 메시지를 받는 하나의 추상 타입으로 묶어 캡슐화하면 결합도 증가를 막고 변하지 않아도 되는 부분의 변경을 유발하지 않게 된다.
  
  #### 비슷해보이는 위 두 패턴의 적용 기준
  
    >하나의 클래스가 여러 타입의 행동을 구현하고 있는 것처럼 보인다면 클래스를 분해하고 Polymorphism 패턴 적용
    >
    >예측 가능한 변경으로 인해 여러 클래스들이 불안정해진다면 Protected Variations 패턴 적용
  
    - 결국 추상화를 통해 캡슐화한다는 점에서는 두 패턴이 같다.
  
  ### p160
  
  #### 추상 클래스와 interface
  
    - 하나의 역할에 해당한다는 점에서는 같다.
    - 하위 타입에 공유해줄 구현이 있다면 추상 클래스, 공유해줄 구현이 없다면 interface
  
  ### p163
  
  #### 도메인 구조와 코드 구조 - 1
  
    >도메인 모델은 단순히 설계에 필요한 용어를 제공하는 것을 넘어 코드의 구조에도 영향을 미친다.
  
    - 도메인 전문가와 함께 도출한 도메인 개념으로 이루어진 도메인 모델은 적절한 책임 할당의 바탕이 되고, 변경 가능성이 있는 곳을 예측할 수 있게 해주므로 추상화와 캡슐화를 더 쉽게 적용할 수 있게 도와준다.
  
  ### p164
  
  #### 상속과 합성
  
    - **런타임 교체가능성이 있다면 합성을 사용해야 한다.**
      - 영화를 상속받은 '금액 할인 영화'와 '비율 할인 영화'가 있을 때 '금액 할인 영화' 객체를 '비율 할인 영화'로 교체해야 한다면?
        - '비율 할인 영화'처럼 동작하게 하려면 비율 할인 영화 인스턴스를 새로 생성하고 필요한 정보(영화, 상영시간, 기본관람료 등)를 새로 생성한 인스턴스에 전달해줘야 한다.
        - 하지만 합성을 사용한다면 '금액 할인'이든 비율 할인'이든 뭐든 영화와 분리된 '할인 정책'으로 추상화해서 런타임 교체가 가능해진다.
      - **'항상 상속보다 합성'보다는 서브 타입과 공유해야할 구현이 있는가, 런타임 교체가능성이 있는가를 기준으로 적절한 것을 선택하는 것이 좋다.**
  
  ### p165
  
  #### 도메인 구조와 코드 구조 - 2
  
    - 처음에 도메인 전문가와 도출한 모델에는 '비율 할인 영화', '금액 할인 영화'만 존재했고 '할인 정책'은 별도로 존재하지 않았던 개념이다.
    - 이처럼 처음에는 도메인 구조에서 코드 구조가 도출되지만, 코드 구조에서 새로운 도메인 개념이 도출되어 도메인 구조를 개선할 수도 있다.
  
  ### p168
  
  #### 어려운 책임 주도 설계의 대안
    - 동작하는 코드 작성 완료 후 리팩터링
  
  #### 몬스터 메서드와 작은 메서드
    - 몬스터 메서드의 단점
      - 높은 코드 이해 비용
      - 로직의 일부 재사용 불가
      - 재사용하는 유일한 방법은 복붙이므로 코드 중복 유발
    - 작은 메서드의 장점
      - 쉬운 재사용(override 포함)
      - 코드 자체가 주석 역할
    - 작은 메서드의 장점은 이름을 잘 지었을 때 극대화된다.
  
  ### p171
  
  #### 몬스터 메서드 분리 후 효과  
    - public 메서드는 상위 수준의 명세를 읽는 느낌
    - 이름을 잘 지은 작은 메서드들은 주석을 읽는 느낌
    - 작은 메서드는 변경 이유가 하나
    - 작은 메서드는 하나의 책임만을 가지므로 이동(리팩터링)이 쉬워진다
    + 몬스터 메서드에서는 로컬 변수로 처리되던 것이 작은 메서드로 분리되면서 인스턴스 변수가 될 수 있는데,
      - 이런 변수가 객체의 책임 완수에 필요한 적절한 인스턴스 변수라면 응집도를 높이는 결과를 가져오지만, 
      - 책임 완수에 필요하지 않다면 다른 객체로 분리해야할 후보가 되기도 한다.
    - 다른 객체의 접근자 메서드를 사용하는 작은 메서드는 다른 객체로 옮겨야 할 유력한 후보
  
  
  
  
  
  ## 06. 메시지와 인터페이스
  
  - 디미터의 법칙, 묻지 말고 시켜라, 의도를 드러내는 인터페이스, 명령-쿼리 분리 인터페이스를 활용해서 퍼블릭 인터페이스를 설계하면 객체의 자율성을 높일 수 있다.
  - 이 네 가지도 책임을 고려하지 않고 무분별하게 적용하면 부작용이 나타나므로, 적절한 책임 유지가 이 네 가지보다 더 근본적인 원리다.
  
  ### p171 - p181
  
  #### 메시지
    - 객체의 유일한 의사소통 수단
    - operation + argument
  
  #### 메시지 전송
    - 다른 객체에게 협력을 요청하는 것
    - 수신자 + 메시지
  
  #### 메서드
    - 메시지를 수신한 객체가 책임을 완수하기 위해 자율적으로 실행하는 함수 또는 프로시저
    - 메시지는 쌍방의 의사소통 수단
    - 메서드는 일방의 문제해결 수단
  
  #### 퍼블릭 인터페이스
    - 객체가 의사소통을 위해 외부에 공개하는 메시지의 집합
  
  #### 오퍼레이션
    - 퍼블릭 인터페이스에 포함된 메시지
  
  #### 총 정리
    
    >프로그래밍 언어의 관점에서 객체가 다른 객체에게 메시지를 전송하면 런타임 시스템은 메시지 전송을 오퍼레이션 호출로 해석하고 메시지를 수신한 객체의 실제 타입을 기반으로 적절한 메서드를 찾아 실행한다.
  
    - 메시지 전송 == 수신 객체의 퍼블릭 인터페이스의 오퍼레이션 호출
    - 수신 객체는 오퍼레이션이 호출되면 적합한 메서드를 자율적으로 선택해서 실행
  
  ### p183
  
  #### 디미터의 법칙(Law of Demeter)
    - 디미터는 프로젝트 이름
  
    >클래스 내부의 메서드는 아래 조건을 만족하는 인스턴스에만 메시지를 전송하도록 구현
    >- this
    >- this의 속성
    >- this의 속성인 컬렉션의 요소
    >- 메서드로 전달된 파라미터
    >- 메서드 내의 지역 객체
  
    - `aaa.getBbb().getCcc().getDdd()..`와 같이 캡슐화를 저해하는 방식의 사용을 제한
    - 대신에 `aaa.doB() -> bbb.doC() -> ccc.doD()` 와 같은 자율성 있는 위임을 선호
  
  ### p187
  
  #### Tell, don't ask
    - 데이터를 요구하지 말고 작업을 요청하라 와 같은 말인 듯
  
  ### p190
  
  #### 의도를 드러내는 인터페이스(Intention Revealing Interface)
    - '어떻게'가 아니라 '무엇'을 나타내도록 메서드 이름을 결정하자
    - 어떤 구현이 있다면 동작은 같되 방식이 완전히 다른 구현을 하나 떠올리고, 그 둘에 같은 메서드 이름을 붙인다고 상상보자. 그 둘 모두에 어색하지 않은 이름이 있다면 의도를 나타내는 좋은 이름일 것이다.
  
  ### p192
  
  #### getter의 폐해
  
    >`audience.getBag().minusAmount(ticket.getFee());`  
    >
    >퍼블릭 인터페이스에 getBag을 포함시키는 순간 객체의 구현이 퍼블릭 인터페이스를 통해 외부로 새어나가 버리고 만다.
  
    - getter가 이름만으로 보면 변경을 일으키지 않을 것 같지만, 실은 getter를 통해 변경 권한을 외부에 주는 것과 마찬가지다.
  
  ### p197
  
  #### 인터페이스 설계 원칙 효과 간단 요약
  
    - 디미터 법칙은 캡슐화를 위반하는 메시지가 인터페이스에 포함되는 것 억제
    - 묻지 말고 시켜라 원칙은 디미터 법칙이 자연스럽게 지켜지게 만들며 자율성을 높이는 효과
    - 의도를 드러내는 인터페이스 원칙은 의사소통 비용을 낮추고 구현과 분리되게 만드는 효과
  
  ### p200
  
  #### 디미터 법칙이 항상 좋은 결과만을 낫지는 않는다
  
    - 묻지 않고 시키기 위해 대상 **객체 내의 위임 메서드로 무분별하게 이동해서 퍼블릭 인터페이스에 포함시키면, 결과적으로 하나의 객체가 여러 책임을 가지면서 응집도가 낮아질 수도 있다.**
      - 위임 메서드로 이동 시 객체의 책임과의 부합도에 대해 한 번 더 고민 필요
  
  ### p202
  
  #### 프로시저와 함수
  
    - 프로시저는 내부 상태를 변경(부수효과)할 수 있으며 값을 반환할 수 없다.
      - 내부 상태가 변경되므로 호출될 떄마다 다른 값이 반환될 수도 있다. 따라서 값을 반환하지 않는 것이 불필요한 혼동을 막는다.
      - 참조 투명성 없음
    - 함수는 내부 상태를 변경할 수 없으며 값을 반환한다.
      - 아무리 호출되도 내부 상태 변경이 없으므로 같은 값을 반환하므로 값을 반환해도 괜찮다.
      - 참조 투명성 있음
  
  ### p212
  
  #### 참조 투명성
  
    >표현식 e가 있을 때 모든 e를 e의 값으로 교체하더라도 결과가 달라지지 않는 특징
  
    - '모든 e'라 함은 표현식 e가 여러 군데 존재함, 즉 여러 번 호출됨을 의미
    - 여러 번 호출되더라도 항상 같은 값을 반환하면 모든 e를 e의 값으로 교체해도 전체 결과가 달라지지 않음
  
  
  
  
  
  ## 07. 객체 분해
  
  - 추상 데이터 타입에는 상속/다형성 개념이 없으며, 오퍼레이션 기준으로 타입을 추상화(하나의 타입으로 여러 타입을 통함하고 숨김)한다.
  - 클래스는 상속/다형성 개념이 있어서, 타입 기준으로 오퍼레이션을 추상화(하나의 오퍼레이션이 타입에 따라 여러 구현을 가짐)한다.
  - 타입 추가 압력이 클 때는 클래스가, 오퍼레이션 추가 압력이 클 때는 추상 데이터 타입이 더 나은 선택
  
  ### p218
  
  #### 프로시저 추상화(Procedure Abstaction)과 데이터 추상화(Data Abstraction)
  
    >프로시저 추상화는 소프트웨어가 무엇을 하는지 추상화한다.  
    >데이터 추상화는 소프트웨어가 무엇을 알아야 하는지 추상화한다.
  
    - 프로시저 추상화는 소프트웨어가 어떻게 하는지 추상화한다. 가 더 적절하지 않나 싶다.
  
  ### p220
  
  #### 기능 분해 방식
  
    >기능 분해의 초점은 하나의 문장으로 표현된 기능을 여러 개의 더 작은 기능으로 분해하는 것이다.
  
    - 기능 분해는 상위 단계에서 추상적으로 기술된 기능을 하위 단계에서 구체화하는 탑다운/하향식 접근법이다.
  
  ### p227 ~ p234
  
  #### 기능 분해 방식의 단점
  
    - What(데이터)이 아니라 How와 Order(절차)에 집중하게 만들어서,
      - 정보 감춤이 잘 지켜지지 않으므로,
      - 결합도가 높고 재사용성이 낮은 코드가 만들어진다.
  
  #### 기능 분해가 적합한 경우
  
    - 협력 관계가 어느 정도 설계된 이후 정해진 책임을 구현하는 데 적합
      - 즉, 모듈 내부의 구현 문제를 해결하는 데 적합
  
  ### p235
  
  #### 정보 감춤과 모듈
  
    >모듈은 서프 프로그램이라기보다 책임의 할당이다.
    >
    >David Parnas
  
    - 모듈은 단순히 기능을 분리해서 묶어놓은 서브 프로그램이 아니라, 책임 할당에 따라서 불필요한 정보를 외부로부터 감추는 데 사용되는 분리 단위다.
      - 자주 변경되는 부분(데이터와 구현)을 모듈 내부로 감추고, 덜 변경되는 부분(규약)을 외부에 노출한다.
  
  ### p236
  
  #### 데이터 캡슐화와 정보 감춤
  
    >데이터와 메서드를 하나의 단위로 통합하고 퍼블릭 메서드를 통해서만 접근하도록 허용하는 방법을 데이터 캡슐화(data encapsulation)라고 한다. 정보 은닉과 데이터 캡슐화는 동일한 개념이 아니다. 변경과 관련된 비밀을 감춘다는 측면에서 정보 은닉과 캡슐화는 동일 개념을 가리키는 두 가지 다른 용어지만 데이터 캡슐화는 비밀의 한 종류인 데이터를 감추는 캡슐화의 한 종류일 뿐이다.
  
    - 이제서야 데이터 캡슐화와 정보 감춤을 구분해주다니..
    - 그런데 마지막 '데이터 캡슐화는 비밀의 한 종류인 데이터를 감추는 캡슐화의 한 종류일 뿐이다.'라는 설명을 보면 여전히 캡슐화를 정보 감춤과 같게 또는 정보 감춤에 포함되는 개념으로 보는 것 같다.
    - 이 설명보다는 p20 정리 부분에 나온대로, **캡슐화는 자율성 확보 장치, 정보 감춤은 자율성 보호 장치**라고 이해하는 것이 나은 듯
  
  ### p239
  
  #### 모듈의 의의
  
    >모듈이 정보 은닉이라는 개념을 통해 데이터라는 존재를 설계의 중심 요소로 부각시켰다
  
  #### 모듈과 하향식 기능 분해와의 차이
  
    - 하향식 기능분해는 메인 함수를 정의하고 필요에 따라 더 세부적인 함수로 분해
    - **모듈은 감춰야 할 데이터를 먼저 결정하고 이 데이터를 조작할 함수를 나중에 결정**
  
  #### 모듈의 단점
  
    - 인스턴스 개념이 없다.
    - 즉 분리 단위나 범위일 뿐 실제 문제를 해결하는 데 필요한 실체화가 없다. -> 실체화 가능한 추상 데이터 타입(Abstract Data Type)이 필요
  
  ### p240
  
  #### 추상 데이터 타입(Abstract Data Type)
  
    >기능 분해의 시대에는 프로시저 추상화가 주로 사용됐으며, 이 시기의 언어에는 새로운 타입을 추가하는 것이 불가능하거나 제한적이었다.
    
  #### Barbara Liskov가 1974년에 데이터 추상화 개념 제안
  
    >추상 데이터 객체를 사용할 때 프로그래머는 오직 객체가 외부에 제공하는 행위에만 관심을 가지며, 행위가 구현되는 세부적인 사항에 대해서는 무시한다. 객체가 저장소 내에서 어떻게 표현되는지와 같은 구현 정보는 오직 오퍼레이션을 어떻게 구현할 것인지에 집중할 때만 필요하다. 객체의 사용자는 이 정보를 알거나 제공받을 필요가 없다.
  
  ### p245 ~ 247
  
  #### 클래스와 추상 데이터 타입의 차이
  
    - 클래스는 상속과 다형성을 지원한다.
    - 상속과 다형성을 지원하면 객체지향(Object-Oriented), 상속/다형성 없는 추상 데이터 기반 프로그래밍은 객체기반(Object-Based) 프로그래밍
    - **객체지향 클래스는 타입을 기준으로 절차를 추상화하고, 객체기반 추상 데이터 타입은 오퍼레이션을 기준으로 타입을 추상화한다.**
      - 직원 클래스는 상속을 활용해서 정규직원/임시직원으로 타입을 구분하고 각 타입 안에 각자에 맞는 오퍼레이션을 스스로 갖고 있다.
      - 직원 추상 데이터 타입은 오퍼레이션을 기준으로 해당 오퍼레이션을 갖는 타입을 하나로 통합한다.
  
  - 물리적으로 하나의 타입을 사용하면서 그 안에 논리적으로 타입을 구분하는 변수가 포함돼 있다면, 클래스를 사용한다고 하더라도 실질적으로는 추상 데이터 타입을 사용한다고 볼 수 있다.
  
    - 예를 들어 개발자를 하나의 클래스로 표현하면서 그 안에 `lang` 같은 변수를 두고 Java, Python, C# 같은 값을 두고 오퍼레이션 내에서 `lang` 값에 따라 동작을 구분한다면 이는 추상 데이터 타입에 해당한다.
  
  ### p251
  
  #### 언제 어느 걸 쓸까
  
    - **타입 추가 변경 압력이 더 클 경우 객체지향 클래스**
      - 타입 추가 시 추상 데이터 타입의 경우 모든 클라이언트에 새 타입에 대한 코드가 추가돼야 하므로 변경 영향 큼
    - **오퍼레이션 추가 변경 압력이 더 클 경우 객체기반 추상 데이터 타입**
      - 오퍼레이션 추가 시 클래스의 경우 상속 계층에 속하는 모든 클래스에 오퍼레이션 추가돼야 하므로 변경 영향 큼
  
  
  
  
  
  ## 08. 의존성 관리하기
  
  - 의존 관계는 협력을 근간으로 하는 객체지향에서는 필연적으로 발생하며, 기피 대상이 아니라 관리 대상
  - 가능한한 추상도가 높은 대상에 의존하게 해야,
    - 결합도가 덜 높아지고
    - 추가되는 요구사항에 로직 추가가 아니라 컨텍스트 확장으로 대응할 수 있게 된다.
  - 아무데서나 new로 직접 생성하지 말고,
    - **구체성을 결정하는 역할을 가진 쪽에서 직접 구체클래스를 생성해서 추상화에 의존하는 쪽에 전달(주입)하고,**
    - **의존하는 쪽에서는 그냥 추상화에만 의존하게 하는 것이 결합도 상승을 낮추는 방법이다.**
  
  
  ### p257
  
  #### 의존성이란?
  
    >의존성이란 의존하고 있는 대상의 변경에 영향을 받을 수 있는 가능성이다.
  
    - 조금 지나친 표현이 아닐까? 의존의 결과 의존하는 대상의 변경에 영향을 받게 되지만, 의존하는 대상이 캡슐화가 매우 잘 돼 있어서 의존 대상의 변경에 영향을 안 받는다고 하더라도 의존이라는 관계 자체는 여전히 존재한다.
    - 일단 dependency는 의존성보다는 의존 관계로 옮기는 게 대부분 더 적합하다고 생각.
  
  ### p263
  
  #### 의존성 설정 방식
  
    >- 생성자 방식(생성자 주입)
    >    - 의존하는 객체가 생성될 때 의존성을 확정
    >    - 객체 상태가 생성 직후부터 안정적
    >- setter 방식(setter 주입)
    >    - 객체 생성 이후에 의존성을 확정할 수 있으므로 유연
    >    - 생성 직후 set 되기 전까지 객체 상태 불안정
    >- parameter 방식(메서드 주입)
    >    - 특정 operation을 수행할 때만 의존할 때 적합
    >    - 지속적 협력 관계가 아니라 일시적/임시적 협력 관계에 사용
    >- 생성자 + setter 방식도 가능
  
  ### p270
  
  #### 의존성 분류
  
    >- 명시적(explicit) 의존성
    >    - 퍼블릭 인터페이스에 노출되는 의존성
    >      - 예) 생성자의 파라미터
    >- 숨겨진(hidden) 의존성
    >    - 퍼블릭 인터페이스에 노출되지 않는 의존성
    >      - 예) 외부에 노출않고 직접 의존대상을 (new로) 직접 생성하는 경우
  
  - **명시적 의존성이라야만 퍼블릭 인터페이스를 통해 컴파일타임 의존성을 런타임 의존성으로 교체할 수 있다.**
  
  ### p271
  
  #### new는 해롭다
    >생성할 구체클래스를 알아야 한다. -> 결합도 증가  
    >new로 호출할 생성자의 파라미터 정보를 알아야 한다. -> 결합도 증가
  
  #### 즉, **new는 결합도를 높이므로** ~~새~~**해롭다.**
    - 물론 써야할 때는 써야지. 다만 결합도를 불필요하게 높이는 건 아닌지 한 번 뒤돌아봐야.
    - 잘 변하지 않는 대상(예: SDK)을 직접 생성하는 것은 결합도가 높아지지만 그에 따른 실질적 폐해는 적다.
  
  - **구체성을 결정하는 역할을 가진 쪽에서 직접 구체클래스를 생성해서 추상화에 의존하는 쪽에 전달(주입)하고,**
  - **의존하는 쪽에서는 그냥 추상화에만 의존하게 하는 것이 결합도 상승을 낮추는 방법**
  
  
  ### p279
  
  #### 컨텍스트 확장
  
    >- 요금 할인, 비율 할인이 아니라 할인이 없는 할인 정책, 요금+비율 복합 할인 정책은 어떻게 할 것인가?
    >- 할인이 없는 할인 정책은 `discountPolicy == null`로 분기처리하면, 이는 사실 상 예외 케이스가 추가되는 것
    >- 예외 케이스를 추가하는 것은 연결된 다른 코드에도 영향을 미친다
    >- 예외 케이스를 추가하지 말고 추상 클래스인 DiscountPolicy를 상속받은 NoneDiscountPolicy를 만들어서 사용하면 예외 케이스 추가 없이, 기존 협력 방식 변경 없이도 Movie에 할인이 없는 할인 정책도 적용 가능
    >- 요금+비율 복합 할인 정책도 예외 케이스로 하지 말고 OverlappedDiscountPolicy를 만들어서 복합 할인 정책도 적용 가능
  
  #### 컨텍스트 확장이란 대략..
    - **추가되는 요구 사항에 대해 기존 코드에 개별 로직을 추가해서 대응하는 것이 아니라,**
    - **의존 대상이 되는 추상체를 확장하는 구상체를 추가해서 기존 코드 수정 없이도 새로 추가되는 요구사항을 충족할 수 있는 것**
  
  
  
  
  
  ## 09. 유연한 설계
  
  - **유연한 설계란 변하는 요구사항에 대해 코드의 변경은 최소화하면서도 기능은 최대한 확장할 수 있는 설계**
  - OCP, 생성-사용 분리, DIP, DI 등의 설계 원칙을 준수하면 유연한 설계를 만드는 데 도움이 된다.
  - **유연한 설계는 컴파일타임의 정적 클래스 구조와 런타임의 동적 객체 구조 사이의 차이에 바탕을 둔다.**
  - 따라서 **유연한 설계는 정적으로 이해하기 복잡한 설계로 이어지는 게 필연적이므로 절대적 선이 아니며, 실제로 유연성이 필요한 곳에 선별적으로 적용하는 것이 좋다.**
  - 동작하는 시스템에는 도메인 모델 뿐만아니라 네트워킹, DB 등 기계적/기술적 개념도 혼재
  - 따라서 **도메인 모델만으로는 동작하는 시스템 전부에 대한 최적의 책임 할당은 사실 상 불가능**하며, **도메인 개념을 넘어서는 부분은 Pure Fabrication을 만들어서 책임을 분배하는 것이 좋다.**
  
  ### p282
  
  #### 개방-폐쇄 원칙(Open-Closed Principle, OCP)
  
    >소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다.  
    >by Robert C. Martin
  
    - 아주 쉽고 짧게 써보면, **동작을 확장할 수 있도록 열려 있어야 하고, 변경이 외부에 영향을 미치지 않도록 닫혀 있어야 한다.**
  
  ### p284
  
  #### OCP와 의존성
  
    >의존성 관점에서 OCP를 따르는 설계란, 컴파일타임 의존성을 유지하면서 런타임 의존성의 가능성을 확장하고 수정할 수 있는 구조
  
  #### OCP와 추상화
  
    - 추상화는 기본적으로 불필요한 것을 생략하는 것
    - **OCP를 따르는 추상화는 변하지 않는 부분만 남겨두고, 변하는 부분을 생략하는 것**
      - 변하는 부분을 생략해야 나중에 변하는 부분을 담당하는 구상체를 추가하면서 확장 가능
  
  ### p287
  
  #### 생성 사용 분리(Separation use from creation)
  
  >동일한 클래스 안에서 객체 생성과 사용이라는 두 가지 이질적인 목적을 가진 코드가 공존하는 것이 문제
  
  - 객체를 사용하는 쪽에서 생성까지 한다면 결합도가 높아져서 OCP를 준수하기 어려워진다.
  - 사용하는 쪽에서는 추상화 된 타입으로 전달받아 사용하면, 그 추상화 된 타입이 사용될 수 있는 여러 컨텍스트에서 OCP를 준수할 수 있다.
  
  ### p289
  
  #### Factory
  
  - **런타임에 어떤 구상체를 사용할지는 보통 클라이언트에서 결정하므로, 구상체의 생성도 클라이언트에서 담당하는 것이 적합**
  - 생성 자체도 클라이언트에서 떼어내고 싶다면, 즉 생성에 책임만 가지는 클래스를 Factory라고 한다.
  
  ### p291
  
  #### Representational Decomposition
  
  >표현적 분해는 도메인에 존재하는 사물 또는 개념을 표현하는 객체들을 이용해 시스템을 분해하는 것  
  >by Craig Larman
  
  >도메인 모델은 설계를 위한 중요한 출발점이지만 단지 출발점이라는 사실을 명심해야 한다.
  
  - **도메인 모델만으로는 설계를 완성할 수 없다**는 의미
  
  #### Behavioral Decomposition
  
  - 동작하는 시스템에는 네트워크 통신, DB 접근처럼 도메인 모델로는 표현되지 않는 기계적/기술적 요소들이 있다.
  - 이런 관점에서 시스템을 분해하는 것을 행위적 분해라고 한다.
  
  #### Pure Fabrication
  
  >도메인과 무관하게 책임을 할당하기 위해 창조되는 객체를 Pure Fabrication(순수 가공물)이라고 부른다.  
  >by Craig Larman
  
  - **도메인 객체만으로 책임을 나누면, 기계적/기술적 요소에 대한 책임도 도메인 객체에 할당될 수 밖에 없으므로 응집도 저하, 결합도 상승 등의 문제 발생**
  
  >어떤 행동을 추가하려고 하는데 이 행동을 책임질 마땅한 도메인 개념이 존재하지 않는다면 Pure Fabrication을 추가하고 여기에 책임을 할당하라
  
  ### p292
  
  #### Pure Fabrication 패턴과 Information Expert 패턴
  
  >Information Expert 패턴에 따라 책임을 할당한 결과가 바람직하지 않을 경우 대안으로 Pure Fabrication을 사용
  
  - Information Expert 패턴에서 Information이란 도메인 모델 관점에서의 정보를 의미한다.
  - 따라서 **도메인 개념에만 의존해서 책임을 할당한 결과가 낮은 응집도, 높은 결합도로 귀결된다면 Pure Fabrication 패턴을 떠올리자.**
  
  ### p293
  
  #### 의존성 주입
  
  >의존성을 객체의 퍼블릭 인터페이스에 명시적으로 드러내서 필요한 런타임 의존성을 외부에서 전달할 수 있도록 만드는 방법
  
  - 난 그래도 의존 관계 주입으로 부르련다.
  
  ### p294
  
  #### 인터페이스 주입
  
  - 다음과 같은 방식이며, interface를 통해 더 명시적으로 선언하므로 표현은 다르지만, 객체가 생성된 후에 주입된다는 관점에서는 setter 주입과 같다.
  
  ```java
  public interface XXXInjectable {
    public void inject(XXX xxx);
  }
  
  public YYY implements XXXInjectable {
  
    private XXX xxx;
  
    @Override
    public void inject(XXX xxx) {
      this.xxx = xxx;
    }
  }
  ```
  
  ### p296
  
  #### 숨겨진 의존성과 Service Locator 패턴
  
  - Service Locator 패턴을 사용하면 의존 관계가 퍼블릭 인터페이스에 드러나지 않으므로 숨겨진 의존성이 존재하게 된다.
  - 퍼블릭 인터페이스에 의존하는 다른 부분에서는 숨겨진 의존성이 해소되지 않은 불완전한 객체를 사용할 위험 존재
  - 컴파일타임에는 발생하지 않고 런타임에 발생하므로 좋지 않음
  - 숨겨진 의존성을 안다는 것은 내부를 안다는 것이므로 정보 감춤 원칙 위배를 수반하므로 좋지 않음
  
  ### p303
  
  #### 의존성 역전 원칙(Dependency Injection Principle)
  
  >구조적 분석 설계 같은 전통적인 소프트웨어 개발 방법에서는 상위 모듈이 하위 모듈에 의존하는 경향이 있다.  
  >이를 역전시켜서 하위 모듈이 상위 모듈에 의존하도록 해야 하위 모듈에서 발생하는 변경이 상위 모듈에 전파되지 않는다.
  
  ### DIP와 패키지
  
  >- 클라이언트가 의존하는 인터페이스를 그 인터페이스 구현체와 같은 패키지에 두는 것이 전통적 방식  
  >- 이 부분도 역전시켜서 인터페이스는 그 인터페이스를 사용하는 클라이언트가 속한 패키지에 두어야, 클라이언트가 하위 모듈이 있는 패키지에 의존하지 않게 된다.
  
  - 그럼 구현체가 속한 패키지에서는 컴파일타임에 그 인터페이스를 어떻게 인식하나?
    - **구현체가 속한 패키지는 하위 패키지이며, 하위 패키지가 인터페이스가 속한 상위 패키지에 의존하는 것은 문제되지 않음**
    - 즉 구현체가 속한 하위 패키지가 인터페이스가 속한 상위 패키지에 의존하게 하면 컴파일타임에 문제 없이 인터페이스를 인식할 수 있다.
  
  ### p305
  
  #### 유연성과 복잡성
  
  >유연성은 항상 복잡성을 수반한다. 유연하지 않은 설계는 단순하고 명확하다. 유연한 설계는 복잡하고 암시적이다.  
  
  - 그렇다. 스프링이나 하이버네이트 등 주요 프레임워크의 소스를 가끔 보다보면, 결합도는 낮고, 응집도는 높고, 유연성은 높은 좋은 구조를 가지고 있겠지만 단순하게 생각하면 너무 복잡하게 얽혀있어서 이해하기 어려운 면이 있다.
  
  >설계가 유연할수록 클래스 구조와 객체 구조 사이의 거리는 점점 멀어진다.
  
  - 유연성은 결국 런타임에 구상체를 교체할 수 있음을 의미하며, 이는 컴파일타임의 정적 클래스 구조와 런타임의 동적 객체 구조가 다르다는 사실에 바탕을 둔다. 따라서 유연성이 높아지면 클래스 구조와 객체 구조 사이의 거리가 멀어진다.
  
  ### p307
  
  #### 의존성과 역할, 책임, 협력
  
  의존성을 관리해야 하는 이유는 결국 변경의 전파를 최소화하는 데 있고, 변경의 전파를 최소화하려면 역할, 책임, 협력에 먼저 중점을 두고 객체의 생성은 나중에 결정해야 한다.
  
  
  
  
  
  ## 10. 상속과 코드 재사용
  
  - 중복을 제거하기 위해 타입 코드를 추가하고, 타입 코드를 조건으로 로직을 분기하는 방법은 응집도를 낮추고 결합도를 높이며 객체지향적이지 않다.
  - **오로지 중복을 제거하기 위해 상속이라는 객체지향의 도구를 사용하는 것은 대개 바람직하지 않다.**
  - 왜냐하면 상속은 다음과 같은 본연의 단점이 있기 때문이다.
    - **부모 클래스는 어떤 메서드가 자식 클래스에서 override 되는지 모르므로, 부모 변경 시 override 관련 내용을 모두 분석해야 하며, 이는 정보 감춤과 캡슐화를 깨게 된다.**
    - **일반 객체 참조는 단방향이지만, 부모-자식 관계에서는 코드에 드러나지 않은 채로 양방향 호출이 가능하다.**
    - **부모 클래스에 인스턴스 변수가 추가되면 자식 클래스에도 인스턴스 변수 관련 코드를 추가해야 한다.**
  - 따라서 **상속은 도메인 개념상 상속 관계가 명확할 때만 제한적으로 사용하고, 중복 제거 및 코드 재사용을 위해서는 상속보다 합성을 사용하는 것이 낫다.**
    - **상속을 사용하더라도 `abstract` 키워드를 클래스와 메서드에 적절히 사용해서 의도를 명확히 드러내는 것이 좋다.**
  
  ### p309
  
  #### 중복 코드
  
  >요구사항이 변경됐을 때 두 코드를 함께 수정해야 한다면 이 코드는 중복이다.  
  >함께 수정할 필요가 없다면 중복이 아니다.
  
  - 내용적으로 같다고 하더라도 사용되는 위치와 시점이 다르다면 요구사항이 변경됐을 때 함께 수정되지 않는 때도 있다. 
  - 이런 중복은 제거해야할 해로운 중복이 아니라, 그저 현 시점, 현 상황에서 하는 일이 같을 뿐이다.
  
  ### p314
  
  #### 중복의 폐해
  
  - 비슷한 기능/역할을 추가하는 가장 쉬운 방법은 복붙. 따라서 복붙의 강력한 유혹을 뿌리치지 못하면 중복 코드가 아주 쉽게 자라난다.
  - **중복된 코드에 변경이 필요하면 중복된 모든 곳에 변경을 적용해야하지만, 변경을 적용하는 입장에서는 중복된 모든 곳을 파악해서 모두 적용한다는 보장이 없으므로, 변경이 적용되지 않은 곳에서 오류가 발생한다.**
  - **중복된 곳을 모두 파악하고 적용해서 오류가 없다 하더라도 결국 중복을 증폭시킨 결과밖에 안 된다.**
  
  ### p316
  
  #### 타입 코드
  
  - 중복을 피하기 위한 가장 간단한 방법
  - 중복되는 부분은 하나로 합치고, 중복되지 않는 부분은 타입을 조건으로 분기해서 처리
  - 낮은 응집도, 높은 결합도로 이어짐
  
  ### p320
  
  #### 상속의 단점
  
  >일반 요금 계산이 부모 클래스, 심야 요금 계산이 자식 클래스인 사례  
  >    - `일반 시간대의 일반 요금 + 심야 시간대의 일반 요금`이 아니라 `전체 시간대의 일반 요금 - 심야 시간대의 일반 요금`으로 계산하는 케이스
  
  - 자식 클래스 작성자가 부모 클래스의 내부 구현에 대해 정확한 지식을 가져야 한다는 것을 의미한다.
  - 이는 부모 클래스의 변경이 닫혀있지 않고 자식 클래스에 열려 있다는 의미이며, 모든 자식 클래스에 미치는 영향을 분석해야 안전성을 보장할 수 있다.
  - 중복 제거를 위해 상속을 사용했지만, 세금 부과라는 요구사항 충족을 위해 부모 클래스와 자식 클래스 모두에 중복 코드 작성
  
  >자식 클래스 메서드 안에서 super 참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 두 클래스는 강하게 결합된다.
  
  - 이 부분은 부연 설명이 있으면 좋겠다. 상속 자체가 구조적으로 강결합을 막지 못하는 한계가 있는 것이지, super 참조를 통한 호출이 강결합을 유발하는 걸까?
  
  ### p323
  
  #### Fragile Base Class 문제
  
  - 책에는 코드가 없는데 위키피디아에 있는 [Fragile Base Class](https://en.wikipedia.org/wiki/Fragile_base_class) 예제를 보면 더 쉽게 알 수 있다.
  
      ```java
      class Super {
  
        private int counter = 0;
  
        void inc1() {
          counter++;  // inc2(); 로 바꾼다면?
        }
  
        void inc2() {
          counter++;
        }
  
      }
  
      class Sub extends Super {
  
        @Override
        void inc2() {
          inc1();
        }
  
      }
      ```
  
      - 아래와 같이 일상적인 Super, Sub 관계로 사용하고 있을 때,
  
        ```java
        Super super = new Sub();
        ```
  
      - Super 에 있는 `void inc1() { counter++; }`를 `void inc1() { inc2(); }`로 변경하면 어떻게 될까?
      - 이는 결국 `void inc1() { sub.inc2(); }`가 되므로 `sub.inc2() -> super.inc2() -> sub.inc2() ...` 이런 무한루프가 된다.
  
  - 부모 클래스에서 호출하는 부모 클래스 내의 non-private 메서드가 자식 클래스에서 override 되어있는지 아닌지 부모 클래스 내에서는 알 수가 없다.
  - 심지어 **부모 클래스는 abstract로 선언되지 않는 한 자기가 부모 클래스인지 조차도 모른다.**
  - **override가 되어 있지 않다고 가정하고 반영한 수정사항은, 위와 같이 실제로는 override 돼있는 경우에는 오류를 발생시킬 수 있다.**
  - 따라서 변경해도 오류가 발생하지 않음을 보장하려면 모든 자식 클래스를 조사해서 override 여부와 그에 따른 오동작 여부를 모두 점검해야 한다.
  - 즉, **정상 동작을 보장하려면 자식 클래스의 구체 내용을 알아야만 하므로 결합도가 높아진다.**
  
  #### (책에 없는 내용) 일반적인 객체 참조와 상속 관계 참조의 차이
  
  - 아래와 같은 일반적인 객체 참조는 단방향이다. A는 B를 알지만 B는 A를 모른다.
  
  ```java
  class A {
    private B b;
  
    public void a1() {
      b.b1();
    }
  }
  
  class B {
    public void b1() {
      ...
    }
  }
  ```
  
  - 하지만 위 Fragile Base Class에서 살펴본 것처럼, 부모 클래스의 non-private 메서드는 자식 클래스에서 override 될 수 있고, 부모 클래스에서는 자식 클래스에서 override 된 메서드를 호출할 수 있으므로 **상속 관계에서는 양방향 호출이 발생할 수 있다.**
  
  ### p324
  
  #### 불필요한 인터페이스 상속
  
  >- Stack이 Vector를 상속한 사례
  >    - Stack에서 add(index, value), remove(index)도 가능
  >- Properties가 Map을 상속한 사례
  >    - Properties에서 put(stringKey, nonStringValue)로 값 넣기 가능
  >    - Properties에서 get(stringKey)의 값이 nonStringValue이면 실제 null이 아닌 데도 null 반환
  >
  >**단순히 코드를 재사용하기 위해서 불필요한 오퍼레이션이 인터페이스에 스며들도록 방치해서는 안 된다.**
  
  ### p326
  
  #### 메서드 오버라이딩 오작용
  
  >Effective Java에 나온 HashSet, InstrumentedHashSet의 원소 count 사례
  
  - 위 일반적인 객체 참조와 상속 관계 참조의 차이에서 설명한 것처럼 내부를 알아야만 안전성을 보장받을 수 있다면, 객체지향의 정보 감춤, 캡슐화는 깨진다.
  
  ### p329
  
  #### 부모 클래스와 자식 클래스 동시 수정 문제
  
  >-노래 목록만 관리하던 Playlist, PersonalPlayList에서
  >    - Playlist에 <singer, title>이 추가되면 PersonalPlaylist에도 수정이 필요해지는 사례
  
  - override가 없는 데도 발생하는 문제!!
  - **부모 클래스에 인스턴스 변수가 추가되면 자식 클래스에는 이를 초기화해줄 코드가 반드시 추가돼야하는 결합이 발생하며, 이를 우회할 방법은 없다.**
  
  ### p332
  
  #### 상속을 쓰면서도 안정성을 높이는 리팩터링
  
  >1. 부모, 자식에서 차이나는 부분을 각각 별도의 private 메서드로 분리
  >    - 구현은 다르지만 signature는 같다.
  >2. 차이나는 부분을 덜어낸 결과 공통되는 부분(인스턴스 변수 포함)을 abstract 클래스로 올림
  >    - abstract 키워드가 상속이 된다는 명확한 의도를 드러낸다.
  >3. 1에서 분리된 메서드의 signature 그대로 abstract 클래스에 abstract 메서드로 선언
  >    - abstract 키워드가 자식 클래스에서 override 된다는 명확한 의도를 드러낸다.
  
  - `abstract` 키워드를 클래스와 메서드에 적절히 사용해서 상속 구조에서 발생하는 불안정성을 줄인다.
  - 상위 `abstract` 클래스에서는 `abstract`로 선언된 추상 메서드에만 의존할 뿐 하위 구체 클래스에 의존하지 않는다.
    - 하위 구체 클래스에 의존하는 것이 아니라 하위 구체 클래스를 통해 기능 확장이 가능하도록 열어둔다.
  - 외부에서는 하위 구체 클래스가 아니라 상위 추상 클래스에 의존한다.
  
  ### p345
  
  #### 상속, 잘 써야..
  
  >상속은 코드 중복을 제거하고 재사용성을 높일 수 있는 가장 유명한 방법  
  >하지만 상속의 오남용은 애플리케이션을 이해하고 확장하기 어렵게 만든다.
  
  - 상속은 코드 재사용만을 목적으로 적용하기엔 단점이 많다.
  - **개념상 상속이 명확한 경우에만 제한적으로 상속을 사용하고, 코드 재사용이 목적이라면 상속보다 합성을 사용하자.**
  
  
  
  
  
  ## 11. 합성과 유연한 설계
  
  - 구현 상속은 조합이 많아지면 서브클래스가 많아지고 중복 코드도 많아진다.
  - 합성은 컴파일타임에는 인터페이스에만 의존하고 런타임에 구현체를 주입해서 쓸 수 있으므로 불필요한 결합도 상승이 발생하지 않는다.
  - **상속은 부모클래스의 구현부를 재사용, 합성은 포함되는 객체의 인터페이스를 재사용**
  
  ### p347
  
  #### 재사용의 대상
  
  >상속은 부모 클래스 안에 구현된 코드 자체를 재사용  
  >합성은 포함되는 객체의 퍼블릭 인터페이스를 재사용
  
  - 결국 합성을 사용하면 런타임에 의존 관계를 변경할 수 있어 더 유연한 설계
  
  ### p352
  
  #### 몽키 패치
  
  - 특정 모듈(클래스 등)에 대한 수정 권한이 없더라도 현재 실행 중인 환경에 한해서 수정할 수 있는 방법
  - 루비의 Open Class, C#의 Extension Method, Scala의 Implicit Conversion 등이 몽키 패치의 예라고 함.
  - 자바는 몽키 패치를 지원하지 않지만 Byte Code Instrumentation이나 AOP로 비슷한 효과를 낼 수 있다.
  
  ### p353
  
  #### 상속으로 인한 조합의 폭발적인 증가
  
  - 요금 할인과 세금 부과 등의 다양한 조합이 필요할 때 상속을 사용하면 각 조합마다 서브클래스를 만들어야 하므로 클래스의 수가 폭발적으로 증가할 수 있다.
  - 이렇게 클래스가 많아지면 중복 코드도 많아지게 된다.
    - **중복을 제거할 목적으로 상속이라는 방법을 선택했는데 결과적으로 중복이 증가하는 아이러니**
  
  
  ### p368
  
  #### 합성 관계로 변경하기
  
  - 실제 요구사항에 맞게 여러 정책 적용 방식을 객체 단위로 나누어 의존관계를 보고 규칙 파악
  - 규칙에 따라 인터페이스를 추출하고, 인터페이스를 포함하는 합성 관계 구성
  - 정책의 구체 구현은 인터페이스 구현체에서 작성
  - 런타임에서 실제 사용될 구현체를 인터페이스에 주입
  
  ### p379
  
  #### 믹스인
  
  - 스칼라로 설명하니 잘 이해가.. 걍 패스..
  
  
  
  
  
  ## 12. 다형성
  
  - 크게 2개, 세부적으로 4개의 다형성으로 분류 가능
  - 일반적으로 다형성이라고 하면 대부분 메서드 오버라이딩을 통한 다형성을 가리킴
  - 메서드는 인스턴스 별로 따고 가져야할 이유가 없으므로 인스턴스별 공간이 아니라 클래스 정보 공간에 포함돼 있음
  - self -> class -> parent -> parent -> ... 와 같이 **메시지를 수신한 객체에서부터 상속 관계 위쪽 방향으로 메서드를 찾음**
    - 자식 클래스의 메서드가 부모 클래스의 메서드를 덮어쓰는 것같은 효과가 발생할 수 있는 이유
  - **self는 항상 메서드를 처음 수신한 객체를 가리키며, 상속 관계 위쪽으로 메서드를 찾아갈 때 self 참조도 함께 전달됨**
    - 부모 클래스에서 자식 클래스의 메서드를 호출할 수 있는 이유
  - 상속은 클래스를 통해서만 가능한 개념이 아님. 자바스크립트처럼 클래스가 아닌 프로토타입을 통해서도 상속 구현 가능
  
  ### p389
  
  #### 상속 사용 기준
  
  >단순히 코드를 재사용할 목적이면 상속을 사용하지 말아야 한다.  
  >다형성을 위해서라면 상속을 고려해볼만하다.
  
  ### p390
  
  #### 다형성의 종류
  
  ```
  다형성 - [Universal, Adhoc]
    Universal - [Parametric, Inclusion]
      Parametric: 제네릭을 통한 다형성
      Inclusion: 메서드 오버라이딩을 통한 다형성. 서브타입 다형성이라고도 부른다.
    Adhoc - [Overloading, Coercion]
      Overloading: 메서드 오버로딩
      Coercion: 문자 + 숫자 시 강제로 문자열 연결 수행
  ```
  
  ### p400
  
  #### 상속의 개념적 구조
  
  >상속을 인스턴스 관점에서 바라볼 때는 개념적으로 자식 클래스의 인스턴스 안에 부모 클래스의 인스턴스가 포함되는 것으로 생각하는 것이 유용하다.
  
  - 스코프와는 혼동하지 말자
  
  #### 데이터와 행동의 물리적 차이
  
  >객체의 경우 인스턴스 별로 다른 상태를 가질 수 있도록 인스턴스 별로 독립적인 메모리를 할당받아 상태를 저장  
  >메서드는 인스턴스 별로 다르지 않으므로 동일한 클래스의 인스턴스끼리 공유 가능  
  >따라서 메서드가 포함된 클래스 정보는 한 번만 메모리에 로딩하고, 인스턴스 별로 클래스를 가리키게 하는 포인터를 갖게 하는 것이 경제적
  
  - 각자 다른 상태를 나타내야하는 인스턴스 변수는 인스턴스 별 독립적 메모리에 저장
  - 같은 클래스의 메서드는 인스턴스 별로 다를 필요가 없으므로 클래스 정보 한 곳에 저장하고 인스턴스에게 모두 공유
  
  ### p402, p408
  
  #### 메시지를 받은 객체가 이를 처리할 메서드를 찾는 과정
  
  - 객체가 메시지를 수신하면 컴파일러는 self 참조를 자동으로 생성하고 메시지를 수신한 객체를 가리키도록 설정한다.
  - 객체는 메서드 정보를 가지고 있는 클래스에 대한 참조(class라고 하자)를 갖는다.
  - self가 가리키는 객체가 가지고 있는 class를 통해 클래스 정보에서 메서드 시그니처 기준으로 메서드를 찾아서 있으면 실행
  - 없으면 클래스의 부모 클래스를 가리키는 참조(parent라고 하자)를 통해 부모 클래스에서 메서드를 찾는다.
    - **parent가 부모 클래스의 인스턴스를 가리키는 걸까 아니면 부모 클래스를 가리킬까?**
  - parent에 없으면 parent의 parent인 클래스에서 메서드를 찾고 없으면 다시 parent... 반복
  - 최상위 클래스(Object)에도 없으면 에러 발생
  
  **자식 클래스 인스턴스를 부모 클래스 인스턴스에 할당해서 업캐스팅 되더라도, 메서드 호출 시 자식 클래스의 메서드가 먼저 호출되는 이유는, 메서드 식별 과정이 위아 같이 이뤄지기 때문.**
  
  ### p424
  
  #### super 참조
  
  >(메서드 호출에 사용되는) super 참조의 정확한 의도는 '지금 이 클래스의 부모 클래스에서부터 메서드 탐색을 시작하세요'다.
  
  - 자바에서는 `super`로 부모 클래스의 `rotected` 등 볼 수 있게 선언된 변수에도 접근할 수 있으므로, `super`가 꼭 메서드 탐색에만 사용되는 것은 아님
  
  ### p425
  
  #### 상속과 super 참조
  
  - self는 메시지를 받은 객체를 가리킨다.
  - 상속에서는 메시지를 받은 객체가 자신이 포함하고 있는 부모 객체에 자신을 가리키는 self 참조를 부모 객체에 자동으로 전달해준다고 생각해도 무방
  - 부모 객체는 또 그 부모 객체에게 self 참조를 전달
  - **결국 self는 객체는 상속 구조 안에 있는 어디에서나, 최초에 메시지를 받은 객체를 가리킨다.**
  
  
  ### p429
  
  #### 포워딩과 위임
  
  >자신이 수신한 메시지를 다를 객체에게 동일하게 전달해서 처리를 요청하는 것을 위임(delegation)이라고 부른다.
  
  - 여기에서 말하는 위임이 객체지향에서 일반적으로 말하는 위임인지 모르겠음
  - 동일하게 전달해야만 위임이고, 받은 메시지의 전체적인 처리를 위해 특정 부분의 처리를 다른 객체에게 맡기는 것은 위임이 아닌 건가?
  
  >메시지를 받은 객체가 받은 메시지의 처리를 다른 객체에게 요청하면서,
  >    - self를 다른 객체에게 전달하면 위임  
  >    - self를 전달하지 않으면 포워딩(forwarding)
  
  - 상속은 self 전달을 언어에서 지원해주므로 편리
  - 그런데 self를 전달하지 않는 포워딩이라는 게 자바에서도 존재하는 건지 모르겠음
  
  ### p430
  
  #### 프로토타입(prototype) 기반 객체지향
  
  - 자바스크립트의 프로토타입 체인
  - 클래스 기반 상속은 컴파일 타임에 정적으로 결정되는데 반해, 자바스크립트의 프로토타입 체인 기반 상속은 런타임에 동적으로 결정
  - super와 비슷하게 `[[Prototype]]`(스펙에서 사용되는 표현) 또는 V8 엔진이나 nodejs에서는 `__proto__`를 통해 연쇄적으로 부모 객체를 따라가며 식별자를 찾음
  - self 참조와 마찬가지로 프로토타입 안에서 `this`를 통해 실제 메시지를 수신한 객체를 참조할 수 있음
  - 정확한 내용은 ㅍhttps://meetup.toast.com/posts/104 참고
  
  
  
  
  