본문 바로가기

개발/[스터디] 이펙티브 자바

[책 요약]이펙티브자바 21~25

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

인터페이스 내 디폴트 메서드의 등장 

자바 8 이전에는 기존 구현체를 수정하지 않고는 인터페이스에 메서드를 추가할 방법이 없었다. 

자바 8 이후, 핵심 컬렉션 인터페이스에 디폴트 메서드가 여러개 추가 되었다. 

 

디폴트 메서드가 기존 구현체에 런타임 오류를 일으킬 수도 있다. 

예. apache.commons.collections4.SynchronizedCollection

4.4 버전부터 removeIf가 apache.commons.collections4.SynchronizedCollection에 추가되었다. 

위 클래스는 객체의 동기화를 제공한다. 그런데 4.4 버전 이전에는 removeIf가 구현체에 없어서, 인터페이스에서 제공하는 디폴트 메서드를 사용하였다. 그 결과 동기화가 없어서, 클라이언트는 예상했던 결과를 받지 못할 수도 있다. 예를 들어, 멀티 스레드 환경에서 SynchronizedColleciton을 공유하고, 그 중 한 스레드가 removeIf를 호출할 경우, ConcurrentModificationException이 발생한다. 

 

결론

- 기존 인터페이스에 메서드를 추가하는 일은 꼭 필요한 일이 아니라면 피해야한다.

- 인터페이스를 설계할 때는 보편적으로 쓰일 메서드를 심사숙고하여 결정해야한다. 

- 인터페이스 릴리즈전 심사숙고하자. 

 

아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라. (= 상수 공개용으로 사용하는 것은 안티패턴이다.)

상수인터페이스는 지양하자

1) 인터페이스 본래의 용도에 어긋난다.

인터페이스는 클라이언트에 제공될 기능을 명세하는 용도이다.

 

2) 사용자에게 필요 없는 정보다. 

책 139p 코드 22-1의 상수는 클라이언트에서 사용될 수가 아니며, 내부 구현을 위한 용도이다.

구현체의 상수는 사용자에게 지나치게 많은 정보를 제공하는 것으로, 오히려 혼란을 야기한다. 

 

3) 구현체에서 상수를 쓰지 않더라도, 바이너리 호환성 때문에 상수 인터페이스를 구현해야만 한다. 

 

그렇다면 상수는 어디에 넣을까?

- 연관된 클래스

- 인스턴스화 할 수 없는 유틸리티 클래스 (코드 22-2. 140p)

 

Tip!

유틸리티 클래스의 상수를 빈번히 사용한다면 정적 임포트를 이용하여 클래스의 이름을 생략하자. 

 

아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라.

태그 달린 클래스

142p 코드 23-1을 살펴보자.

Figure 클래스 내에서 사각형, 원 두 도형의 개념이 함께 있다. 

 

문제점 1. 각 도형에게 필요없는 프로퍼티 값 존재

사각형은 width, height만 필요한 반면, 원은 radius만 프로퍼티로 필요하다. 

 

문제점 2. 각 도형의 area가 원/사각형 중 어느 도형의 area인지 불분명해진다. 

예) Figure figure = new Figure(10); // 처음 생성시 원을 의도했을 것 

....

log(figure.area); // 원의 영역임을 알기 위해서는 선언부로 가야하며, 생성자를 다시 확인해야한다. 

 

태그 달린 클래스를 어떻게 리팩토링할까.

추상 클래스 (Figure) + 상속 클래스 (Circle, Rectangle) 조합으로 바꾸자. 

 

아이템 24. 멤버 클래스는 되도록 static으로 만들어라. 

중첩 클래스(nested class)란? 

- 다른 클래스 안에 정의된 클래스

- 종류 : 정적 멤버 클래스 / (비정적) 멤버 클래스 / 익명 클래스 / 지역 클래스 

  => 정적 멤버 클래스를 제외하면 모두 inner class

 

정적 멤버 클래스 & 비정적 멤버클래스

멤버 크래스의 인스턴스가 바깥 인스턴스를 참조한다면 비정적으로, 그렇지 않다면 정적으로 만들자. 

 

익명 클래스

중첩 클래스가 한 메서드 안에서만 쓰이고, 그 인스턴스를 생성하는 곳이 한 곳이며, 해당 타입으로 쓰기에 적합한 클래스나 인스턴스가 있을 경우

 

지역 클래스

굳이 쓸 필요가 있을까?

 

아이템 25. 톱레벨 클래스는 한 파일에 하나만 담으라

컴파일러가 한 클래스에 대한 정의를 여러개 만들어 내는 경우를 막아야한다. 

예제의 소스 코드 컴파일 순서에 따라 프로그램의 동작이 달라짐. 

 

-> 불가피하게 하나의 파일에 몰아넣을 경우, 정적 멤버 클래스를 사용하자