[Clean Code] 6장 객체와 자료구조
6장 객체와 자료구조
다른 개발자가 변수에 의존하지 않도록 변수는 비공개( private )로 정의한다.
그렇다면 왜 조회( get )함수와 설정( set )함수를 당연하게 공개( public )해 변수를 외부에 노출할까?
객체는 동작을 공개하고 자료는 숨긴다.
그래서 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기 쉬운 반면에 기존 객체에 새 동작을 추가하기는 어렵다.
자료구조는 별다른 동작 없이 자료를 노출한다.
그래서 기존 자료 구조에 새로운 동작을 추가하기는 쉽지만 기존 함수에 새 자료 구조를 추가하기는 어렵다.
목차
- 자료 추상화
- 자료/객체 비대칭
- 디미터 법칙
- 기차 충돌
- 잡종 구조
- 구조체 감추기
- 자료 전달 객체
- 활성 레코드
- 결론
6-1. 자료 추상화
변수 사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지지 않는다.
구현을 감추려면 추상화가 필요하다.
변수를 private으로 선언하더라도 각 값마다 조회 함수와 설정 함수를 제공한다면 구현을 외부로 노출하는 셈이다.
조회 함수와 설정 함수로 변수를 다룬다고 클래스가 되지는 않는다.
추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 클래스다.
구현을 외부로 노출하는 경우 ( 구체적인 클래스 )
public class Point{
private double x;
private double y;
}
구현을 완전히 숨기는 경우 ( 추상적인 클래스 )
public interface Point {
double getX();
double getY();
void setCatesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
구현을 외부로 노출하는 경우 ( 구체적인 함수 )
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
구현을 완전히 숨기는 경우 ( 추상적인 함수 )
public interface Vehicle {
double getPercentFuelRemaining();
}
자료를 세세하게 공개하기보다는 추상적인 개념으로 표현해야 한다.
인터페이스와 조회 함수, 설정 함수만으로 추상화가 이뤄지지 않는다.
6-2. 자료/객체 비대칭
객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.
자료 구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.
절차적인 도형 클래스 ( 자료 구조형 )
public class Square {
public Point topLeft;
public double side;
}
public class Rectangle {
public Point topLeft;
public double height;
public double width;
}
public class Circle {
public Point center;
public double radius;
public double width;
}
public class Geometry {
public final double PI = 3.141592653585793;
public double area(Object shape) throws NoSuchShapeException {
if(shape instanceOf Square) {
Square s = (Square)shape;
return s.side * s.side;
}
else if(shape instanceOf Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
}
else if(shape instanceOf Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius
}
}
}
Geometry 클래스는 세 가지 도형 클래스를 다룬다.
절차적인 도형 클래스를 아무 메서드를 제공하지 않고, 자료 구조로 변환한 결과이다.
새 도형을 추가하고 싶다면 Geometry 클래스에 속함 함수를 모두 고쳐야한다.
자료 구조를 사용하는 절차적인 코드는 기존 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다.
절차지향 코드는 새로운 자료 구조를 추가하기 어렵고 추가하려면 모든 함수를 고쳐야 한다.
객체 지향적인 도형 클래스
public class Square implements Shape {
public Point topLeft;
public double side;
public double area() {
return side*side;
}
}
public class Rectangle implements Shape {
public Point topLeft;
public double height;
public double width;
public double area() {
return height*width;
}
}
public class Circle implements Shape {
public Point center;
public double radius;
public double width;
public double area() {
return PI*radius*radius;
}
}
area()는 다형 메서드라고 부른다.
새 도형을 추가해도 기존 함수에 아무런 영향을 미치지 않는다.
반면에 새 함수를 추가하고 싶다면 도형 클래스를 전부 고쳐야한다.
객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽고 새로운 함수를 추가하기 어렵다.
추가하려면 모든 클래스를 수정해야 한다.
6-3. 디미터 법칙
메소드가 반환하는 객체의 메소드를 사용하면 안되는 법칙.
모듈은 자신이 조작하는 객체의 속성을 몰라야 한다.
객체는 자료를 숨기고 함수는 공개한다.
즉, 객체는 조회 함수로 내부를 공개하면 안 된다는 의미이다.
내부구조를 숨기지 않고 노출하는 셈이다.
6-3-1. 기차 충돌
String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
여러 객체가 한 줄로 이어진 기차처럼 보인다.
조잡하다.
메소드가 반환하는 객체의 메소드를 사용하므로 디미터 법칙 위반이다.
JQuery에서의 메소드 체이닝은 자료구조만 반환하기 때문에 가능한 이유다.
아래 코드로 변환하는 것이 바람직한 객체지향 표현이다.
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
String outputDir = scratchDir.getAbsolutePath();
ctxt, opts, scratchDir이 객체라면 디미터 법칙을 위반한다.
하지만 자료 구조라면 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.
final String outputDir = cxtx.opts.scratchDir.absolutePath;
코드를 위와 같이 구현했다면 디미터 법칙을 거론할 필요가 없이 자료 구조는 무조건 함수 없이 공개 변수만 포함하고 객체는 비공개 변수와 공개 함수를 포함한다면 된다.
6-3-2. 잡종 구조
절반은 객체이며 절반은 자료 구조인 잡종 구조가 존재한다.
공개 변수, 공개 함수, 주요 함수, getter와 setter가 모두 섞여 있는 구조
클래스, 자료 구조 양쪽에서 단점만 모아 놓은 프로그래머가 피해야 할 구조
( 새로운 함수와 새로운 자료 구조도 추가하기 어렵다 )
6-3-3. 구조체 감추기
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
폴더 경로를 얻는 목적이 임시 파일 생성을 위함이라면 ctxt 객체가 최종 목적인 임시 파일을 생성하도록 지시한다.
결과적으로 ctxt 객체는 내부구조를 드러내지 않으며 함수는 자신이 몰라야 하는 여러 객체를 탐색할 필요가 없다.
6-4. 자료 전달 객체
자료 구조체의 전형적인 형태는 공개 변수만 존재하고 함수는 없는 클래스이다.
이런 자료 구조를 DTO라고 한다.
결론
객체는 동작을 공개하고 자료는 숨긴다.
- 기존 동작을 변경하지 않으면서 새로운 객체 타입을 추가하기 쉽다.
- 기존 객체에 새로운 동작을 추가하기 어렵다.
자료 구조는 별다른 동작 없이 자료를 노출한다.
- 기존 자료구조에 새로운 동작을 추가하기 쉽다.
- 기존 함수에 새로운 자료 구조를 추가하기 어렵다.
이상적인 구조
객체 : 비공개 변수와 공개 함수만 포함한다.
자료 구조 : 함수 없이 공개 변수만 포함한다.
적합한 쓰임새
객체 : 새로운 자료 타입의 추가
자료 구조 : 새로운 메서드 추가