Programming Language/JAVA

Model 클래스에는 Setter가 꼭 필요한가?

Hooligans 2020. 6. 9. 20:07

개요

 

 Model(DTO, VO 등) Object를 사용하면서 private 접근 제한자로 멤버 변수를 선언하고 접근자(getter)와 설정자(setter)를 통해서 객체의 멤버에 접근하는 것이 습관이 되어가던 찰나, "VO 나 DTO를 변경할 필요가 없다면 굳이 setter를 선언할 필요가 있을까?"라는 피드백을 받게 되어 생각해보게 되었습니다.

 

 생각 없이 사용해온 접근자와 설정자를 왜 써야 하는지부터 알아보겠습니다.

 

직접 멤버 변수에 접근하지 않고 왜 번거로운 getter와 setter 메서드를 만들어서 사용하는 거야?

 

 

 java 서적을 보면, '클래스의 멤버 변수는 private 접근 제어자를 사용하고, getter와 setter를 통해 객체의 멤버 변수에 접근해야 한다.'는 말을 많이 접할 수 있습니다.

 

 왜 그래야만 할까요?

 

 이펙티브 자바의 내용에 따르면 멤버 변수를 접근자를 통해 가져오는 이유는 클래스의 내부 구현을 숨기고, 오직 API를 통해서만 다른 클래스와 소통을 하기 위함이라고 명시되어 있습니다. 즉, 객체 지향의 특성 중, 캡슐화를 통한 정보 은닉을 하기 위함입니다.

 

그렇다면 정보를 은닉하면 어떤 장점이 있는지 알아볼까요?

 먼저, 캡슐화된 클래스는 API로만 소통을 하기 때문에 다른 클래스와 결합도가 낮아지게 됩니다. 이로 인해, 여러 개의 클래스들을 병렬적으로 개발할 수 있어 시스템 개발 속도를 높일 수 있습니다.

 

 결합도가 낮다는 의미는 장애가 발생 시에 해당 클래스만 최적화하면 된다는 장점이 있습니다.

 

 또한, 다른 클래스들에 영향을 주지 않고 독립적으로 동작이 가능하기 때문에 다른 응용 프로그램에서도 이를 재사용할 수 있다는 장점이 있습니다.

 

 테스트 환경에서도 쉽게 테스트가 가능합니다.

 

 이렇게 클래스를 만든다면 조금 더 객체지향적인 프로그램을 만들 수 있겠죠?

 

 음.. 이제 접근자를 통해 멤버 변수에 접근하는 이유를 알았는데 setter는 객체의 수정을 위해서라면 필요한 것이 아닐까요?

 

 한 번 생성한 객체를 수정하는 경우가 많지 않은 것은 알지만 필요할 때가 있다면 만들어 두면 문제가 되진 않을 것 같은데 왜 setter는 꼭 필요한 경우에만 구현해야 할까요?

 

 

 지금부터 setter 구현을 최소화하는 이유에 대해 알아보겠습니다.

 

Setter 구현은 왜 최소화해야 할까?

 

 Setter 구현을 최소화하는 이유는 더 나아가 클래스의 변경 가능성을 최소화하기 위함입니다. 그렇다면 클래스의 변경 가능성을 최소화해야 하는 이유는 무엇일까요?

 

 이를 알기 위해서는 불변 클래스(Immutable Class)에 대해서 알아야 합니다.

 

 불변 클래스란 인스턴스의 내부 값을 수정할 수 없는 클래스를 의미합니다. 즉, 처음 생성된 인스턴스의 값이 절대 변하지 않습니다.

 

 결국 클래스의 변경 가능성을 최소화한다는 것은 불변 클래스를 사용해야 한다는 것을 의미합니다. 그렇다면 불변 클래스는 어떤 장점이 있기에 사용할까요?

 

불변 클래스(Immutable Class)는 왜 사용할까?

 

 불변 클래스는 우선 인스턴스의 값이 변하지 않기 때문에 가변 객체와 달리 상태 변화에 대해서 신경 쓰지 않아도 됩니다. 그러므로 객체의 동작을 예측하기 쉽고, 오류 발생 가능성도 최소화할 수 있습니다. 가변 객체의 경우, setter가 어떤 변화를 가져오는지 문서화하지 않으면 신뢰할 수 없습니다.

 

 이와 더불어 객체의 값을 어떠한 스레드도 변경하지 못하기 때문에 멀티 스레드 환경에서도 사용이 용이합니다. 즉, Thread-Safe 합니다. 그러므로 별도의 동기화 처리 없이 객체를 여러 스레드에서 공유할 수 있습니다.

 

 물론 불변 클래스를 사용하면 객체를 수정하기 위해서는 변경된 값을 지닌 새로운 인스턴스를 만들어야 하기 때문에 메모리 부족과 성능 저하와 같은 단점도 존재합니다.

 

 하지만, 위의 장점들이 단점을 상쇄시킬 만큼 강력하기 때문에 불변 클래스를 사용해야 합니다.

 

 이러한 불변 클래스는 어떻게 만들어야 할까요?

 

그래서 불변 클래스는 어떻게 만드나요?

 

불변 클래스를 만들기 위해서는 설정자(setter) 메서드를 구현하지 않습니다.

 

 또한 하위 클래스에서 부주의하게 객체의 상태를 변하게 만드는 사태를 막기 위해서 클래스를 확장할 수 없도록 해야 합니다. 클래스 자체를 final로 선언하면 되지만, 아래 그림과 같이 모든 생성자를 private으로 선언하고, 오로지 정적 팩토리 메서드로만 인스턴스를 생성할 수 있게 하도록 하면 상속이 불가능해집니다.

 

public class User {

  private final int id;
  
  private final String name;
  
  private final int age;
  
  private User(int id, String name, int age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }
  
  public static User valueOf(int id, String name, int age) {
  	return new User(id, name, age);
  }
}

 

 마지막으로 모든 필드는 private과 final로 선언해야만 합니다. 필드가 참조하는 가변 객체를 클라이언트에서 직접 접근해서 수정하는 일을 막기 위함입니다.

 

정리해보기

1. getter와 setter를 사용하는 이유는 캡슐화를 통해 정보를 은닉함으로써 객체지향적인 프로그램을 작성하기 위함입니다.

 

2. setter를 최소화해야 하는 이유는 불변 클래스를 사용함으로써 그 장점을 활용하여 사용하기 쉽고 안전한 클래스를 만들기 위함이었습니다.

 

참고

  • 이펙티브 자바 3판, Josha Bloch 지음, 인사이트 출판사, 2018년 11월 1일 초판 발행