Skip to content

Latest commit

 

History

History
83 lines (63 loc) · 2.63 KB

16.public 클래스의 필드를 외부로 직접 노출하지 마라.md

File metadata and controls

83 lines (63 loc) · 2.63 KB

public 클래스의 필드를 외부로 직접 노출하지 마라

아래와 같이 인스턴스 필드를 모아 놓기만 하는 퇴보한 클래스를 작성하지 마라

public class UsedCar {
    public int mileage;
    public int price;
}

이런 클래스는

  • 데이터 필드에 직접 접근할 수 있으므로, 캡슐화의 이점이 없다
  • API 수정 없이 내부 표현을 바꿀 수 없다
  • 외부에서 필드에 접근할 때, 부수 작업을 수행할 수 없다
  • 불변식을 보장할 수 없다

만약 public 클래스의 필드를 아래와 같이 불변으로 만든다면, 불변식을 보장할 수는 있게 된다
하지만 나머지 단점은 여전히 존재한다

public final class UsedCar {
    private static final int MILEAGE_MINIMUM = 0;
    private static final int PRICE_MINIMUM = 0;
    
    public final int mileage;
    public final int price;
    
    public UsedCar(int mileage, int price) {
        if (mileage < MILEAGE_MINIMUM || price < PRICE_MINIMUM) {
            throw new IllegalArgumentException("주행 거리와 가격은 0보다 커야 합니다.");
        }
        this.mileage = mileage;
        this.price = price;
    }
}

책에서는 이 대신 getter와 setter를 사용하는 것이 객체지향적이라는 말이 나온다
하지만 위의 좋지 않은 사례에 상대적으로 그렇다는 것이고, 이미 둘을 지양해야 할 이유를 미션 내에서 모두 체득하고 있다고 생각하기에,
getter와 setter를 넣은 코드는 생략하겠다


별개로 pakage-private 클래스, 혹은 private 중첩 클래스라면, 데이터 필드를 노출해도 괜찮다
pakage-private의 경우에는 패키지 내부에서만 사용되기에, 외부의 수정 없이 데이터 표현 방식을 바꿀 수 있기 때문이다
private 중첩 클래스는 범위가 더욱 좁아서, 외부 클래스까지만 수정 범위가 제한된다

public class UsedCar {
    private int mileage;
    private int price;
    private Fuel fuel;
    
    public UsedCar(int mileage, int price) {
        this.mileage = mileage;
        this.price = price;
        this.fuel = new Fuel();
    }
    
    private void chargeFuel() {
        fuel.amount = 100;
    }
    
    private class Fuel {
        public int amount;
        public Fuel() {
            this.amount = 0;
        }
    }
}

참고한 글들

https://taxol1203.github.io/effective%20java/EJ-Item16/