객체와 자료구조를 구분하고 언제 사용해야하는지 알아보자.
구현을 외부로 노출하고 구현을 완전히 숨긴 두 클래스가있다.
public class Point {
public double x;
public double y;
}
// 인터페이스가 자료구조를 명백하게 표현하고있다.
public interface Point {
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
자료를 세세하게 공개하기보다는 추상적인 개념으로 표현하는 편이 좋다.
책에서는 다음과 같이 이야기한다.
추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 의미의 자클래스다.
새로운 자료 타입이 필요할 경우 클래스와 객체지향 기법이 적합하다.
반면에 새로운 자료타입이 아닌 새로운 함수가 필요하다면 절차적인 코드와 자료구조가 더 적합할 수 있다.
때로는 단순한 자료구조와 절차적인 코드가 가장 적합한 상황도 있다는 말이다.
디미터 법칙은 잘 알려진 휴리스틱으로 모듈은 자신이 조작하는 객체의 속사정을 몰라야한다
라는 법칙이다.
휴리스틱?
휴리스틱(heuristics) 또는 발견법(發見法)이란 불충분한 시간이나 정보로 인하여 합리적인 판단을 할 수 없거나, 체계적이면서 합리적인 판단이 굳이 필요하지 않은 상황에서 사람들이 빠르게 사용할 수 있게 보다 용이하게 구성된 간편추론의 방법을 말한다.
정확히 표현하자면 클래스 C의 메소드 f는 다음과 같은 객체의 메소드만 호출해야한다
라고 주장한다.
위 객체에서 허용된 메소드가 반환하는 객체의 메소드는 호출하면 안된다.
즉, 쉽게말해 친구랑만 놀라는 이야기다.
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
위 코드는 디미터의 법칙을 어긴다는 것을 확인할 수 있다.
위와 같은 코드는 여러 객체가 한줄로 이어진 기차처럼 보여 기차충돌 (train wreck)이라고 부른다.
매우 조잡한 방식이니 지양해야한다.
하지만 만약 내부 항목이 객체가아닌 자료구조라면 디미터법칙이 적용되지 않는다.
final String outputDir = ctxt.options.scratchDir.absolutePath
위와같은 혼란으로부터 때때로 절반은 객체, 절반은 자료구조인 잡종구조가 나온다.
이런 구조는 새로운 함수는 물론이고 새로운 자료구조도 추가하기가 어렵기 때문에 피하는 편이 좋다.
위 잡종구조에서 예시로 들었던 코드를 다시보자.
final String outputDir = ctxt.options.scratchDir.absolutePath
만약 ctxt
가 객체라고 가정해보면, 저렇게 많이 파고들어가야할 근본적인 이유를 찾아보고 적절한 임무를 부여해야한다.
예를들어 위 코드는 임시 파일을 생성하기 위한 목적을 위해 작성된 코드라고 가정해보자.
그렇다면 다음과 같이 임시 파일을 생성하라는 메소드를 만들어주는 것이 더 좋은 선택지라고 할 수 있겠다.
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
흔히 DTO는 DB에 저장된 정보를 코드에서 사용할 객체로 변환하는 일련의 단계에서 사용하는 구조체다.
DTO는 JavaBeans를 따른다고한다.
참고자료_DTO와 Java Bean
활성레코드
활성레코드는 DTO의 특수한 형태다.
공개변수가 있거나 비공개변수에 Getter/Setter 함수가 있는 자료구조이지만 대개 save나 find 같은 탐색함수도 제공한다.
활성레코드는 DB 테이블이나 자른 소스에서 자료를 직접 변환한다.
MVC 아키텍처에서의 Model이 대표적인 예시가 되겠다.
자료/객체 비대칭에서 이야기했듯이
어떤 시스템을 구현할 때 새로운 자료타입을 추가하는 유연성이 필요하면 객체가,
새로운 동작을 추가하는 유연성이 필요하면 자료구조와 절차적인 코드가 더 적합하다.
경우에 따라 유연하게 작성할 필요가 있다.