Java 기초부터 마스터까지 — 3화
객체, 캡슐화, 불변 값 설계하기
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
객체는 관련된 상태와 동작을 하나의 경계 안에 묶는다. 필드를 무조건 숨기는 것이 아니라 유효한 상태만 만들 수 있도록 규칙을 클래스에 두는 것이 캡슐화다.
생성자로 유효한 객체 만들기
public final class Player {
private final String name;
private int health;
public Player(String name, int health) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("name is required");
}
this.name = name;
this.health = Math.max(0, health);
}
public void takeDamage(int amount) {
if (amount > 0) {
health = Math.max(0, health - amount);
}
}
public int getHealth() {
return health;
}
}
외부가 health를 직접 바꾸지 못하고 takeDamage라는 규칙을 통해서만 변경한다. 생성자가 끝난 객체는 이름과 체력이 유효하다는 조건을 만족한다.
참조는 같은 객체를 가리킬 수 있다
Player first = new Player("Rose", 100);
Player second = first;
second.takeDamage(20);
System.out.println(first.getHealth()); // 80
second에 객체가 복제된 것이 아니라 같은 Player를 가리키는 참조가 복사되었다. 독립된 복사본이 필요하면 어떤 필드를 복사할지 명시적으로 설계해야 한다.
불변 값 만들기
public final class ItemKey {
private final int id;
private final String grade;
public ItemKey(int id, String grade) {
this.id = id;
this.grade = grade;
}
}
필드를 final로 두고 변경 메서드를 제공하지 않으면 생성 후 상태가 바뀌지 않는다. 다만 필드가 변경 가능한 컬렉션이라면 방어적 복사나 읽기 전용 뷰까지 고려해야 한다.
객체 설계의 핵심은 getter와 setter를 모두 만드는 것이 아니다. 누가 상태를 바꿀 수 있고 어떤 조건이 항상 유지되어야 하는지를 클래스의 공개 메서드로 표현하는 것이다.