[Programming] - CleanCode 06. 객체와 자료구조


자료 추상화


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);
}

point 클래스는 구현을 드러냈고

point 인터페이스는 추상화를 통해 구현을 완전히 숨겼다.

아무리 변수를 private로 선언한다고 해도 getter, setter를 제공하면 구현을 외부로 노출하는 셈이다.

구현을 감추려면 추상화가 필요하다.

public interface Vehicle {
	double getFuelTankCapacityInGallons();
	double getGallonsOfGasoline();
}
public interface Vehicle {
	double getPercentFuelRemaining();
}

위 2개도 첫번째는 전체 연료양과 현재 연료량을 그저 읽어 오는 함수뿐이다.

하지만 아래 인터페이스는 그것을 연산한 %를 반환한다. 해당 함수의 정보가 어디서 오는지 전혀 드러나지 않는다.

자료/객체 비대칭


위 2개 예저는 자료구조와 객체의 차이를 보여준다.

객체추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.

자료구조는 자료를 그대로 공개하며 별다른 함수를 제공하지 않는다.

public class Square {
	public Point topLeft;
	public double side;
}
public class Circle {
	public Point center;
	public double radius;
}

public class Geometry {

	public double area(Object shape) throws NoSuchShapeExceptiop
	{
		if(shape instanceof Square) {
			Sqare s = (Sqaure)shape;
			return s.side * s.side;
		} else if (shape instanceof Circle) {
			Circle c = (Circle)shape;
			return PI * c.radius * c.radius;
		}
}

public class Square implements Shape {
	private Point topLeft;
	private double side;
	
	public double area() {
		return side * side;
	}
}

public class Circle implements Shape {
	private Point center;
	private double radius;
	private final double PI = 3.141592653589793;
	
	public double area() {
		return PI * radius * radius;
	}
}

위 2개의 자료구조와 클래스 구조를 비교해보아라.

자료구조 타입으로 작성한 절차지향 코드는 새로운 도형이 추가될때 기존 함수를 다 수정해야한다.

반면, 클래스로 만든 객체지향 코드는 새로운 도형이 추가 될때 class만 새로 만들어주면 된다.

반대로, 자료구조 타입으로 작성한 절차지향 코드는 새로운 함수가 추가 될때 관리하는 클래스에서 새로운 함수를 추가해주면 된다. 반면, 클래스로 만든 객체지향 코드는 새로운 함수가 추가되면 모든 class를 수정해야 한다.

다시 말해, 객체 지향 코드에서 어려운 변경은 절차지향에서 쉽고 또 그 반대이다.

모든 것을 객체로 짜야한다는 것은 미신이다. 상황에 따라 단순한 자료구조와 절차적인 코드가 적합할 때가 있다.

디미터의 법칙


디미터 법칙은 “모듈은 자신의 조작하는 객체의 속사정을 몰라야 한다”는 법칙이다.

클래스 C의 메서르 f는 다음과 같은 객체의 메서드만 호출해야한다.

  • 클래스 C
  • f가 생성한 객체
  • f 인수로 들어온 객체
  • C 인스턴스 변수에 저장된 객체
//어기는 예시, 이런 코드를 기차 충돌이라고 표현한다.
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

만약 위 코드가 ctxt, Options, ScratchDir이 자료구조라면 괜찮다.

객체라면 내부 구조를 숨겨야 하고 (메서드로 표현)

자료구조라면 내부 구조를 노출한다. (대신 메서드 없음)

잡종 구조


때로는 절반은 객체, 절반은 자료구조 같은 잡종 구조가 만들어진다.

그러다보면 절차적인 프로그래밍의 자료 구조 접근 방식처럼 비공개 변수를 사용하고 싶은 유혹에 빠진다.

이런 잡종 구조는 새로운 함수는 물론이고 새로운 자료 구조도 추가하기 어렵다.

결론


객체는 동작을 공개하고 자료를 숨긴다.

  • 새로운 자료구조를 추가하기 쉽다
  • 새로운 함수 추가가 어렵다 (모든 객체 수정해야함)

자료구조는 별다른 동작 없이 자료를 노출한다.

  • 새로운 함수 추가가 쉽다
  • 새로운 자료구조를 추가하기 어렵다 (함수들에 자료구조 처리 다 수정해야함)