OOD 의 목표는 코드 수정 비용 줄이기
어플리케이션 디자인의 핵심은 메시지
그래서 엄격하게 정의된 public interface
를 구축하는 과정이 중요
이 기술의 이름은 오리타입 (duck typing
)
객체의 클래스보다는 행동에 의해 규정되는 카멜레온
타입: 프밍 언어들은 타입이라는 개념을 통해 변수의 내용물이 어떤 카테고리에 속하는지 설명하려함 string: 문자열, number: 숫자, array: 배열 등
타입을 통해 내용물이 어케 행동하는지 예측 가능
타입을 예측할 수 있는 이유는 객체들의 퍼블릭 인터페이스
를 믿기 때문
한 객체가 다른 객체의 타입을 알고 있다면 대상 객체가 반응할 수 있는 메시지를 알고 있는 것
객체는 서로 다른 여러 개의 인터페이스 구현 가능
모든 객체가 어떤 타입이든 될 수 있다고 믿으면 디자인의 무한 가능성 열림
이런 유연성을 사용하기 위해 클래스를 가로지르는 타입(across-class types)
을 알아 볼 수 있어야함
오리 타입을 이해하기 위해, 오리타입을 사용하지 않았을 때 부터 알아보자
Trip 의 prepare 메서드는 인자로 받은 mechanic 객체에게 prepare_bicycles 메시지를 전송
class Trip {
readonly bicycles: array
readonly customers: any
readonly vehicle: any
// 무엇이든 'mechanic' 인자의 클래스가 될 수 있음
prepare(mechanic) {
return mechanic.prepare_bicycles(bicycles)
}
}
// 우연히 아래 클래스의 인스턴스를 넘겨주면 제대로 작동함
class Mechanic {
prepare_bicycles(bicycles) {
return bicycles.forEach(b => prepare_bicycle(b))
}
prepare_bicycle(bicycle) {
// ...
}
}
하지만 prepare-bicycles 라는 메서드에 반응할 수 있는 객체를 수신해야한다는 사실에 의존하고 있음
위 코드에서 여행을 어케 준비할지
에 대한 지식을 Mechanic 에게 넘김
요구사항이 변경되어 ㅈ2
class Trip {
readonly bicycles: array
readonly customers: any
readonly vehicle: any
// 여행 준비과정 복잡
prepare(preparers) {
preparers.forEach(function(p) {
switch (p.constructor.name) {
case 'Mechanic':
preparer.prepare_bicycles(bicycles)
case 'TripCoordinator':
preparer.buy_food(customers)
case 'Driver':
preparer.gas_up(vehicle)
preparer.fill_water_tank(vehicle)
default:
}
})
}
}
class TripCoordinator {
buy_food(customers) {
//...
}
}
class Driver {
gas_up(vehicle) {
// ...
}
fill_water_tank(vehicle) {
// ...
}
}
변경된거
Trip 의 prepare 메서드가 3 개의 서로 다른 클래스 참조하고 메서드의 이름도 정확히 알고 있음
위 디자인은 클래스 종속적
이 행동을 실행하는 가장 명확한 건 걍 메시지 전송하기
하지만 문제는
위 prepare 메서드는
의존성 너무 높아짐
또한 이렇게 코딩하면
위 의존성을 제거하기 위해 다음을 이해하자
인자의 클래스가 무엇을 할 줄 아는지
말고 prepare가 무엇을 원하는지
에 집중
prepare 는 여행을 준비하고 싶어함
여행을 준비하는 객체(preparer)
이기만 하면됨결론은 prepare 메서드는 Preparer 에게 어떤 메시지를 전송할지만 생각하면 됨: prepare_trip
Preparer 란 무엇일까?