변수를 비공개로 정의하는 이유가 있다. 남들이 변수에 의존하지 않게 만들고 싶어서다. 그렇다면 왜 조회 함수와 설정 함수를 공개해 비공개 변수를 외부에 노출하는가?
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);
}
추상적이다. 추상적인 이 클래스는 직교 좌표계를 사용하는지 극좌표계를 사용하는지 알 길이 없다. 그럼에도 불구하고 인터페이스는 자료 구조를 명백하게 표현한다.
자료구조 이상을 표현한다. 클래스 멧드가 접근 정책을 강제한다.
변수를 private으로 선언하더라고 각 값마다 조회 함수와 설정 함수를 제공한다면 구현을 외부로 노출하는 셈이다.
추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 의미의 클래스다.
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
자동차 연료 상태를 구체적인 숫자 값으로 알려준다. 두 함수가 변수값을 읽어 반환할 뿐이라는 사실이 거의 확실하다.
public interface Vehicle {
double getPercentFuelRemaining();
}
자동차 연료 상태를 백분율이라는 추상적인 개념으로 알려준다. 정보가 어디서 오는지 전혀 드러나지 않는다.
객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다. 자료 구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.
때로는 단순한 자료 구조와 절차적인 코드가 가장 적합한 상황도 있다.
디미터 법칙은 잘 알려진 휴리스틱으로, 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙이다.
좀더 정확히 표현하자면, "클래스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다"
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
위와 같은 코드를 기차 충돌이라 부른다. getOptoins() 함수가 반환하는 객체의 getScratchDir() 함수를 호출한 후 getScratchDir() 함수가 반환하는 객체의 getAbsolutePath() 함수를 호출하기 때문이다.
Options opts = ctxt.getOptions();
File scrachDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
위의 코드가 더 낫다.
만약 자료구조라면 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.
애초에 ctxt가 객체라면 속을 드러내라고 말하지 말고 메시지를 보내는 것이 제일 낫다.
객체는 동작을 공개하고 자료를 숨긴다. 그래서 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면, 기존 객체에 새 동작을 추가하기는 어렵다. 자료 구조는 별다른 동작 없이 자료를 노출한다. 그래서 기존 자료 구조에 새 동작을 추가하기는 쉬우나, 기존 함수에 새 자료구조를 추가하기는 어렵다.
시스템을 구현할 때, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적합하다. 다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.