독서찰기(讀書札記) (90) 썸네일형 리스트형 [아이템 21] 인터페이스는 구현하는 쪽을 생각해 설계하라 [Why] 자바 8에 와서 기존 인터페이스에 메서드를 추가할 수 있도록 디폴트 메서드를 소개했다. 디폴트 메서드를 선언하면, 인터페이스 구현 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 하지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. e.g.) 자바 8에서는 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가되었다. 주로 람다를 활용하기 위해서다. 디폴트 메서드는 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으킬 수 있다. [How] 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다. 디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님을 명심해야 한.. 골격 구현(skeletal implementation) 클래스란? 골격 구현(skeletal implementation)은 인터페이스와 추상 클래스의 이점을 함께 사용할 수 있는 디자인이다. 상황 다양한 유형의 상품을 판매하는 자판기를 만들어보자. 코드 public interface Ivending { void start(); void chooseProduct(); void stop(); void process(); } // 사탕 자판기 public class CandyVending implements Ivending { @Override public void start() { System.out.println("Start Vending machine"); } @Override public void chooseProduct() { System.out.println("P.. [아이템 20] 추상 클래스보다는 인터페이스를 우선하라 [Why] 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다. 자바는 단일 상속만 지원하니, 추상 클래스 방식은 새로운 타입을 정의하는 데 커다란 제약을 안게 되는 셈이다. 인터페이스가 선언한 메서드를 모두 정의하고 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있다. 클래스 선언에 implements 구문만 추가하면 된다. 기존 클래스 위에 새로운 추상 클래스를 끼워넣기는 일반적으로 어렵다. 인터페이스는 믹스인(mixin) 정의에 안성맞춤이다. 인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다. e.g.) Singer 인터페이스, Songwriter .. [아이템 19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라. 상속을 고려한 설계와 문서화란? 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다. [Why] 상속을 염두에 두지 않고 설계했고, 상속할 때의 주의점도 문서화해놓지 않은 '외부' 클래스를 상속할 때는 위험하다. 아이템18 상속용 클래스의 생성자는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다. 상위 클래스의 생성자가 하위 클래스의 생성자보다 먼저 실행되므로 하위 클래스에서 재정의한 메서드가 하위 클래스의 생성자보다 먼저 호출된다. 이때 그 재정의한 메서드가 하위 클래스의 생성자에서 초기화하는 값에 의존한다면 의도대로 동작하지 않는다. public class Super { // 잘못된 예 - 생성자가 재정의 가능 메서드를 호출한다. .. [아이템 18] 상속보다는 컴포지션을 사용하라 ※ 여기서 말하는 '상속'은 클래스가 다른 클래스를 확장하는 구현 상속을 말한다. 클래스 인터페이스를 구현하거나 인터페이스가 다른 인터페이스를 확장하는 인터페이스 상속과는 무관하다. ※ 상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 안에서라면 상속도 안전한 방법이다. 확장할 목적으로 설계되었고 문서화도 잘 된 클래스아이템19도 마찬가지로 안전하다. 하지만, 일반적인 구체 클래스를 패키지 경계를 넘어, 즉 다른 패키지의 구체 클래스를 상속하는 일은 위험하다. [Why] 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 상속은 반드시 하위 클래스가 상위 클래스의 '진짜' 하위 타입인 상황에서만 쓰여야 한다. 클래스 A를 상속하는 클래스 B를 작성하려 한다면 "B가 정말 A인가?"라고 자문해.. [아이템 17] 변경 가능성을 최소화하라 불변 클래스란? 인스턴스의 내부 값을 수정할 수 없는 클래스 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다. 자바 플랫폼 라이브러리에서의 예시) String, 기본 타입의 박싱된 클래스들, BigInteger, BigDecimal [Why] 가변 클래스보다 설계하고 구현하고 사용하기 쉽다. 불변 클래스라면 한번 만든 인스턴스를 최대한 재활용할 수 있다. 자주 사용되는 인스턴스를 캐싱하여 중복 생성되지 않게 해주는 정적 팩터리를 제공할 수 있다. 아이템1 불변 객체는 자유롭게 공유할 수 있음은 물론, 불변 객체끼리는 내부 데이터를 공유할 수 있다. 객체를 만들 때 다른 불변 객체들을 구성요소로 사용하면 그 구조가 아무리 복잡하더라도 불변식을 유지하기 수월하다. 오류가.. [아이템 16] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 [Why] class Point { public double x; public double y; } 인스턴스 필드를 모아놓는 일 외에는 아무 목적도 없는 퇴보한 클래스 데이터 필드에 직접 접근할 수 있으니 캡슐화의 이점을 제공하지 못한다. 아이템15 API를 수정하지 않고는 내부 표현을 바꿀 수 없고, 불변식을 보장할 수 없으며, 필드에 접근할 때 부수 작업을 수행할 수도 없다. [When] public 클래스에서라면 접근자를 제공함으로써 클래스 내부 표현 방식을 언제든 바꿀 수 있게 한다. package-private 클래스 혹은 private 중첩 클래스라면 데이터 필드를 노출한다 해도 하등의 문제가 없다. [How] public 클래스 class Point { private double x; pri.. [아이템 15] 클래스와 멤버의 접근 권한을 최소화하라 ※ 어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다. 정보은닉, 혹은 캡슐화라고 하는 이 개념은 소프트웨어 설계의 근간이 되는 원리다. ※ 멤버(필드, 메서드, 중첩 클래스, 중첩 인터페이스)에 부여할 수 있는 접근 수준은 네 가지다. · private: 멤버를 선언한 톱레벨 클래스에서만 접근할 수 있다. · package-private: 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있다. 접근 제한자를 명시하지 않았을 때 적용되는 패키지 접근 수준이다. (단, 인터페이스의 멤버는 기본적으로 public이 적용된다) · protected: package-private의 접근 범위를 포함하며, 이.. 이전 1 ··· 6 7 8 9 10 11 12 다음