Skip to content

Latest commit

 

History

History
142 lines (117 loc) · 7.73 KB

클래스와_멤버의_접근_권한을_최소화하라.md

File metadata and controls

142 lines (117 loc) · 7.73 KB

어설픈 시스템과 잘 설계된 시스템의 차이점

  • 어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 다음과 같다
  • 클래스 내부 데이터와 구현 정보를 얼마나 잘 숨겼는지
  • 잘 설계된 컴포넌트는 오직 API를 통해서만 다른 컴포넌트와 소통
  • 서로의 내부 동작 방식에는 전혀 개의치 않음 (정보 은닉)

정보 은닉의 장점

  • 정보 은닉의 장점은 정말 많다
  • 그 중 대부분은 시스템을 구성하는 컴포넌트들을 독립시킨다는 맥락의 장점
  • 하나씩 알아보자
  • 시스템 개발 속도를 높인다. (서로의 내부 동작 방식을 모르게 함으로써 병렬적인 개발 가능)
  • 시스템 관리 비용을 낮춘다. (독립적인 유지보수 가능)
  • 재사용성을 높인다 (독자적 컴포넌트는 유용하게 쓰일 가능성 높음)
  • 큰 시스템을 제작하는 난이도 낮춤 (개별로 검증 가능하기 때문)

정보 은닉을 위한 자바의 장치

  • 자바는 정보 은닉을 위한 다양한 장치를 제공
  • 그 중 접근 제어 메커니즘에 대해 알아보자
  • 접근 제어 메커니즘은 클래스, 인터페이스, 멤버의 접근성을 명시
  • 이 접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심!

접근 제어 메커니즘 원칙

  • 기본 원칙은 모든 클래스와 멤버의 접근성을 가능한 좁혀야 한다는 것
  • 달리 말하면, 소프트웨어가 올바로 동작하는 한 항상 가장 낮은 접근 수준을 부여해야 한다는 것

톱 레벨 클래스와 인터페이스의 접근 제어 수준

한줄 요약: 패키지 외부에서 사용할 일이 없으면 package-private으로 설정하자

  • 톱레벨 클래스는 가장 바깥쪽에 있는 클래스라는 의미
  • 톱레벨 클래스와 인터페이스에 부여할 수 있는 접근 수준은 두가지
  • public, package-private
  • public으로 선언하면 공개 API가 되는 것
  • package-private으로 선언하면 내부 구현이 된다.
  • 패키지 외부에서 사용할 일이 없으면 package-private으로 설정하자
  • package-private의라면 이들은 내부 구현이 되니 다음 배포에 수정 교체등이 자유롭다
  • 반면 public이라면 API가 됨으로 하위 호환을 위해 영원히 관리해줘야 한다.

한 클래스에서만 사용하는 package-private

  • 만약 한 클래스에서만 사용하는 package-private 톱레벨 클래스나 인터페이스가 있다면 이를 사용하는 클래스의 내부 클래스로 위치 시켜보자
package machine.domain.calculate;

public class Calculator {
	
	private final Adder adder = new Adder();
	
	public int add(int a, int b) {
		return adder.add(a, b);
	}
	....
}
package machine.domain.calculate;

//package-Private 톱 클래스
class Adder { 
	...
}
  • 위의 코드에서 Adder 클래스는 Calculator에게서 밖에 사용되지 않는다.
  • 하지만 톱 클래스에 대한 가장 낮은 접근 제어 수준은 package-private임으로 같은 패키지라면 어떤 클래스든 Adder를 사용할 수 있다.
  • 불필요하게 접근 제어 메커니즘이 넓다
package machine.domain.calculate;

public class Calculator {
	
	public int add(int a, int b) {
		return adder.add(a, b);
	}
	....

	// 한 클래스에서만 사용하는 클래스를 이너 클래스로 위치
	// 이렇게 함으로써 Adder는 바깥 클래스 하나에서만 접근 가능함
	private static class Adder {
		...
	}
}
  • 한 클래스에서만 사용하는 톱레벨 클래스를 사용하는 쪽에 중첩 기키면 바깥 클래스 하나에서만 접근할 수 있도록 할 수 있다.

멤버에 부여할 수 있는 접근 제어 수준

  • 멤버: 필드, 메서드, 중첩 클래스, 중첩 인터페이스
  • 멤버에 적용할 수 있는 접근 제어 수준은 4가지
  • private: 멤버를 선언한 톱레벨 클래스에서만 접근 가능
  • package-private: 멤버가 소속된 패키지 안의 모든 클래스에서 접근 가능 (default)
  • protected: package-private + 이 멤버를 선언한 하위 클래스에서 접근 가능
  • public: 모든 곳에서 접근 가능

멤버에 대한 접근 제어 원칙

  • 클래스의 공개 API를 세심히 설계한 후, 그 외의 모든 멤버는 private으로 만들자
  • 그런 다음 오직 같은 패키지의 다른 클래스가 접근해야 하는 멤버에 한해 package-private으로 풀어주자
  • 그리고 권한을 풀어주는 일을 자주 하게 된다면 컴포넌트 분해가 필요하다는 메시지가 아닌지 생각해보자
  • private, package-private은 모두 구현에 해당함으로 보통은 공개 API에 영향을 주지 않는다.
  • 단 Serializable을 구현한 클래스에서는 그 필드들도 의도치 않게 공개 API가 될 수도 있다

pacakge-private 에서 protected로 바꾸면?

  • public 클래스에서 pacakge-private, protected로 멤버의 접근 제어 수준을 바꾸는 순간 접근 가능한 범위가 굉장히 넓어진다.
  • public 클래스의 protected 멤버는 공개 API이다.
  • 공개 API는 영원히 지원해야 하는 대상
  • 따라서 멤버의 접근 제어 수준이 protected인 것은 적을 수록 좋음

멤버 접근성을 좁히지 못하는 상황

  • 상위 클래스의 메서드를 재정의하고 싶은 경우를 생각해보자
  • 상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다.
  • 이는 멤버 접근성을 원하는대로 좁히지 못하는 제약 상황
  • 이러한 제약 상황은 왜 있을까?
  • 상위 클래스의 인스턴스는 하위 클래스로 대치될 수 있어야 한다는 리스코프 치환 원칙 때문

코드를 테스트하는 목적으로 접근 제어 수준 완화

  • 코드를 테스트하려는 목적으로 접근 제어 범위를 넓히려 할 때가 있다.
  • 클래스의 private 멤버를 package-private까지 풀어주는 것은 허용 가능
  • 그 이상은 안됨
  • 이 위로는 공개 API로 관리의 대상이 되어야 하기 때문

public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다.

  • public 인스턴스는 필드에 담을 수 있는 값을 제한할 힘을 잃게 된다.
  • 그 필드와 관련된 모든 것은 불변식을 보장할 수 없게 된다는 뜻
  • 여기에 더해 필드가 수정될 때 Thread-Safe하지 않다.
  • 이러한 문제는 정적 필드에서도 마찬가지 But 예외 있음
  • 해당 클래스가 표현하는 추상 개념을 완성하는 데 꼭 필요한 구성요소로써의 상수라면 public 공개도 괜춘
  • 다만 public static final은 반드시 기본 타입 값이나 불변 객체를 참조하도록 하자
  • 가변 객체를 참조한다면 불이익(사이드 이펙트) 많다.

자바 9의 모듈

  • 자바 9에서는 모듈 시스템이라는 개념이 도입되면서 암묵적으로 접근 수준이 추가되었음
  • 패키지가 클래스의 묶음이라면 모듈은 패키지들의 묶음
  • 모듈은 자신에 속하는 패키지들 중 공개할 것들을 선언한다.
  • protected 혹은 public 멤버라도 해당 패키지를 공개하지 않았다면 모듈 외부에서는 접근할 수 없다.
  • 모듈 시스템을 활용하면 클래스를 외부에 공개하지 않으면서도 같은 모듈을 이루는 패키지 사이에서는 자유롭게 공유할 수 있다.
// 모듈 내부의 abc.test 패키지를 외부에 공개한다.  
module abcmodule { exports abc.test; }
  • 다만 모듈의 장점을 제대로 누리려면 해야 할 일이 많다.
  • 아직까지는 모듈 개념이 널리 받아들여지지 않았고 까다로운 만큼 당분간은 사용하지 말자