안녕하세요 돼지왕 왕돼지입니다.
오늘은 "클래스와 그 멤버의 접근성을 최소화하자." 라는 주제로 이야기하고자 합니다.
이 글은 "Effective Java" 의 내용을 정리한 것입니다.
잘 설계된 모듈과 그렇지 않은 모듈
잘 설계된 모듈과 그렇지 않은 모듈을 구분 짓는 가장 중요한 잣대는, 모듈 자신의 내부 데이터 및 그 외의 상세한 구현부분을 다른 모듈로부터 얼마나 숨기느냐에 달려 있습니다. 즉 정보 은닉 ( information hiding ) 과 캡슐화 ( encapsulation ) 이 얼마나 잘 지켜졌냐는 것이죠.
모듈화를 잘 하면 뭐가 좋은데?
- 개발, 테스트, 최적화, 사용 및 수정이 편리합니다.
- 개발부분에서는 모듈이 나뉘어져 있으면 병행 개발이 가능해져 개발이 매우 빨라집니다. 모듈들을 관리하는 모듈을 만드는 입장에서는 모듈을 더 빨리 파악하기 쉽습니다. 모듈로 나뉘어져있으면, 다른 모듈을 수정하지 않고 해당 모듈만 수정할 수 있기 때문에 유지보수 측면에서 매우 좋습니다.
- 모듈화는 큰 시스템 개발시의 위험 부담도 줄여 줍니다. 시스템 전체가 덜 되어도, 모듈 별 성공 여부를 입증할 수 있기 때문이죠.
모듈화를 잘 한다는 것은 뭘 잘한다는 것인가요?
- 접근 제어를 통한 정보 은닉을 잘 하는 것이 모듈화를 잘 하는 것으로 볼 수 있습니다. 자바에서는 private, protected, public, package 전용의 접근 변경자 ( access modifier ) 를 제공합니다. 각 클래스나 멤버의 접근 허용을 최소화 하는 것이 중요하죠. 즉 public access 를 최소화 하는 것이 가장 중요합니다.
- 패키지 전용의 최상위 클래스나 인터페이스가 단 하나의 클래스에서만 사용된다면, 사용하는 클래스의 private 중첩 클래스로 만드는 것을 고려해 볼 만 합니다. 하지만 더 중요한 것은 가능한한 public 을 줄이는 것이죠.
접근 제어자들을 알려주세요.
- private : 멤버가 선언된 최상위 클래스 내에서만 접근 가능하다.
- 패키지 전용 : 멤버가 선언된 클래스가 속한 패키지의 모든 클래스에서 접근 가능하다. 디폴트 ( default ) 접근 이라고도 하며, 접근 지시자를 지정하지 않으면 이 수준이다.
- protected : 패키지 전용 접근 수준이며, 추가적으로 멤버가 선언된 클래스의 서브 클래스로부터 접근 가능하다.
- public : 어디에서든 이 멤버를 접근 할 수 있다.
정보은닉에 대해 추가적으로 알아야 할 사항은 없나요?
- 슈퍼 클래스의 메소드를 오버라이드 하는 경우, 슈퍼 클래스에서 지정한 접근 수준보다 더 낮은 것을 지정할 수 없습니다.
- 클래스에서 인터페이스를 구현할 경우, 클래스에서 구현한 인터페이스의 메소드는 반드시 public 으로 선언되어야 합니다. 인터페이스의 모든 멤버들은 접근 지시자를 주지 않아도 자동으로 public 이기 때문이죠.
- 인스턴스 필드는 절대로 public 으로 하지 말아야 합니다. 인스턴스 필드가 final 이 아니거나, 가변 객체의 final 참조일 떄 그 필드를 public 으로 지정하면 외부에서 이 필드의 값을 임의로 변경 가능하므로 그 필드가 갖는 값을 제한 할 수 없게 됩니다. 이 경운에 thread-safe 하게 만들기 어렵습니다.
- 심지어 final 이면서 불변객체를 참조하더라도, public 으로 공개하면, 그 class 의 구조를 바꿀 때 유연성이 매우 떨어집니다.
- public static final 필드를 제외한 static 필드도 일반 멤버변수와 같이 주의를 해야 하며, public static final 필드를 사용할 경우에도, 배열이나 Collection 등을 참조하는 경우는 가변객체를 참조하는 것임에 주의해야 합니다.
그럼 Collection 이나 Array 류는 불변 public static final 로 만들 수 없나요?
만들 수 있습니다.
<방법 1>
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES = Collections.unmodifiableList( Arrays.asList( PRIVATE_VALUES ) );
<방법 2>
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values(){
return PRIVATE_VALUES.clone();
}
'프로그래밍 놀이터 > 디자인 패턴, 리펙토링' 카테고리의 다른 글
[Design Pattern/Java] 가변성을 최소화 하자. (0) | 2012.03.27 |
---|---|
[Design Pattern/Java] public 클래스에서는 public 필드가 아닌 접근자 ( accessor ) 메소드를 사용한다. (0) | 2012.03.14 |
[Design Pattern/Java] Comparable 인터페이스의 구현을 고려하자. (0) | 2012.03.13 |
[Design Pattern/Java] clone 메소드는 신중하게 오버라이드 하자. (0) | 2012.03.12 |
[Design Pattern/Java] toString 메소드는 항상 오버라이드 하자. (0) | 2012.03.12 |
댓글