[Java] getter/setter 왜 사용 지양해야할까?

2025. 10. 21. 17:13Dev./Java

728x90
반응형

자바 입문하면서 가장 처음 맞이한 난관이다. 이번 과제를 수행해가며 과제 수행 여부에만 집중했다. 구현하라니까 구현하고 이런식으로 그 기준에만 맞추려고 했다. 팀원간에 setter의 적용에 대한 이슈가 나오며 setter를 사용하지 않으셨다는 의견을 들었다. 덧붙여 주신 의견으로 setter를 지양해야한다는 글들을 접하셨다고 하셨다. 나도 그이야기를 들은 후 찾아보니 진짜 지양해야한다는 글이 상당히 많았다. 하지만 찾아봐도 왜 지양해야할까에 대한 궁금증이 해소되지않았다. 왜 지양해야할까? 값에대한 private 필드를 그럼 어떻게 간접적으로 접근하고 저장할까??

getter/setter

  • 객체의 필드(데이터)에 접근하기 위한 간접 통로
  • private 필드에 직접 접근하지 않고, 메서드를 통해 접근하게 만드는 구조

getter

필드의 값을 읽을 때 사용

setter

필드의 값을 할당할 때 사용

public class Account {
    private int balance;

    public int getBalance() { // getter
        return balance;
    }

    public void setBalance(int balance) { // setter
        this.balance = balance;
    }
}

내가 예제로 배운 캡슐화(Encapsulation)를 위해 자바에서 권장되는 기본 패턴이다.

보기에는 private 필드를 간접적으로 접근 했으니 getter/ setter 잘 사용한거같았다.

문제점

1. 직접 접근과 다를 게 없다.

  • 문 잘 잠궈놓고 열쇠 같이 걸어논 식
  • 여기서 직접 접근과 다를게 없다는것은 값을 직접적으로 할당한것이라는 의미이다.
account.setBalance(0); // 외부에서 private 필드 마음대로 변경 가능

2. 애매한 네이밍

메소드 네임에서 메소드의 의도를 알 수가 없다. 잔액을 저장하는건지, 삭제하는건지 내가 작성한 코드가 아니라면 저 코드를 참조해 의도를 직접 읽어야 할 것이다. => 개발 비용 증가

account.setBalance(0); //나 할당 아닌데? 그냥 봐선 모를껄?

해결 방안

1. 기본 구조를 꼭 사용하고 싶다

직접 유효성 검사나 해당 메소드 접근을 적절하게 제어할 수 있는 또 다른 메소드를 추가 구현

2. 행위 중심 메소드로 변경

객체지향은 ‘무엇을 가진다(상태)’가 아니라 ‘무엇을 한다(행위)’를 중심으로 설계한다고 한다. 즉 객체의 본질은 데이터 구조가 아니라 역할과 책임이라는 의미이다. 

결합도(coupling) 가 낮아짐 → 외부는 객체의 내부 상태를 몰라도 됨. 무엇을 하는지만 알면 됨

이전에 올린 OCP 개념과도 이어지는 것이다.

//입금
public void deposit(int amount) {
    if (amount <= 0) throw new IllegalArgumentException("0 이하 입금 불가");
    this.balance += amount;
}
//출금
public void withdraw(int amount) {
    if (amount > this.balance) throw new IllegalStateException("잔액 부족");
    this.balance -= amount;
}
  • 외부는 balance의 값을 조작 하지않고 간접적으로 요청함
  • 행위 중심 메소드로 사용할땐 반드시 기존 set이 포함된 네이밍이 아닌 최대한 직관적으로 의도를 알수있는 네이밍을 써야한다.
  • 이 메소드들은 사실 setter처럼 보이지만 정의로 보면 setter는 아니라고 할 수 있다. 그런 의미에서 setter를 지양하라는 이야기가 나온거 같다고 생각했다.

getter

읽기전용 뷰로 제공해야 의미가 있다. 네이밍도 get보다는 직관적으로 작성해주면 좋다.

기본 자료형

public int getBalance() {
    return balance;
}

기본 자료형( int, double, boolean등) 자체는 immutable(불변)이기 때문에 자체적으로 복사본을 리턴한다

 

컬렉션

public ArrayList<Number> readOnlyResults() {
    return Collections.unmodifiableList(results);
}
public ArrayList<Number> copyResult() {
        return new ArrayList<>(this.results);
    }
  • 읽기전용 뷰 리턴 - 조회만 가능, add, remove등 행위 수행할 수 없음
  • 배열 복사 - 간단하지만 새로 생성하기 때문에 메모리 차지 있음

요약

 

  • private으로 숨긴 필드를 public getter/setter로 다시 열면 결국 다시 외부에 노출
    • 정보 은닉 무의미
  • 객체 내부 상태를 직접 조작할 수 있는 코드는 객체지향 설계에 위배 - 불변성 깨짐
  • 정확한 의도를 가진 행위중심의 메소드를 설계하라는 입장에서 getter/setter를 지양하라는 이야기가 나온거 같다고 생각한다.

 

728x90
반응형