Item 17 : 변경 가능성을 최소화 하라
2021. 7. 16. 10:03
불변 클래스에 대한 설명이다.
일단 먼저 클래스를 불변으로 만들기 위한 규칙은 다음과 같다.
- 객체의 상태를 변경하는 메소드(변경자)를 제공하지 않는다.
- 클래스를 확장할 수 없도록 한다.
- 하위 클래스에서 부주의하게 혹은 나쁜 의도로 객체의 상태를 변하게 만드는 사태를 막아준다.
- 상속을 막는 대표적인 방법은 클래스를 final로 선언하는 것이지만, 다른 방법도 있다.
- 모든 필드를 final로 선언한다.
- 시스템이 강제하는 수단을 이용해 설계자의 의도를 명확히 드러내는 방법
- 새로 생성된 인스턴스를 동기화 없이 다른 스레드로 건네도 문제없이 동작하게끔 보장하는데도 필요
- 모든 필드를 private으로 선언
- 필드가 참조하는 가변 객체를 클라이언트에서 직접 접근해 수정하는 일을 막아줌
- 기술적으로는 기본 타입 필드나 불변 객체를 참조하는 필드를 public final로만 선언해도 불변객체가 되지만, 이렇게 하면 다음 릴리즈에서 내부 표현을 바꾸지 못하므로 권하지는 않는다.
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
- 클래스에 가변 객체를 참조하는 필드가 하나라도 있다면 클라이언트에서 그 객체의 참조를 얻을 수 없도록 해야 한다.생성자, 접근자, readObject 메소드 모두에서 방어적 복사를 수행하라.
- 이런 필드는 절대 클라이언트가 제공한 객체 참조를 가리키게 해서는 안 되며, 접근자 메소드가 그 필드를 그대로 반환해서도 안된다.
책에서의 예시이다.
public final class Complex{
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
public double realPart() {return re;}
public double imaginaryPart() {return im;}
public Complex plus(Complex c) {
return new Complex(re + c.re, im + c.im);
}
public Complex minus(Complex c) {
return new Complex(re - c.re, im - c.im);
}
public Complex times(Complex c) {
return new Complex(re * c.re - im * c.im, re * c.im + im. * c.re);
}
public Complex dividedBy(Complex c){
double tmp = c.re * c.re + c.im * c.im;
return new Complex((re * c.re + im * c.im) /tmp,
re * c.im + im * c.re);
}
@Override public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Complex))
return false;
Complex c = (Complex) o;
return Double.compare(c.re, re) == 0
&& Double.compare(c.im, im);
}
@Override
public int hashCode() {
return 31 * Double.hashCode(realNumber) + Double.hashCode(imaginaryNumber);
}
@Override
public String toString() {
return "(" + realNumber + " + " + imaginaryNumber + "i)";
}
}
복소수를 표현한 클래스다. 함수형 프로그래밍의 모습과 비슷한데
사용자가 Complex의 변수에 접근해서 사용하는 것이 아닌 사칙연산 메소드를 제공하여
이용하게끔 만들어 놓은 클래스이다.
그럼 이렇게 불변으로 클래스를 만들면 장점이 무엇일까?
- 불변 객체는 단순하다.
- 불확실한 변수를 줄여준다.
- 불변 객체는 근본적으로 스레드 안전하여 따로 동기화 할 필요 없다.
- 여러 스레드가 동시에 사용해도 훼손되지 않는다.
- 불변 객체는 안심하고 공유할 수 있다.
- 불변 객체는 자유롭게 공유할 수 있음은 물론, 불변객체끼리는 내부 데이터를 공유할 수 있다.
- 불변 객체는 그 자체로 실패 원자성을 제공한다.
단점
- 값이 다르면 반드시 독립된 객체로 만들어야 한다 -> 비용이 커진다.
인프런 수업중에서도 강사님이 자주 언급하시는 부분이 있다
바로 Getter는 만들지언정 Setter는 함부로 만들지 말라고 하신다.
이 처럼 컴포넌트에 접근 할 수 있는 요소를 최소화 하고 접근 할 수 있는 부분을 정해놔야
나중에 데이터가 변경되어도 어떤 부분에서 변경되었는지 추적할 수 있기 때문이다.
'책 > 이펙티브자바' 카테고리의 다른 글
Item 19 : 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2021.07.18 |
---|---|
Item 18 : 상속보다는 컴포지션을 사용하라 (0) | 2021.07.18 |
Item 16 : public 클래스에서는 public 필드가 아닌 접근자 메소드를 사용하라 (0) | 2021.07.15 |
Item 15 : 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2021.07.14 |
Item 14 : Comparable을 구현할지 고려하라 (0) | 2021.07.13 |