객체와 자료 구조

변수를 private으로 선언하는 이유는 남들이 변수에 의존하지 않게 만들고 싶어서다.
변수 타입, 구현을 맘대로 바꾸고 싶어서다.

자료 추상화

두 코드를 비교해보자
한 클래스는 구현을 외부로 노출하고 다른 클래스는 구현을 완전히 숨긴다.

//1번 - 구체적인 Point Class
public class Point{
    public double x;
    public double y;
}

//2번 - 추상적인 Point Class
public interface Point{
    double getX();
    double getY();
    void setCartesian(double x, double y);
    double getR();
    double getTheta();
    boid setPolar(double r, double theta);
}

2번은 직교좌표계인지 극좌표계인지 모른다.
자료 구조 이상을 표현한다. 클래스 메서드가 접근 정책을 강제한다.
1번은 직교좌표계를 사용한다. 개별적으로 값을 읽고 설정하게 강제한다.
구현을 노출한다. -> 변수를 private으로 하더라도 get/set이 노출된다면 구현이 외부로 노출되는 셈이다.

//3번
public interface Vehicle{
    double getFuelTankCapacityInGallons();
    double getGallonsOfGasoline();
}

//4번
public interface Vehicle{
    double getPercentFuelRemaining();
}

3번가 4번 사이에서는 4번이 더 좋다.
자료를 세세하게 공개하기보다는 추상적인 개념으로 표현하는 편이 좋다.

자료/객체 비대칭

앞서 소개한 두 예제는 객체와 자료구조의 차이를 보여준다.
객체는 추상화 뒤로 자료를 숨긴채 자료를 다루는 함수만 공개한다.
자료구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.

//절차적인 코드
public class Rectangle{
    public Point topLeft;
    public double height;
    public double width;
}

public class Circle{
    public Point center;
    public double radius;
}

public class Geometry{
    public double area(Object shape) throws NoSuchShapeException{
        if (shape instanceof Rectangle){
            Rectangle r = (Rectangle)shape;
            return r.height * r.width;
        }else if(shape instanceof Circle){
            Circle c = (Circle)shape;
            return 3.14 * c.radius * c.radius;
        }else{
            throw new NoSuchShapeException();
        }
    }
}

//객체 지향 코드
public class Rectangle implements Shape{
    private Point topLeft;
    private double height;
    private double width;
    public double area(){
        return height*width;
    }
}

public class Circle implements Shape{
    private Point center;
    private double radius;

    public double area(){
        return 3.14 * radius * radius;
    }
}

객체 지향 vs 절차적인 코드

  • 객체 지향 코드에서는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.

  • 절차적인 코드에서는 기존 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다.

  • 객체 지향 코드에서는 새로운 함수를 추가하기 어렵다. 그러려면 모든 클래스를 고쳐야 한다.

  • 절차적인 코드에서는 새로운 자료 구조를 추가하기 어렵다. 그러려면 모든 함수를 고쳐야 한다.

개발을 하다보면 새로운 함수가 아니라 자료 타입이 필요한 경우가 필요하다 -> 객체 지향
새로운 자료 타입이 아닌 새로운 함수가 필요하다 -> 절차적인 코드 + 자료구조

디미터 법칙

디미터 법칙은 휴리스틱으로 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙이다.
객체는 자료를 숨기고 함수를 제공한다. 객체는 조회 함수로 내부 구조를 공개하면 안된다는 의미다.

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

  1. 클래스 C
  2. f가 생성한 객체
  3. f 인수로 넘어온 객체
  4. C 인스턴스 변수(프로퍼티)에 저장된 객체

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

기차 충돌

위와 같은 코드를 기차 충돌이라 부른다.
위 코드는 나누는 편이 좋다.

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final Strin goutputDir = scratchDir.getAbsolutePath();

자료 전달 객체

자료 구조체의 전형적인 형태는 공개 변수만 있고 함수가 없는 클래스다.
때로는 DTO라 일컫는다.
특히 DB와 통신 or 소켓으로 받은 Msg를 분석할 때 유용하다.

-> DTO는 자료구조이므로 함수를 제공하지 않는다.

결론

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

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

+ Recent posts