2016년 11월 7일 월요일

[자바] Effective Java 4장 - 클래스와 인터페이스1

클래스와 인터페이스1

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

  • 정보은닉 : 필요한 정보 외의 모든 구현 세부사항을 다른 모듈에서 접근하지 못하도록 감추는 것
  • 정보은닉은 왜 중요한가?
    • 모듈간 의존성이 낮아진다. -> 재사용, 리팩토링이 쉽다.
    • 효율적인 성능튜닝을 할 수 있다. -> 모듈별로 모니터링하기 쉽다.
  • 클래스에서의 정보은닉 : 불필요한 멤버필드 & 메서드를 접근권한을 통해 감추는 것
    • private : 최상위 레벨 클래스 내부에서만 접근 가능.
    • package-private(default) : 같은 패키지 내의 아무 클래스나 접근 가능. 자바에서는 명시적으로 접근권한을 설정하지 않으면 기본적으로 이 권한이 주어진다.
    • protected : 해당 클래스 및 그 하위 클래스에서만 접근 가능
    • public : 어디에서든 접근 가능
  • 멤버필드는 절대로 public 권한으로 선언하면 안된다.
  • 꼭 공개가 필요한 멤버필드는 public static final 을 이용해 공개하려는 변수를 상수로 선언하는 것을 고려해본다. (단, 기본타입에 한해서... 참조타입은 상수이지만 값을 변경할 수 있다.)

2. 클래스 안에는 public 필드를 두지 말고 접근자 메서드를 사용한다.

  • pulbic 멤버필드는 정보은닉의 이점을 누릴 수 없다.
  • 멤버필드를 private / protected로 변경하고, public gettersetter 접근 메서드를 이용하면 정보은닉의 이점을 100% 누릴 수 있다.
  • package-private / private 중첩 클래스의 멤버필드는 경우에 따라서 public으로 선언하여 코드가독성을 높이기도 한다.
    • 이 중첩클래스들은 바깥의 클래스만 접근이 가능하기 때문에, 정보은닉을 어기는 사례가 아님.

3. 변경 가능성을 최소화한다.

  • 변경 불가능(immutable) 클래스 : 객체를 수정할 수 없는 클래스(ex String 클래스)
  • 변경 불가능 클래스의 이점
    • 설계&구현이 쉽다.
    • 오류 가능성이 적다.
    • 멀티 쓰레드에서 동시성 접근에 대한 걱정을 안해도 된다.
  • 변경 불가능 클래스의 단점
    • 값마다 객체를 새로 생성해야 한다.
  • 변경 불가능 클래스 만드는 방법
1. 객체 상태를 변경하는 setter 메서드를 제공하지 않는다.
2. 상속 받을 수 없도록 한다. class를 선언할 때 final 키워드를 이용하면 상속금지 클래스가 된다.
3. 모든 필드를 final로 선언한다.
4. 모든 필드를 private으로 선언한다.
5. 변경 가능 필드를 제공해야 한다면, 복사본을 만들엉 제공한다.

4. 상속하는 대신 구성한다.

  • 상속 : 클래스를 재사용하기 위해 해당 클래스의 자식 클래스로 구현하는 방법. 부모 클래스로 부터 private 이외의 필드, 메서드를 물려받을 수 있다.
  • 상속의 단점
    • 부모 클래스가 변경되면, 그 여파가 자식클래스까지 미친다.
class A {
    protected int age;
    public int getAge() {
        return age;
    }
}

class B extends A {
    @Override
    public int getAge() {
        age += 5;
        return getAge();
    }
}
  • 구성 : 물려받고자 하는 클래스의 기능을 이용하기 위해 새로운 클래스 내부에 해당 클래스를 private 필드로 선언하고, 이용하고자 하는 메서드를 호출하여 결과를 반환하도록 래핑(Wrapping)하는 방법
  • 구성의 단점
    • callback 구현방식과 함께 사용하기에는 적합하지 않다.
class A {
    private int age;
    public int getAge() {
        return age;
    }
}

class B {
    private A a;
    public getAge() {
        return a.getAge() + 5;
    }
}
  • 즉, 상속이 꼭 맞는 경우가 아니라면 구성 방법을 고려한다.

5. 상속을 위한 설계와 문서를 갖추거나, 그럴 수 없으면 상속을 금지한다.

  • 일반적으로 상속 가능 클래스를 설계하는 것 보다, 구성 방법을 고려하거나, 가능하다면 변경 불가능 클래스로 만들어 상속을 금지하는 것이 훨씬 쉽다.
  • 상속 클래스를 작성하려면 적절한 개수의 protected 멤버를 유지한다.
    • protected 멤버가 너무 많으면 관리하기 힘들다.
    • protected 멤버가 너무 적으면 상속하는 의미가 별로 없는 클래스가 된다.
  • 상속을 허용하는 클래스를 작성할 때의 주의사항
1. 생성자에서 재정의 가능 메서드를 호출하면 안된다. 상속관계에서 부모클래스의 생성자가 자식클래스의 생성자보다 먼저 불리기 때문에, 재정의 가능 메서드의 값이 하위 클래스 생성자에 의존하게 되면 문제가 생긴다.
2. Cloneable, Serializable 인터페이스를 구현하는 클래스라면, clone(), readObject() 메서드도 생성자와 같은 역할을 하므로, 위의 규칙을 지켜야 한다.
3.  상속 가능한(public / protected) 메서드가 내부적으로 어떻게 동작하는지 문서화해야 한다. 자식클래스가 그 메서드를 재정의할 때, 그 문서를 보고 부모 메서드의 행동을 가늠하여 구현되기 때문이다.

댓글 없음:

댓글 쓰기