it 서적 독후감/이팩티브 자바

[ITEM 16] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

데일리코딩 2025. 3. 11. 23:27

간혹 단순히 여러 값을 담은 인스턴스가 필요한 객체를 생성할 때 이렇게 작성하는 경우가 있다.

public class PointV1 {

    public double x;
    public double y;
}

 

나의 경우에는 코딩테스트 코드 작성할때 getter, setter 메서드로 호출하는것이 너무 귀찮아서 이렇게 한적은 있지만

실제로 어플리케이션 개발 때는 절대 사용하지 않는 클래스 설계다..

 

이 코드의 문제점은 다음과 같다

  1. 생성자를 통해 값을 셋팅하지 않아 필수값을 누락할 수 있다
  2. 생성자를 통해 값을 셋팅하지 않아 x,y의 불변식이 무너질 수 있다.
  3. 외부 공개 클래스인데 내부 상태를 완전히 노출되어 언제 객체가 이상하게 작동해도 이상할 점이 없다
  4. 캡슐화의 이점을 얻을 수 없다. (객체의 자율성을 보장하지 못한다)
  5. 불변하지도 않아 스레드 세이프하지 않아 여러 스레드가 접근 시 반드시 문제가 되는 클래스다.

철저한 객체지향 프로그래머의 설계

package effctive_java.item_16;

public class PointV2 {

    private int x;
    private int y;

    public PointV2(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

 

접근자와 변경자 메서드를 활용해 데이터를 캡슐화 했다.

public 클래스라면 이 방식이 확실히 맞다고 판단한다

 

하지만 객체가 더 다양한 기능을 하고 다른 객체와 협력 해야하는 클래스라면

해당 클래스가 가지고 있는 상태 값에 대해서는 private 접근 제어자를 설정하여 내부 데이터에 대한 완전한 캡슐을 하고

public 메서드를 통해서 다른 객체와 협력하는 방식으로 설계를 할것이다. 

 

package effctive_java.item_16;

public class PointV3 {
    
    private final int x;
    private final int y;

    public PointV3(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public PointV3 getCurrentPosition() {
        return this;
    }
    
    public String getPositionMessage() {
        StringBuilder sb = new StringBuilder();
        return sb.append(x).append(", ").append(y).toString();
    }

    private int getX() {
        return x;
    }
    private int getY() {
        return y;
    }
}

 

내가 작성한 위 코드는 위 문제들을 해결했다

  1. 생성자에서 필수로 x, y 좌표를 받아 x, y 둘중 하나라도 없는 이상한 인스턴스가 생성되는것을 방지한다 (불변식)
  2. final 키워드를 넣어줘서 불변으로 병렬프로그램에서 안심하고 사용할 수 있다.
  3. 현재 코드예제가 너무 단순해서 억지처럼 보이지만 내부 데이터를 캡슐화 하여 접근하지 못하게 막고 (자율성을 높이고)
    public 메서드인 getCurrentPosition() 를 통해 다른 객체와 협력을 할 수 있게 설계했다.

처음 Version1 인 PointV1 클래스가 가진 모든 문제를 해결했다.

아마 보통 데이터 위주 설계라면 V2를 많이 사용하겠지만 객체 위주로 설계를 한다면 V3 으로 객체간의 협력적인 코드를 작성할 것 같다.