본문 바로가기

STUDY REVIEW/이펙티브 자바 독서스터디

[EFFECTIVE JAVA] 이펙티브 자바 독서스터디 - 4장 클래스와 인터페이스

4장 클래스와 인터페이스
아이템 15. 클래스와 멤버의 접근 권한을 최소화하라
아이템 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라
아이템 17. 변경 가능성을 최소화하라
아이템 18. 상속보다는 컴포지션을 사용하라
아이템 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
아이템 20. 추상 클래스보다는 인터페이스를 우선하라
아이템 21. 인터페이스는 구현하는 쪽을 생각해 설계하라
아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라
아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라
아이템 24. 멤버 클래스는 되도록 static으로 만들라
아이템 25. 톱레벨 클래스는 한 파일에 하나만 담으라

읽고 느낀 점

 

재밌는 예제와 쉬운 설명을 하고 싶은데, 책을 읽고 지식을 받아드리기 벅차 내 수준으로는 재밌는 예제와 쉬운 설명이 쉽지 않다... 어서 실력이 늘어서 1하면 딱 1로 이해하고 싶다... 지금은 1하면 숫자? 자연수? 1? 물음표연쇄마다 

어서 실력이 늘기를 꿈구며 완독을 바래본다.


아이템 15. 클래스와 멤버의 접근 권한을 최소화하라

핵심 정리
프로그램 요소의 접근성은 가능한 한 최소한으로 하자.
최소한의 public API를 설계하자.
그 외 클래스, 인터페이스, 멤버가 공개되지 않도록 하자.
public 클래스는 상수용 public static final 필드 외에는 어떠한 public 필드도 가져선 안된다.
public  static final 필드가 참조하는 객체가 불변인지 확인하자.

 

잘 설계된 컴포넌트는 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼는가?

모든 내부 구현을 완벽하게 숨겨, 구현과 API를 깔끔하게 분리해라

이를 정보 은닉(information hiding) 혹은 캡슐화(encapsulation) 라고 한다

 

캡슐화의 장점으로는 개발 속도를 높일 수 있다. 여러 컴포넌트를 병렬 개발할 수 있기 때문이다. 성능 최적화에도 도움을 준다. 또한 각 컴포넌트를 더 빨리 파악할 수 있고 다른 컴포넌트로 교체하는 부담도 적기 때문에 관리적인 비용도 줄일 수 있으며 재사용성을 높일 수 있다. 그리고 시스템이 미완성되었어도 개별 컴포넌트의 동작을 검증할 수 있기 때문에 큰 시스템의 제작을 조금 더 쉽게 해준다.

 

핵심은 모든 클래스와 멤버의 접근성을 최대한 좁혀야 한다.


 

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

핵심 정리
public 클래스는 절대 가변 필드에 직접 노출해서는 안된다.
하지만 package-private 클래스나 private 중첩 클래스에서는 종종 필드를 노출하는 편이 나을 수 있다.

 

접근자와 변경자 메서드를 활용해 데이터를 캡슐화하자.

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() { return x; }
    public double getY() { return y; }

    public void setX(double x) { this.x = x; }
    public void setY(double y) { this.y = y; }
}

 

아이템 17. 변경 가능성을 최소화하라

핵심 정리
변경 가능성을 최소화하라
불변 클래스를 활용하자.

 

불변 클래스란 인스턴스의 내부 값을 수정할 수 없는 클래스이다.

 

  • 클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다
  • 불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄이자
  • 다른 합당한 이유가 없다면 클래스의 모든 필드는 private final 이어야 한다
  • 생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다. 확실한 이유가 없다면 생성자와 정적 팩터리 외에는 그 어떤 초기화 메서드도 public으로 제공해서는 안 된다

 

아이템 18. 상속보다는 컴포지션을 사용하라

핵심 정리
상속은 캡슐화를 해친다.
상속은 상위 클래스와 하위 클래스가 순수한 is-a 관계일 때만 써야한다.
is-a 관계일때도 안심할 수만은 없는 게, 하위 클래스와 피키지가 상위 클래스와 다르고, 상위 클래스가 확장을 고려해 설계되지 않았다면 문제가 될 수 있다.
상속의 취약점을 피하고자 상속 대신 컴포지션과 전달을 사용하자
래퍼 클래스로 구현할 적당한 인터페이스가 있다면 이는 하위 클래서보다 견고하고 강력하다.

 

컴포지션 대신 상속을 사용하기로 결정하기 전 마지막 자문해야할 질문!

  1. 확장하려는 클래스의 API에 아무런 결함이 없는가?
  2. 결함이 있다면, 이 결함이 클래스의 API까지 전파되어도 괜찮은가?
  3. 컴포지션으로는 이런 결함을 숨기는 새로운 API를 설계할 수 있지만 상속은 상위 클래스의 API 결함까지 승계되는데 괜찮은가?

 

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

핵심 정리
클래스를 확장할 명확한 이유가 떠오르지 않는다면 상속을 금지하는 편이 낫다.
상속을 금지하려면 클래스를 final로 선언하거나 생성자 모두를 외부에서 접근할 수 없도록 만들자.

 

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

 

상속을 금지하는 방법

  1. 쉬운 방법! 클래스를 final로 선언하기
  2. 모든 생성자를 private나 package-pirvate으로 선언하고 public 정적 팩토리를 만들어주

 

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

핵심 정리
다중 구현용 타입으로는 인터페이스가 가장 적합하다.
복잡한 인터페이스라면 구현하는 수고를 덜어주는 골격 구현을 함께 제공하는 방법을 고려하자.
골격 구현은 가능한 한 인터페이스의 디폴트 메서드로 제공하며, 그 인터페이스를 구현한 모든 곳에서 활용하도록 하는 것이 좋다. 

 

자바가 제공하는 다중 구현 매커니즘은 추상 클래스와 인터페이스이다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다.


 

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

핵심 정리
구현하는 쪽을 생각해 설계하라

 

인터페이스를 설계할 떄는 세심한 주의를 기울여야 한다.

반드시 테스트를 거치고 서로 다른 방법으로 3가지는 구현해보자.

바로잡을 기회가 아직 남았을 떄 결함을 찾을 수 있다!


 

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

핵심 정리
상수 공개용 수단으로 사용하지 말자

 

인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다

클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지 클루아언트한테 이야기하는 것이다. 인터페이스는 오직 이 용도로만 사용하자.


 

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

핵심 정리
새로운 클래스를 작성하는데 태그 필드가 등장한다면 태그를 없애고 계층구조로 대체하는 방법을 생각해보자. 기존 클래스가 태그 필드를 사용하고 있다면 계층구조로 리팩토링 하는걸 고민하자.

 

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


 

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

핵심 정리
중첩 클래스에는 4가지가 있다
메서드 밖에서도 사용하거나 메서드 안에 정의하기에 길다면 멤버 클래스로 만든다.
멤버 클래스의 인스턴스 각각이 바깥 인스턴스를 참조한다면 비정적으로, 
그렇지 않다면 정적으로 만든다.
중첩 클래스가 한 메서드 안에서만 쓰이며 그 인스턴스를 생성하는 지점이 한 곳이고 해당 타입으로 쓰기에 적합한 클래스나 인터페이스가 있다면 익명 클래스로 만들고, 
그렇지 않다면 지역 클래스로 만든다.

 


 

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

핵심 정리
소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자.
컴파일러가 한 클래스에 대한 정의를 여러개 만드는 일이 사라질 것이다.
소스 파일을 어떤 순서로 컴파일하든 바이너리 파일이나 프로그램의 동작이 달라지는 일은 결코 일어나지 않을것이다.

 

단순히 톱레벨 클래스들을 서로 다른 소스 파일로 분리하자