2025. 10. 21. 17:13ㆍDev./Java
자바 입문하면서 가장 처음 맞이한 난관이다. 이번 과제를 수행해가며 과제 수행 여부에만 집중했다. 구현하라니까 구현하고 이런식으로 그 기준에만 맞추려고 했다. 팀원간에 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를 지양하라는 이야기가 나온거 같다고 생각한다.
'Dev. > Java' 카테고리의 다른 글
| [Java] List, 객체를 value로 활용하기 (객체 중첩) (0) | 2025.10.23 |
|---|---|
| [Java] Map, 객체를 value로 활용하기 (객체 중첩) (0) | 2025.10.22 |
| [Java] OCP(Open/Closed Principle) (0) | 2025.10.20 |
| [Java] Stack(스택) 자료구조 (0) | 2025.10.17 |
| [Java] 캡슐화 (0) | 2025.10.16 |