1. 자료 추상화
public class Point {
public double x;
public doulbe y;
}
public interface Point {
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
두 클래스를 비교해보자
2차원 점을 표현하는 클래스인데
위 클래스의 경우 외부로 모두 노출되지만,
아래 클래스의 경우 구현을 완전히 숨긴 형태이다
또한 접근 시 좌표값을 읽을 때 위 클래스의 경우 각각 개별적으로 읽게 되지만
아래 클래스의 경우 두 값을 동시에 설정해야한다
구현을 감추기 위해서는 추상화가 필요하다
다음 예제를 보면 추상화에 대해 조금 더 감이 온다
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
public interface Vehicle {
double getPercentFuelRemaining();
}
같은 interface 객체이지만 첫번째 코드는 필요한 연료의 값만 그대로 알려주는 형태이지만
두번째 코드의 경우 백분율로 계산한 추상적인 개념으로 알려준다
이처럼 세세한 자료(값)를 공개하기보다는 추상적인 개념으로 표현하는 방법을 고민해야한다
무분별한 get, set 함수가 가장 안좋다
2. 자료/객체 비대칭
자료구조는 자료(값)를 그대로 공개하며 별다른 함수를 제공하지 않는다
객체는 추상화 뒤로 자료(값)를 숨긴 채 다루는 함수만 공개한다
절차적인 자료구조로 도형 클래스를 구현할 경우 아래 코드와 같이 구현할 수 있다
public class Square {
public Point topLeft;
public double side;
}
public class Circle {
public Point center;
public double radius;
}
public class Geometry {
public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException {
if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * s.side;
}
else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throws new NoSuchShapeException();
}
}
이 코드를 객체 지향 형태로 구현할 경우 아래 코드와 같이 구현할 수 있다
public class Square implements Shape {
private Point topLeft;
private double side;
public double area() {
return side * side;
}
}
public class Circle implements Shape {
private final double PI = 3.141592653589793;
private Point center;
private double radius;
public double area() {
return PI * c.radius * c.radius;
}
}
상속과 추상화를 통해 객체로 구현할 수 있다
자료구조와 객체 지향 코드는 근본적으로 양분된다
(자료 구조를 사용하는) 절차적인 코드는 기존 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다.
반면, 객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.
절차적인 코드는 새로운 자료 구조를 추가하기 어렵다.
그러려면 모든 함수를 고쳐야 한다.
객체 지향 코드는 새로운 함수를 추가하기 어렵다.
그러려면 모든 클래스를 고쳐야 한다.
즉, 객체 지향 코드에서 어려운 변경은 절차적인 코드에서 쉬우며,
절차적인 코드에서 어려운 변경은 객체 지향 코드에서 쉽다
java의 경우 객체 지향 코드를 지향하지만
때로는 단순한 자료 구조와 절차적인 코드가 가장 적합한 상황도 있다
3. 디미터 법칙
디미터의 법칙: 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙
앞에서 계속 설명했듯이 객체는 자료를 숨기고 함수를 공개해야 한다
즉, 조회 함수(get)로 내부 구조를 공개하면 안된다는 의미
파일 생성을 위해 파일명과 디렉토리 정보를 받아오는 코드가 있다고 가정할 때
ctxt.getOptions().getScratchDir().getAbsolutePath();
위와 같은 코드를 기차 충돌(train wreck)라 부른다
(이어진 기차처럼 보여서)
내부 구조가 확연히 드러나므로 디미터 법칙을 위반한다
ctxt.createScratchFileStream(classFileName);
파일을 생성하는 것이 목적이라면, 해당 객체에게 책임을 위임하면 된다
내부 구조를 드러내지 않으며 해당 함수가 자신이 몰라야하는 여러 객체를 탐색할 필요도 없다
4. 자료 전달 객체
만약 가공되지 않은 자료(값) 정보를 전달해야 한다면 DTO를 사용하자
마무리 느낀 점
클린코드 내용 중 가장 중요한 부분 중 하나가 아니었을까 싶다
추상화와 디미터의 법칙만 잘 지켜도 코드 작성 시 생각보다 훨씬 많은 변화가 생기는 것 같다
단순히 추상화 = interface class를 선언하고 상속받는 정도라고 생각하고 있었는데
메서드를 정의하는 부분에 있어서도 추상화 개념이 필요하다는 내용이 가장 인상깊었다
다음부터 조금 더 신경써서 메서드를 정의해야겠다
'개발 서적 > 클린코드' 카테고리의 다른 글
클린코드 - 8.경계 (0) | 2022.07.06 |
---|---|
클린코드 - 7.오류 처리 (0) | 2022.07.05 |
클린코드 - 5.형식 맞추기 (0) | 2022.06.04 |
클린코드 - 4.주석 (0) | 2022.06.04 |
클린코드 - 3.함수 (0) | 2022.02.27 |