본문 바로가기

책/Effective Java

클래스와 인터페이스

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

 - 모든 클래스와 멤버의 접근성을 가능한 좁혀야 한다.

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

 - public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않다. ((public static final로 선언된 상수 제외)

 - public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안 된다. (배열은 private으로 만들고, 반환 객체는 불변 리스트 혹은 배열의 복사본으로 한다.)


public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

 - public 클래스라면 데이터 필드를 직접 노출하지 말고 접근자, 변경자 메소드를 제공하자.

 - package-private 혹은 private 중첩 클래스라면 데이터 필드를 노출한다 해도 문제가 없다.


변경 가능성을 최소화하라

클래스를 불변으로 만들기 위한 5가지 규칙

 - 객체의 상태를 변경하는 메서드를 제공하지 않는다.

 - 클래스를 확장할 수 없도록 한다.

 - 모든 필드를 final로 선언한다.

 - 모든 필드를 private로 선언한다.

 - 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.


상속보다는 컴포지션을 사용하라

 - 상속은 캡슐화를 깨뜨릴 수 있다.

 - 상위 클래스와 하위 클래스가 순수한 is-a 관계일 때도 하위 클래스와 상위 클래스의 패키지가 다르고, 상위 클래스가 확장을 고려해 설계되지 않았다면 문제가 될 수 있다

 - 특히 래퍼 클래스로 구현할 적당한 인터페이스가 있다면 상속 대신 컴포지션과 전달을 사용하자.


상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

 - 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다.

 - 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있다.

 - 상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 유일하다. (상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다.)

 - 상속용 클래스의 생성자, clone과 readObject 메서드는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다.

 - 상속용으로 설계하지 않은 클래스는 상속을 금지하자. (클래스를 final로 선언하거나, 생성자를 private이나 package-private으로 선언하고, 정적 팩토리 메서드를 사용해 생성 된 인스턴스를 돌려준다.)


추상 클래스보다는 인터페이스를 우선하라

 - 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해 넣을 수 있다.

 - 인터페이스는 믹스인(클래스가 구현할 수 있는 타입, 믹스인을 구현한 클래스에 원래의 주된 타입 외에도 특정 선택적 행위를 제공한다고 선언하는 효과를 줌) 정의에 좋다.

 - 인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다.

 - 래퍼 클래스 관용구와 함께 사용하면 기능을 향상시키는 안전하고 강력한 수단이 된다.


인터페이스는 구현하는 쪽을 생각해 설계하라

 - 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려운 법이다.

 - 디폴트 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있다. (기존 인터페이스에 디폴트 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다.)


인터페이스는 타입을 정의하는 용도로만 사용하라

 - 상수 인터페이스 안티 패턴은 사용하지 말자. (상수 공개용 수단으로 사용하지 말자.)


태그 달린 클래스보다는 클래스 계층구조를 활용하라

 - 태그 달린 클래스는 장황하고, 오류를 내기 쉽고, 비효율적이다.

 - 태그 달린 클래스는 계층구조를 어설프게 흉내낸 아류일 뿐이다.


멤버 클래스는 되도록 static으로 만들라

 - 멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 무조건 static을 붙여서 정적 멤버 클래스로 만들자.

 - 중첩 클래스가 한 메서드 안에서만 쓰이면서 그 인스턴스를 생성하는 지점이 단 한 곳이고, 해당 타입으로 쓰기에 적합한 클래스나 인터페이스가 이미 있다면 익명 클래스로 만들고, 그렇지 않으면 지역 클래스로 만들자.


톱레벨 클래스는 한 파일에 하나만 담으라

 - 소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자.


' > Effective Java' 카테고리의 다른 글

람다와 스트림  (0) 2020.03.20
열거 타입과 애너테이션  (0) 2020.03.18
제네릭  (0) 2020.03.17
모든 객체의 공통 메서드  (0) 2020.03.13
객체 생성과 파괴  (0) 2020.03.10