전체보기
21. 인터페이스는 구현하는 쪽을 고려해 설계해라( default 메서드)
자바 8 전에는 기존 구현체를 깨뜨리지 않고 인터페이스에 메서드를 추가할 방법은 존재하지 않았다. 자바 8부터 디폴트 메서드를 통해서 기존 인터페이스에 메서드를 추가할 수 있게 되었다. 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 단, 이렇게 디폴트 메서드를 추가한다고 해도 기존 구현체들과 매끄럽게 연동된다는 보장은 없다. 생각 할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어렵기 때문이다. default boolean removeIf(Predicate
20. 추상 클래스보다는 인터페이스를 우선하라(템플릿 메서드 패턴)
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스 두가지다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만 지원하니, 추상 클래스 방식은 새로운 타입을 정의하는데 커다란 제약을 안게 되는 셈이다. 반면 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급받는다. 기존 클래스에도 손쉽게 새로운 인터페이슬 룩현해넣을 수 있다. 인터페이스가 요구하는 메서드를 추가하고, 클래스 선언에 implements 구문만 추가하면 끝이다. 반면 기존 클래스 위에 새로운 추상 클래스를 끼워넣기는 어려운게 일반적이다. 두 클래스가 같은 추상 ..
19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
상속을 고려한 설계와 문서화란? 우선, 메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야 한다. 달리 말하면, 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 클래스의 API로 공개된 메서드에서 클래스 자신의 또 다른 메서드를 호출할 수도 있다. 그런데 마침 호출되는 메서드가 재정의 가능 메서드라면 그 사실을 호출하는 메서드의 API 설명에 적시해야 한다. 덧붙여서 어떤 순서로 담아야 호출하는지, 각각의 호출 결과가 이어지는 처리에 어떤 영향을 주는지도 담아야 한다. 더 넓게 말하면, 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다. 예를 들어 백그라운드 스레드나 정적 초기화 과정에서도 호출이 일어날 수 있다. A..
18. 상속보다는 컴포지션을 사용하라
상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다. 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다. 상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 안에서라면 상속도 안전한 방법이다. 확장할 목적으로 설계되었고 문서화도 잘 된 클래스도 마찬가지로 안전하다. 하지만 일반적인 구체 클래스를 패키지 경계를 넘어, 다른 패키지의 구체 클래스를 상속하는 것은 위험하다. 메서드 호출과 달리 상속은 캡슐화를 깨드린다. 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다. 상위 클래스의 릴리스에 따라 내부 구현이 달라지게 되면 그 여파로 하위 클래스가 오작동 할 수 있다는 것이다. 상위 클래스 설계자가 확장은 충분히 고려하고 문서화를 제대로 해..
17. 변경 가능성을 최소화하라
불변 클래스란 간단히 말해 그 인스턴스의 내부 값을 수정할 수 없는 클래스다. 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다. 자바 플랫폼 라이브러리에도 다양한 불변 클래스가 있다. String, 기본 타입의 박싱된 클래스들, BigInteger와 BigDecimal 등이 여기 속한다. 클래스를 불변으로 만들려면 다음 다섯 가지 규칙을 따르면 된다. 객체의 상태를 변경하는 메서드를 제공하지 않는다. 클래스를 확장할 수 없도록 한다. 하위 클래스에서 부주의하게 혹은 나쁜 의도로 객체의 상태를 변하게 하는 것을 막는다. 모든 필드를 final로 선언한다. 시스템이 강제하는 수단을 이용해 설계자의 의도를 명확히 드러내는 방법이다. 새로 생성된 인스턴스를 동기화 없이 다른..
16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라
Getter&Setter로 흔히 불리는 접근자와 변경자 메서드 이다. public 클래스라면 패키지 바깥에서 접근할 수 있는 접근자를 제공함으로써 클래스 내부 표현 방식을 언제든 바꿀 수 있는 유연성을 얻을 수 있다. public 클래스가 필드를 공개하면 이를 사용하는 클라이언트가 생겨나고, 내부 표현 방식을 마음대로 바꿀 수 없게 된다. https://kimfk567.tistory.com/14 getter,setter를 사용하는 이유와 객체의 부품화 (in VO,DTO) 문득 getter,setter 제네레이터를 통해 VO,DTO를 만들고 왜 이렇게 사용할까?하는 생각이 들었다. getter ,setter를 만드는건 제네레이터가 해주기 때문에 쉽게 만들 수 있고 값을 받아오고 입력해줘서 DB kimfk..
15. 클래스와 멤버의 접근 권한을 최소화하라
어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다. 잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한다. 오직 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 전혀 개의치 않는다. 이것이 바로 정보 은닉, 캡슐화이다. 캡슐화의 장점은 정말 많다. 그 중 대부분은 시스템을 구성하는 컴포넌트들을 서로 독립시켜서 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있게 해주는 것과 연관되어 있다. 여러 컴포넌트를 병렬로 개발할 수 있기 때문에 시스템 개발 속도를 높인다. 시스템 관리 비용을 낮춘다. 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 ..
14. Comparable을 구현할지 고려하라
이번에는 Comparable 인터페이스의 compareTo() 이다. compareTo() 함수에는 "문자열의 비교" 와 "숫자의 비교" 두 방식이 존재한다. 숫자의 비교 같은 경우는 단순히 크다(1), 같다(0), 작다(-1) 의 관한 결과값을 리턴해주는 반면 문자열의 비교 같은 경우는 같다(0) 외엔 문자열의 아스키 코드 값의 차이를 리턴한다. compareTo는 단순 동치성 비교에 더해 순서까지 비교할 수 있고 제네릭하다. Complarable을 구현했다는 것은 그 클래스의 인스턴스들에는 자연적은 순서가 있음을 뜻한다. 그래서 Comparable을 구현한 객체들의 배열은 다음처럼 손쉽게 정렬할 수 있다. Arrays.sort(a); 검색, 극단값 계산, 자동 정렬되는 컬렉션 관리도 역시 쉽게 할 수..
13. clone 재정의는 주의해서 진행하라
Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이지만, 아쉽게도 의도한 목적을 제대로 이루지 못했다. 가장 큰 문제는 clone 메서드가 선언된 곳이 Cloneable이 아닌 Object이고, 그마저도 protected 라는 데 있다. 그래서 Closeable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없다. 리플렉션을 사용하면 가능하지만, 100% 성공하는 것도 아니다. 해당 객체가 접근이 허용된 clone 메서드를 제공한다는 보장이 없기 때문이다. 하지만 이를 포함한 여러 문제점에도 불구하고 Cloneable 방식은 널리 쓰이고 있어서 잘 알아두는 것이 좋다. Cloneable 인터페이스는 Object의 protected 메서드인 clone의 동작 방..
12. toString을 항상 재정의하라
Object의 기본 toString 메서드가 우리가 작성한 클래스에 적합한 문자열을 반환하는 경우는 거의 없다. 이 메서드는 PhoneNumber@abbd처럼 단순히 클래스_이름@16진수로_표시한_해시코드 를 반환할 뿐이다. toString의 규약은 "모든 하위 클래스에서 이 메서드를 재정의하라" 라고 한다. toString을 잘 구현한 클래스는 사용하기에 훨씬 편하고 디버깅하기 편해진다. toString 메서드는 객체를 println, printf, 문자열 연결 등, 혹은 디버거가 객체를 출력할 때 자동으로 호출된다. 직접 호출하지 않아도 어디선가 쓰일 것이다. 그렇기에 실전에서 toString은 보안에 문제가 되지 않는 한 그 객체가 가진 주요 정보 모두를 반환하는게 좋다. toString을 구현할 ..