모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다.
톱레벨 클래스와 인터페이스에 package-private 또는 public을 쓸 수 있다.
public으로 선언하면 API가 되므로 하위 호환성을 유지하려면 영원히 관리해야 한다.
패키지 외부에서 쓰지 않을 클래스나 인터페이스라면 package-private으로 선언한다.
**class DefaultMemberService implements MemberService {**
...
한 클래스에서만 사용하는 package-private 클래스나 인터페이스는 해당 클래 스에 private static으로 중첩 시키자.
class DefaultMemberService implements MemberService {
private String name;
**private static class PrivateStaticClass {
// 해당 DefaultMemberService 와 남남의 관계 가령 접근하기 수월하다.
}**
**private class PrivateClass {
// 외부 인스턴스를 참조하는 필드가 생긴다.
sout(name);
}**
public static void main(String[] args) {
Arrays.stream(PrivateClass.class.getDeclaredFields()).forEach(System.out::println);
}
}
private과 package-private은 내부 구현.
public 클래스의 protected와 public은 공개 API.
코드를 테스트 하는 목적으로 private을 package-private으로 풀어주는 것은 허용할 수 있다. 하지만 테스트만을 위해서 멤버를 공개 API로 만들어서는 안 된 다. (테스트를 같은 패키지에 만든다면 그럴 필요도 없다.)
public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다. (아이템16)
클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안 된다.
public static final String NAME = "name";
public class ItemService {
**private MemberService memberService;**
boolean onSale;
protected int saleRate;
public ItemService(MemberService memberService) {
if (memberService == null) {
throw new IllegalArgumentException("MemberService should not be null.");
}
this.memberService = memberService;
}
**MemberService getMemberService() {
return memberService;
}**
}
===
@ExtendWith(MockitoExtension.class)
class ItemServiceTest {
@Mock
MemberService memberService;
@Test
void itemService() {
ItemService service = new ItemService(memberService);
assertN
otNull(service);
**assertNotNull(service.getMemberService());**
}
}