6. 객체와 자료 구조
자료 추상화
자료를 세세하게 공개하기보다는 추상적인 개념으로 표현하는 것이 좋다.
인터페이스나 조회/설정 함수만으로는 추상화가 이뤄지지 않는다.
개발자는 객체가 포함하는 자료를 표현할 가장 좋은 방법을 심각하게 고민해야 한다.
아무 생각 없이 조회/설정 함수를 추가하는 방법이 가장 나쁘다.
자료/객체 비대칭
객체와 자료 구조는 근본적으로 양분된다.
객체 지향 코드에서 어려운 변경은 절차적인 코드에서 쉬우며,
절차적인 코드에서 어려운 변경은 객체 지향 코드에서 쉽다.
복잡한 시스템을 짜다보면 새로운 함수가 아니라 새로운 자료 타입이 필요한 경우가 생기는데,
이 때는 클래스와 객체 지향 기법이 가장 적합하다.
반면, 새로운 자료 타입이 아니라 새로운 함수가 필요한 경우도 있는데, 이 때는 절차적인 자료 구조가 좀 더 적합하다.
디미터 법칙
모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙
기차 충돌
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
위와 같은 형태(꼬리에 꼬리를 무는 형태) 를 기차 충돌이라 하며, 지양해야 하는 방법이다.
하지만, 디미터의 법칙을 위반하느냐 하면 그건 확실히 알 수가 없다.
객체일 경우에는 위반하는 것이 되지만(객체라면 내부 구조를 숨겨야 하므로),
자료 구조라면 당연히 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.
But, final String outputDir = ctxt.options.scratchDir.absolutePath 였다면, 논란이 필요없다.
잡종 구조
객체와 자료구조의 형태가 섞인 구조로 새로운 함수는 물론이고 새로운 자료 구조도 추가하기 어렵다.
양쪽에서 단점만 모와놓은 구조라 볼 수 있다.
함수나 타입을 보호할지 공개할지 확신하지 못해 어중간하게 내놓은 설계에 불과
자료 전달 객체
자료 구조체의 전형적인 형태는 공개 변수만 있고, 함수가 없는 클래스다.
이런 자료 구조체를 떄로는 자료 전달 객체 Data Transfer Object (DTO) 라 한다.
그리고 좀 더 일반적인 형태는 빈(bean) 구조이다. 빈은 private 변수를 조회/설정 함수로 조작한다.
일종의 사이비 캡슐화로 별다른 이익을 제공하지 않는다.
활성 레코드
DTO 의 특수한 형태이다. DTO + save/find 같은 함수도 제공한다.
활성 레코드는 데이터베이스 테이블이나 다른 소스에서 자료를 직접 변환한 결과다.
이런 레코드에 비지니스 규칙 메서드를 추가할 경우 잡종이 되므로, 활성 레코드는 자료 구조로 취급하고, 비즈니스 구조는 따로 가져간다.
결론
객체는 동작을 공개하고 자료를 숨긴다.
그래서 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면,
기존 객체에 새 동작을 추가하기는 어렵다.
자료 구조는 별다른 동작 없이 자료를 노출한다.
그래서 기존 자료 구조에 새 동작을 추가하기는 쉬우나, 기존 함수에 새 자료 구조를 추가하기는 어렵다.
어떤 시스템을 구현할 때 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가,
다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.
결국 이렇다 하는 정답은 없는 것이다.
사견을 덧붙이면…?
이번 장의 내용은 짧다. 정말 짧지만, 이해하는 데에는 꽤나 많은 시간이 들었던 장이다.
특히 앞 장의 객체와 자료구조를 읽으면서… 내가 평소에 만드는게 객체 인지 자료구조인지…
이게 이건가? 저게 이건가? 하면서 명확하지 않은 채로 읽었기 때문이다. (일단 처음엔 읽는다, 이해가 안되도 그냥)
뒤로 가면서 익숙한게 나와서 그나마 좀 명확해졌는데, 그 부분이 바로 자료 전달 객체 이 부분이다.
완전 쌩신입 때의 나는 그저 DTO 만 만들었고 (그러다가 본 건 있어서 잡종 구조가 된 것 같기도 하다.)
최근까진 이게 클래스, 객체, 빈 다 총칭하는 줄 알았다.
이제는 둘의 차이점도 알았겠다. 최대한 잡종 구조는 지양, 경계하면서 코딩해야겠다.