티스토리 뷰
어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다. 잘 설계된 컴포넌트는 모든 내부 구현을 완벽하게 숨겨, 구현과 API 를 깔끔하게 분리한다. 이러한 개념은 OOP 의 원칙 중 하나인 캡슐화, 정보 은닉을 지키기 위한 것이다.
그러면 이러한 정보 은닉을 구현함으로써 얻을 수 있는 장점들에 대해서 살펴보자.
- 시스템 개발 속도를 높인다. 여러 컴포넌트를 병렬로 개발할 수 있기 때문이다.
- 시스템 관리 비용을 낮춘다. 각 컴포넌트를 빨리 파악해서 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문이다.
- 정보 은닉 자체가 성능을 높여주지는 않지만, 성능 최적화에 도움을 준다.
- 소프트웨어 재사용성을 높인다. 외부에 거의 의존하지 않고 독자적으로 동작할 수 있는 컴포넌트이기 때문이다.
- 큰 시스템을 제작하는데 있어 난이도를 낮춰준다. 시스템 전체가 완성되지 않은 상태에서도 개별 컴포넌트의 동작을 검증할 수 있기 때문이다.
사실 내가 느끼기에 1번 4번 5번은 같은 의미인 것 같다. 결국 정보 은닉 그 자체로부터 오는 장점이라기 보다는 인터페이스를 분리해서 개발함으로써 재사용성을 높이고 결합도를 낮추는 것에 의의가 있는 것 같다.
자바에서는 캡슐화를 위한 다양한 방법을 제공하지만 이번 포스팅에서는 그 중 접근제어자에 대해서 알아본다.
접근제어자로 캡슐화 구현하기!
핵심은 간단하다! 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다. 약간 최소 권한의 원칙처럼 당연하지만 지키기 어렵고 애매한.. 내용인 것 같다.
그럼 자바에서 제공하는 접근제어자에는 어떠한 것들이 있는지 살펴보자.
- private : 해당 클래스 내부에서만 접근할 수 있다.
- package-private (default) : 동일한 패키지에서만 접근할 수 있다.
- protected : 이 클래스를 상속받은(구현한) 하위 클래스에서 접근할 수 있다.
- public : 모든 곳에서 접근할 수 있다.
기억해야 할 것은 아래로 내려올 수록 더 넓은 접근성을 가지고 당연히 아래의 접근제어자는 위의 것들의 접근범위를 포함한다!! (즉, protected 접근제어자는 package-private 의 접근범위를 포함한다)
우선 클래스 파일의 제일 밖의 클래스에 부여할 수 있는 접근제어자에 대해서 알아보자. 기본적으로 package-private 과 public 두 가지 접근제어자를 사용할 수 있는데 public 을 부여하게되면 공개 API 가 되는 것이고 package-private 은 패키지 내부에서만 접근할 수 있게 되는 것이다.
패키지 외부에서 사용될 일이 없다면 package-private 를 선언하는 것이 좋고 이렇게 함으로써 클래스 수정이 있을 때 클라이언트는 아무런 피해 없이 다음 버전으로 수정, 교체, 제거할 수 있다.
(이후 추가적인 버전개발이 진행 되더라도 하위 호환을 관리하지 않아도 된다)
public 클래스의 인스턴스 필드는 되도록 public 이 아니어야 한다.
꼭 필요한 구성요소가 상수라면 public sataic final 필드로 공개해도 좋다. 하지만 이러한 필드는 반드시 기본 타입 값이나 불변 객체를 참조해야 한다. 그렇지 않을 경우 final 이 아닌 필드와 다를 것이 없다. 참조되는 객체 자체를 수정할 수는 없겠지만 참조하고 있는 객체 자체가 수정될 수 있기 때문이다.
비슷한 맥락으로 길이가 0이 아닌 배열은 모두 변경 가능하니 주의하자.
public static final Thing[] VALUES = { ... };
배열 자체에 어떤 객체들이 할당되어 있는지를 수정할 수 없겠지만 객체 자체를 수정할 수 있기 때문이다. 위와 같은 코드를 사용하기 위해서 아래 두 가지 대안이 있다.
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
'개발 > Effective JAVA' 카테고리의 다른 글
[아이템 18] 상속보다는 컴포지션을 사용하라 (0) | 2021.07.15 |
---|---|
[아이템 17] 변경 가능성을 최소화하라 (0) | 2021.07.13 |
[아이템10~13] 모든 객체의 공통 메서드 재정의 (0) | 2021.06.27 |
[아이템9] try-finally보다는 try-with-resources를 사용하라 (0) | 2021.06.22 |
[아이템7] 다 쓴 객체 참조를 해제하라 (0) | 2021.06.22 |