[Clean Code] 6장 | 객체와 자료구조

PADO·2020년 12월 28일
2

Clean Code

목록 보기
7/15
post-thumbnail

🧷 6장 | 객체와 자료구조

남들이 변수에 의존하지 않도록 변수는 비공개(private)로 정의한다.
그렇다면 어째서 조회(get)함수와 설정(set)함수를 당연하게 공개(public)해 변수를 외부에 노출할까?

객체는 동작을 공개하고 자료를 숨긴다. 그래서 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기 쉬운 반면, 기존 객체에 새 동작을 추가하기는 어렵다.

자료 구조는 별다른 동작 없이 자료를 노출한다. 그래서 기존 자료 구조에 새 동작을 추가하기는 쉬우나, 기존 함수에 새 자료 구조를 추가하기는 어렵다.

📘 자료 추상화

변수 사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지지는 않는다. 구현을 감추려면 추상화가 필요하다!
변수를 private으로 선언하더라도 각 값마다 get함수와 set함수를 제공한다면 구현을 외부로 노출하는 셈이다.
조회 함수와 설정함수로 변수를 다룬다고 클래스가 되지는 않는다.
추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 클래스다.

  • 구체적인 Point 클래스 (구현을 외부로 노출)
public class Point {
  private double x;
  private double y;
}
  • 추상적인 Point 클래스 (구현을 완전히 숨김)
public interface Point {
  double getX();
  double getY();
  void setCatesian(double x, double y);
  double getR();
  double getTheta();
  void setPolar(double r, double theta);
}
  • 구체적인 Vehicle 클래스 (구현을 외부로 노출)
public interface Vehicle {
  double getFuelTankCapacityInGallons();
  double getGallonsOfGasoline();
}
  • 추상적인 Vehicle 클래스 (구현을 완전히 숨김)
public interface Vehicle {
  double getPercentFuelRemaining();
}

자료를 세세하게 공개하기보다는 추상적인 개념으로 표현해야 한다.
인터페이스나 조회/설정 함수만으로는 추상화가 이뤄지지 않는다.

📘 자료/객체 비대칭

  • 객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.
  • 자료 구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.

절차적인 도형 클래스

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 클래스에서 구현한다.
만약 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()는 다형 메서드다. Geometry 클래스는 필요 없다.
새 도형을 추가해도 기존 함수에 아무런 영향을 미치지 않는다!
반면 새 함수를 추가하고 싶다면 도형 클래스를 전부 고쳐야 한다!

자료 구조를 사용하는 절차적인 코드는 기존 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다. 반면, 객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.

절차적인 코드는 새로운 자료 구조를 추가하기 어렵다. 그러려면 모든 함수를 고쳐야 한다.
객체 지향 코드는 새로운 함수를 추가하기 어렵다. 그러려면 모든 클래스를 고쳐야 한다.

객체 지향 코드에서 어려운 변경은 절차적인 코드에서 쉬우며, 반대는 객체 지향 코드에서 쉽다!

📘 디미터 법칙

메소드가 반환하는 객체의 메소드를 사용하면 안 된다.

모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다. 객체는 자료를 숨기고 함수를 공개한다.
→ 객체는 조회 함수로 내부를 공개하면 안 된다는 의미다. 내부구조를 숨기지 않고 노출하는 셈이다.

기차 충돌

여러 객체가 한 줄로 이어진 기차처럼 보인다. 조잡하다.

String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

→ 메소드가 반환하는 객체의 메소드를 사용해서 디미터 법칙 위반
→ 아래 코드로 변환하는 것이 바람직함.

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
String outputDir = scratchDir.getAbsolutePath();

→ ctxt, opts, scratchDir이 객체라면 디미터 법칙 위반
→ ctxt, opts, scratchDir이 자료 구조라면 내부 구조를 노출하므로 디미터 법칙이 적용되지 않음.

final String outputDir = cxtx.opts.scratchDir.absolutePath;

코드를 위와 같이 구현했다면 디미터 법칙을 거론할 필요가 없어진다.
자료구조는 무조건 함수 없이 공개 변수만 포함하고, 객체는 비공개 변수와 공개 함수를 포함한다면 된다.

잡종 구조

절반은 객체, 절반은 자료 구조인 잡종 구조.

  • 공개 변수, 공개 함수, 주요 함수, getter, setter 모두 섞여 있는 구조
  • 클래스, 자료 구조 양쪽에서 단점만 모아 놓은 피해야 할 구조
    → 새로운 함수는 물론, 새로운 자료 구조도 추가하기 어렵다.

구조체 감추기

BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);

디렉토리 경로를 얻는 목적 은 임시 파일 생성을 위함 → ctxt 객체가 최종 목적인 임시 파일을 생성하도록 명령
ctxt 객체는 내부구조를 드러내지 않으며, 함수는 자신이 몰라야 하는 여러 객체를 탐색할 필요가 없다.

📘 자료 전달 객체

자료 구조체의 전형적인 형태는 공개 변수만 있고 함수가 없는 클래스다. 이런 자료 구조를 DTO라 한다.

DTO

공개 변수만 있고 함수가 없는 클래스

Bean

비공개 변수와 getter, setter가 있는 클래스

활성 레코드

공개, 비공개 변수와 getter, setter, 그리고 탐색 함수가 있는 클래스

📘 결론

객체는 동작을 공개하고 자료를 숨긴다.
→ 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉽다.
→ 기존 객체에 새 동작을 추가하기는 어렵다.

자료 구조는 별다른 동작 없이 자료를 노출한다.
→ 기존 자료구조에 새 동작을 추가하기는 쉽다.
→ 기존 함수에 새 자료 구조를 추가하기는 어렵다.

바람직한 구조

  • 객체: 비공개 변수와 공개 함수만 포함
  • 자료 구조: 함수 없이 공개 변수만 포함

적합한 쓰임

  • 객체: 새로운 자료 타입 추가
  • 자료 구조: 새로운 메소드 추가

0개의 댓글