4장 : 클래스와 인터페이스

2023. 4. 6. 12:20스터디/이펙티브 자바 스터디

728x90

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

- 클래스 내부 데이터 및 구현 정보를 외부 컴포넌트로부터 잘 숨겨야 : 캡슐화

- 모든 클래스이 맴버와 접근성을 가능한 좀혀야

- public일 필요가 없는 클래스의 접근 수준을 최대한 낮춰야

- 리스코프 치환 원칙 : 상위 클래스의 인스턴스는 하위 클래스의 인스턴스로 대체해 사용할 수 있어야

- 즉, 상위 클래스의 메서드를 정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다

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

- public을 가변 필드로 갖는 클래스는 일반적으로 스레드에 안전하지 않음

- 정적 필드도 마찬가지이나, 상수라면 public static final 필드로 공개해도 좋음

- 길이가 0이 아닌 배열은 모두 변경이 가능, 클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안 됨 : private 배열로 만들고 public 불변 리스트를 추가하거나, 방어적 복사를 하는 식으로 진행

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

- public 필드는 캡슐화의 이점을 제공하지 못하고, 내부 표현도 못바꾸고, 불변식을 보장할 수도 없음


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

- 불변 클래스 : 인스턴스의 내부 값을 수정할 수 없는 클래스

- 불변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉬움, 오류 발생률도 적음, 훨씬 안전

 

# 불편 클래스 생성 규칙

1. 객체 상태를 변경하는 메서드 제공 x

2. 클래스 확장 불가 

3. 모든 필드를 private final로 선언 

4. 자신 외에 내부 가변 컴포넌트 접근 불가하게 함

 

- 불변 객체는 근복적으로 스레드 안전하여 따로 동기화할 필요가 없음

- 불변 객체 간은 내부 테이터 공유 가능

- 불변 객체는 그 자체로 실패 원자성 제공

- 값이 다르면 반드시 독립된 객체로 만들어야 한다는 단점이 있음 : StringBuiler같은 가변 동반 클래스를 이용

- 클래스는 꼭 필요한 경우가 아니라면 불변이어야

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

- 상속은 코드를 재사용하는 강력한 수단, 허나 최선은 아님

- 다른 패키지의 구체 클래스를 상속하는 일은 위험

- 메서드 호출과 달리, 상속을 캡슐화를 깨트림

- 상위 클래스 변경이 위험

- 컴포지션 설계 : 새로운 클래스 제작 후 private 필드로 기존 클래스의 인스턴스를 참조하는 것

 

public final class Person {
    private List<String> cars;

    public void addCar(String car){
        cars.add(car);
    }

    public void addCarAll(List<String> cars){
        this.cars.addAll(cars);
    }
}

public class ForwardingPerson {

    private Person person;

    public void addCar(String car) {
        person.addCar(car);
    }

    public void addCarAll(List<String> cars) {
        person.addCarAll(cars);
    }
}

public class InstrumentedPersonCar extends ForwardingPerson {
    private int carCount;

    public InstrumentedPersonCar(Person person) {
        super(person);
    }

    @Override
    public void addCar(String car) {
        carCount ++;
        super.addCar(car);
    }

    @Override
    public void addCarAll(List<String> cars) {
        carCount += cars.size();
        super.addCarAll(cars);
    }

    public int getCarCount() {
        return carCount;
    }
}

- 래퍼 클래스는 콜백 프레임워크와 어울리지 않음

 

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

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

- 호출되는 메서드가 재정의 가능 메서드라면 그 사실을 호출하는데 메서드의 API 설명에 적시해야

- 이어지는 처리에 어떤 영향을 주는지도 담아야

- 모든 상황을 문서로 남겨야

- Implementation Requirements : 내부 동작 방식을 설명

- 상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어 보는 것

- 상속용 클래스 생성자는 재정의 가능 메서드를 호출해서는 안 됨

- Cloneable와 Serializeable 인터페이스를 상속받은 클래스는 상속 할 수 있게 하는 것은 안좋음

- clone, readObject 모두 재정의 메서드를 호출해서는 안 됨.

- 상속용으로 설계하지 않은 클래스는 상속을 금지해야


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

- 인터페이스는 믹스인 정의에 안성맞춤

- 믹스인 : 클래스가 구현할 수 있는 타입,주된 기능에 선택적 기능을 혼합 , 원래 주된 타입 외에도 특정 선택적 행위를 제공한다고 선언하는 효과를 줌 ex) Compareable

- 인터페이스로는 계층구조가 없는 타입 프레임워크 제작 가능

- 레퍼 클래스 관용구와 함께 사용시 인터페이스는 기능을 향상시키는 안전하고 강력한 수단이 됨

- 골격 구현은 인터페이스 제약 떄문에 추상 클래스로 제공하는 경우가 효과적

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

- 기존 인터페이스에 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니라면 피해야 - 디폴트 메서드가 기존 구현체들과 충돌하지 않을지 심사숙고해야함도 당연- 디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님


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

- 클래스가 인터페이스를 구현한다는 것은 자신이 인스턴스로 무엇을 할 수 있는지를 클라이언트에 말해주는 것- 상수 인터페이스는 안티패턴, 클라이언트 코드가 내부 구현에 해당하는 이 상수들에 종속되게 함 - 상수를 공개할 땐 사용하는 클래스나 인터페이스 자체에 추가하거나 열거형으로 표현- 그것도 안되면 인스턴스 불가한 유틸리티 클래스 활용


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

- 태그 달린 클래스 대신 계층구조 활용

- 루트가 될 추상 클래스를 정의, 동작이 달라지는 메서드들을 루트 클래스의 추상 메서드로 선언


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

- 비정적 맴버 클래스의 인스턴스는 바깥 클래스의 인스턴스와 암묵적으로 연결

- 중첩 클래스의 인스턴스가 바깥 인스턴스와 독립적으로 존재할 수 있다면 정적 맴버 클래스로 만들어야

- 비정적 맴버 클래스는 바깥 인스턴스 없이 생성 불가

- 비정적 맴버 클래스는 어댑터 정의시 자주 쓰임

- 자신의 반복자를 구현할 때 비정적 맴버 클래스 주로 사용

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

- static을 생략하면 메모리 누수 발생 가능

- 익명 클래스는 맴버와 달리 쓰이는 시점에 선언과 동시에 인스턴스 생성됨

# 정리

- 메서드 밖에서도 사용하거나 메서드 안에 정의하기에 너무 길다면 맴버 클래스로 생성

- 멤버 클래스의 인스턴스 각각이 바깥 인스턴스를 참조한다면 비정적, 그렇지 않으면 정적

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

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

 

728x90

'스터디 > 이펙티브 자바 스터디' 카테고리의 다른 글

7장 : 람다와 스트림  (0) 2023.04.06
6장 : 열거 타입과 애너테이션  (0) 2023.04.06
5장 : 제네릭  (0) 2023.04.06
3장 : 모든 객체의 공통 메서드  (0) 2023.04.05
2장 : 객체 생성과 파괴  (0) 2023.04.04