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

📝 전체 내용 간단 요약

  • public 클래스에서 멤버 필드(데이터)를 직접 외부에 노출하지 말고, 접근자(getter)와 변경자(setter) 메서드를 통해 간접적으로 접근하도록 설계해야 합니다.

  • 이렇게 하면 코드의 안정성, 유지보수성, 유연성을 높일 수 있습니다.


📚 미리 알아야 할 내용 요약

📍 접근자(getter), 변경자(setter) 메서드란?

  • 접근자(getter)

    • 클래스의 멤버변수(필드)의 값을 읽을 때 사용하는 메서드입니다.

    public int getAge() {
        return age;
    }
  • 변경자(setter)

    • 클래스의 멤버변수(필드)에 새로운 값을 설정할 때 사용하는 메서드입니다.

    public void setAge(int age) {
        this.age = age;
    }

📌 접근자와 변경자를 쓰는 이유

  • public 필드를 바로 사용하면 코드 변경이 어렵습니다.

  • 접근자와 변경자를 사용하면 코드의 내부 구조(표현 방식)를 바꾸더라도 외부 코드는 수정하지 않아도 됩니다. (캡슐화의 장점)

  • 필드를 직접 공개하면 다음 문제가 생깁니다.

    1. 필드의 유효성(불변식, invariant)을 보장할 수 없습니다.

    2. 표현 방식을 바꾸려면 모든 코드를 수정해야 합니다.

    3. 필드의 값을 읽거나 쓸 때 추가 작업(예: 검증)을 수행할 수 없습니다.


📚 미리 알아야 할 용어

한글 용어
영어 용어
설명

불변식

invariant

객체가 유지해야 하는 항상 변하지 않는 규칙

캡슐화

encapsulation

데이터를 보호하고 접근을 제한하여 내부를 숨기는 것

접근자

accessor(getter)

데이터를 읽을 때 사용하는 메서드

변경자

mutator(setter)

데이터를 변경할 때 사용하는 메서드


🚩 주의사항

  • public 필드는 외부에서 누구나 접근 및 변경 가능하므로 사용하면 위험합니다.

  • 모든 필드를 public이 아닌 private로 두고 필요한 경우에만 getter와 setter를 만드세요.

  • 테스트 때문에 접근 제어 수준을 public으로 높이면 안 됩니다.


⭐ 중요한 점

  • public 클래스가 필드를 공개하면 API 변경이 어려워집니다.

  • 불변 객체라도 public 필드를 사용하는 건 바람직하지 않습니다. 내부 구현 방식이 고정되기 때문입니다.

  • 접근자 메서드를 쓰면 코드가 더 유연해지고 유지보수가 쉬워집니다.


❌ 잘못된 예제

// 나쁜 예: 필드를 모두 public으로 노출
public class Point {
    public double x;
    public double y;
}

// 사용 예시
Point point = new Point();
point.x = 10; // 잘못된 값이 들어가도 검증할 방법이 없음
point.y = -9999; // 문제가 있어도 막을 수 없음
  • 이러한 방식은 절대 쓰지 마세요!


✅ 좋은 예제 (접근자와 변경자 사용한 예시)

public class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        setX(x);
        setY(y);
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        if(x < 0) {
            throw new IllegalArgumentException("x는 음수가 될 수 없습니다.");
        }
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        if(y < 0) {
            throw new IllegalArgumentException("y는 음수일 수 없습니다.");
        }
        this.y = y;
    }
}
  • 외부에서 접근 시 값이 항상 올바른지 확인 가능하며, 값이 잘못 들어가는 걸 막을 수 있습니다.


📌 예외 상황: private 중첩 클래스와 package-private 클래스의 경우

  • 외부에 절대 노출되지 않고 내부에서만 사용하는 클래스라면 필드를 직접 노출해도 괜찮습니다. (범위가 제한적이기 때문)

  • 외부에 공개된 클래스(public 클래스)는 반드시 접근자와 변경자를 사용해야 합니다.


⚠️ 주의사항

  • 클래스 내부 데이터를 변경하지 않는다면, setter는 생략하고 getter만 제공하는 것이 좋습니다. (불변 객체를 권장)

  • public static final 필드도 가변 객체(배열이나 List 등)는 절대 직접 공개하면 안 됩니다. 불변 객체만 공개 가능!

예시:

// 안전한 불변 클래스 예시
public final class Time {
    private final int hour;
    private final int minute;

    public Time(int hour, int minute) {
        this.hour = hour;
        this.minute = minute;
    }

    public int getHour() { return hour; }
    public int getMinute() { return minute; }
}
  • 이처럼 불변 객체는 변경 불가능하므로 안전합니다.


🤔 어려운 점

  • 처음에는 public 필드를 그냥 쓰는 게 쉬웠지만, 접근자와 변경자가 가지는 진정한 장점을 이해하는 게 어려웠습니다.

  • 처음에 getter, setter를 만드는 과정이 불필요한 과정처럼 느껴졌지만, 객체가 복잡해질수록 필드를 보호하는 게 매우 중요하다는 걸 이해했습니다.


🗣️ 느낀 점

  • 처음에는 그냥 편해서 public 필드를 많이 썼는데, 시간이 지날수록 이 방법이 매우 위험하다는 걸 체감했습니다.

  • 특히 여러 사람이 협업하는 큰 프로젝트에서는 데이터가 노출되면 정말 유지보수가 어렵겠다고 느껴졌고, 접근자와 변경자의 중요성을 강력하게 느끼게 되었습니다.

  • 앞으로는 습관적으로라도 무조건 private 필드를 기본으로 설정하고, 필요한 경우에만 접근자를 통해 접근할 수 있게 만들어야겠다고 생각했습니다.


🎯 한 줄로 다시 보는 요약 (Nutshell)

🔑 public 클래스의 필드는 절대 그대로 노출하지 말고 접근자(getter/setter)로 데이터를 보호하고 관리하자!


Last updated