정보 은닉을 얼마나 잘했는지가 컴포넌트가 잘 설계 됐는지 알 수 있는 여부
정보 은닉의 장점
모든 클래스와 맴버의 접근성을 가능한 좁혀야 한다
리스코프 치환 원칙을 지키기 위해서는 상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다
public 클래스의 인스턴스 필드는 되도록 public이 아니어야 한다
public 가변 필드를 갖는 클래스는 일반적으로 스레드 안전하지 않다
클래스에서 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안 된다
모듈이 도입되면서 모듈 중 공개할 것들을 선언할 수 있다→ public이나 protected여도 공개하지 않으면 모듈 외부에서는 접근이 불가능하다
public 클래스에서는 가변 필드를 직접 노출해서는 안 된다
불변 필드라면 노출해도 위험이 덜하지만 안심할 수는 없다
불변 클래스: 인스턴스의 내부 값을 수정할 수 없는 클래스, 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다
불변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉽고, 오류가 생길 여지도 적다
클래스를 불변으로 만들기 위한 5가지 규칙
불변 객체는 근본적으로 안전하여 따로 동기화할 필요 없고 안심하고 공유할 수 있다
불변 객체 끼리는 내부 데이터를 공유할 수 있다
객체를 만들 때 불변 객체들을 구성요소로 사용하면 그 구조가 아무리 복잡하더라도 불변식을 유지하기 훨씬 수월하다
불변 객체는 그 자체로 실패 원자성을 제공
불변 클래스의 단점은 값이 다르면 반드시 독립된 객체로 만들어야 한다는 것
클래스는 꼭 필요한 경우가 아니라면 불변이여야 하기 때문에 게터가 있다고 해서 무조건 세터를 만들지 말자
불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄이자
다른 합당한 이유가 없다면 모든 필드는 private final이어야 한다
생성자는 불변식 설정이 모두 완료된 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다
메서드 호출과 달리 상속은 캡슐화를 깨뜨린다
상위 클래스의 구현이 달라지면 하위 클래스가 오작동 할 수 있다
상위 클래스에서 메서드가 추가되면 하위 클래스에서 허용되지 않은 원소를 추가할 수 있게 될 가능성이 생긴다
새로운 클래스를 만들고 private 필드로 기존 클래스의 인스턴스를 참조하게 해서 문제를 해결할 수 있다
상속은 반드시 하위 클래스가 상위 클래스의 진짜 하위 타입인 상황에서만 쓰여야 한다
상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다
효율적인 하위 클래스를 큰 어려움 없이 만들 수 있게 하려면 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅을 잘 선별하여 protected 메서드 형태로 공개해야 할 수 도 있다
상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어 보는 것이 유일하기 때문에 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다
상속용 클래스의 생성자는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안된다
클래스를 상속용으로 만들려면 엄청난 노력이 들고 제약이 있는데, 상속용으로 설계하지 않은 클래스는 상속을 금지하는 것이 좋다
상속을 금지시키는 방법
둘의 가장 큰 차이점은 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 하지만 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급
인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다
인터페이스는 기능을 향상시키는 안전하고 강력한 수단
복잡한 인터페이스는 골격 구현을 함께 제공하면 좋다
디폴트 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있기 때문에 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다
상수 인터페이스 안티패턴은 인터페이스를 잘못 사용한 예
태그 달린 클래스는 장황하고, 오류 내기 쉽고, 비효율적이다
태그 달린 클래스를 클래스 계층구조로 바꾸는 방법
중첩 클래스: 다른 클래스 안에 정의된 클래스
중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외에 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다
중첩 클래스의 종류: 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 지역 클래스
정적 멤버 클래스
비정적 멤버 클래스
멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 무조건 static을 붙여서 정적 멤버 클래스로 만들어야 한다
→ static을 생략하면 인스턴스로의 숨은 외부 참조를 갖게 되어 가비지 컬렉터가 바깥 클래스의 인스턴스를 수거하지 못해 메모리 누수가 생길 수 있다
익명 클래스
지역 클래스
해당 규칙을 따르면 컴파일러가 한 클래스에 대한 정의를 여러 개 만들어 내는 일은 사라지고, 소스 파일을 어떤 순서로 컴파일하든 바이너리 파일이나 프로그램의 동작이 달라지는 일은 결코 일어나지 않는다