📌 자료 추상화
아래 두 코드는 2차원 점을 표현했다. 두 번째 코드는 인터페이스로 자료 구조를 명백하게 표현한다. 첫 번째 코드는 변수를 private로 선언하더라도 값마다 get/set 함수를 제공한다면 구현을 외부로 노출시키는 것은 마찬가지다. 따라서 추상 인터페이스를 제공하여 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 의미를 가지는 클래스를 나타낼 수 있다. 즉 개발자는 객체의 자료를 표현할 가장 좋은 방법을 신중하게 고민해야 한다. 생각 없이 get/set 함수를 추가하면 안 된다.
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);
}
📌 자료/객체 비대칭
- 객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.
- 자료 구조는 자료 그대로 공개하여 별다른 함수를 제공하지 않아야 한다.
- 객체 지향 코드에서 어려운 변경은 절차적인 코드에서 쉽고, 절차적인 코드에 어려운 변경은 객체 지향 코드에서 쉽다.
📌 디미터 법칙
디미터 법칙은 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙을 말한다. 디미터 법칙은 클래스 C의 메서드 F는 다음과 같은 객체의 메서드만 호출해야 한다.
- 클래스 C
- f가 생성한 객체
- f가 인수로 넘어온 객체
- C 인스턴스 변수에 저장된 객체
아래 코드는 디미터 법칙을 어기는 코드이다. 해당 코드를 한 줄로 이어진 기차처럼 보이는 기차 충돌(train wreck)이라 부른다.
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
위 코드는 일반적으로 조잡해 보여 지양해야 하며, 아래와 같이 나누는 것이 낫다. ctxt객체가 Options를 포함하고, Options가 ScratchDir을 포함하며, ScratchDir이 AbsolutePath를 포함한다는 사실을 알 수 있다. 이렇게 했다고 해서 디미터 법칙을 어기지 않는다고 할 순 없다. 객체인지 자료 구조인지에 따라 달라질 수 있다. 객체라면 내부 구조를 숨겨야 하니 디미터 법칙을 위반한다. 하지만 자료 구조라면 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
그렇다면 매번 내부를 들여봐야 할까? 생각이 들 수 있다. 위 코드에선 get 함수를 사용해서 혼동이 올 수 있지만 자료 구조는 함수 없이 공개 변수만 포함한다면 아래와 같은 코드를 사용해야 할 것이다. 그렇다면 객체인지 자료 구조인지 쉽게 판별할 수 있다.
final String outputDir = ctxt.options.scratchDir.absolutePath;
여기서 문제는 절반은 객체이고, 절반은 자료 구조인 잡종 구조가 되지 않도록 주의해야 한다. 양쪽 단점을 모아놓은 구조를 만들 수 있기 때문이다. 따라서 중요한 기능을 수행하는 함수도 있고, 공개 변수나 공개 get/set 함수가 있는 것을 피해야 한다.
📌 자료 전달 객체(DTO)
변수만 가지고 별다른 함수가 없는 형태의 객체를 자료 전달 객체(DTO)라고 한다. 사용자에게 받은 메시지나 레이어 간에 데이터를 전달하기 위해 사용한다. DTO 하면 꼭 따라다니는 것이 VO(Value Object)이다. VO는 데이터 그 자체를 의미하는데 이 둘의 차이점에 대해 알아보는 것을 추천한다. (영상)
public class Address {
private String street;
private String streetExtra;
...
public Address(String street, String streetExtra, ...) {
this.street = street;
this.streetExtra = streetExtra;
...
}
public String getStreet() {
return street;
}
public String getStreetExtra() {
return streetExtra;
}
...
}
'책 > CleanCode' 카테고리의 다른 글
✨ Clean Code 9장: 단위 테스트 (0) | 2021.01.31 |
---|---|
✨ Clean Code 7장: 오류 처리 (0) | 2021.01.21 |
✨ Clean Code 5장: 형식 맞추기 (0) | 2021.01.14 |
✨ Clean Code 3장: 함수 (0) | 2020.12.15 |
✨ Clean Code 2장: 의미 있는 이름 (0) | 2020.11.23 |