대부분의 사람들은 클래스를 결정한 후 클래스에 어떤 속성과 메서드가 필요한지 고민한다. 하지만 진정한 객체지향 패러다임으로의 전환은 클래스가 아닌 객체에 초점을 맞출 때 얻을 수 있다.
객체는 상태와 행동을 함께 가지는 복합적인 존재이다. 이처럼 데이터와 기능을 객체 내부를 함께 묶는 것을 캡슐화 라고 한다.
대부분의 객체지향 프로그래밍 언어들은 외부의 접근을 통제할 수 있는 접근제어 메커니즘을 제공한다.
캡슐화와 접근제어는 객체를 퍼블릭 인터페이스와 구현 두 부분으로 나눈다.
클래스 작성자는 클라이언트 프로그래머에게 필요한 부분만 공개하고 나머지는 숨겨야 한다.
이를 구현 은닉이라 한다.
작성자는 클라이언트의 영향을 걱정하지 않고 구현을 변경할 수 있으며,
클라이언트는 인터페이스만 이해하면 되므로 알아야 할 지식의 양을 줄일 수 있다.
객체지향의 세계에서 각 객체들은 서로의 메서드를 호출하며 상호작용한다.
이처럼 시스템의 어떤 기능을 구현하기 위해 객체들 사이에 이뤄지는 상호작용을 협력 이라고 부른다.
객체가 다른 객체와 상호작용할 수 있는 유일한 방법은 메시지를 전송 하는 것.
다른 객체에게 요청이 도착할 때 해당 객체가 메시지를 수신 했다고 표현한다.
이처럼 수신된 메시지를 처리하기 위한 자신만의 방법을 메서드 라고 부른다.
컴파일 시점의 의존성과 런타임에서의 의존성은 다를 수 있다.
유연하고 쉽게 재사용이 가능하며 확장 가능한 객체지향 설계가 가지는 특징은 이처럼 컴파일/런타임 의존성이 상이하다.
하지만 이렇게 컴파일/런타임 의존성이 상이할 수록 코드를 이해하기는 어려워진다.
훌륭한 객체지향 설계자로 성장하기 위해서는 항상 유연성과 가독성 사이에서 고민해야 한다. 무조건 유연한 설계도, 무조건 읽기 쉬운 코드도 정답이 아니다.
상속은 구현상속과 인터페이스 상속으로 분류할 수 있다.
순수하게 코드를 재사용하기 위한 목적으로 상속을 하는 것을 구현상속이라 하고,
다형적인 협력을 위해 부모클래스와 자식클래스가 인터페이스를 공유할 수 있도록 상속을 이용하는 것을 인터페이스 상속이라고 한다.
상속은 구현상속이 아닌 인터페이스 상속을 위해 사용해야 한다.
구현을 재사용할 목적으로 상속을 사용하게 되면 변경에 취약한 코드를 낳게 될 확률이 높다.
상속은 객체지향에서 코드를 재사용하기 위해 널리 사용되는 기법이나, 두 가지 관점에서 설계에 안좋은 영향을 미친다.
1. 캡슐화를 위반한다.
합성은 상속이 가지는 두 가지 문제점을 모두 해결한다.
인터페이스에 정의된 메시지를 통해서만 재사용이 가능하기 때문에 구현을 효과적으로 캡슐화할 수 있다.
의존하는 인스턴스를 교체하는 것이 비교적 쉽기 때문에 설계를 유연하게 만든다.