언어/JAVA

언어/JAVA

[Effective Java] 태그 달린 클래스보다는 클래스 계층구조를 활용하라

아이템 23 : 태그 달린 클래스보다는 클래스 계층구조를 활용하라 두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스가 있다. 태그 달린 클래스에는 단점이 한가득이다. 우선 열거 타입 선언, 태그 필드, switch 문 등 쓸데없는 코드가 많다. 여러 구현이 한 클래스에 혼합돼 있어서 가독성도 나쁘다. 다른 의미를 위한 코드도 언제나 함께 하니 메모리도 많이 사용한다. 필드들을 final로 선언하려면 해당 의미에 쓰이지 않는 필드들까지 생성자에서 초기화해야 한다. 한마디로, 태그 달린 클래스는 장황하고, 오류를 내기 쉽고, 비효율적이다. 다행히 자바와 같은 객체 지향 언어는 타입 하나로 다양한 의미의 객체를 표현하는 훨씬 나은 수단을 제공한다. 바로 클래스 ..

언어/JAVA

[Effective Java] 인터페이스는 타입을 정의하는 용도로만 사용하라

아이템 22 : 인터페이스는 타입을 정의하는 용도로만 사용하라 인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 달리 말해, 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. 이 지침에 맞지 않는 예로 상수 인터페이스가 있다. 상수 인터페이스란 메서드 없이, 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. 아래 코드는 상수 인터페이스 안티패턴이다. 1 2 3 4 5 6 7 8 public interface PhysicalConstants { static final double AVOGADROS_NUMBER = 6.022_140_857..

언어/JAVA

[Effective Java] 인터페이스는 구현하는 쪽을 생각해 설계하라

아이템 21 : 인터페이스는 구현하는 쪽을 생각해 설계하라 자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었다. 인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 나는데, 추가된 메서드가 우연히 기존 구현체에 이미 존재할 가능성은 아주 낮기 때문이다. 자바 8에서는 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가되었다. 주로 람다를 활요하기 위해서다. 자바 라이브러리의 디폴트 메서드는 코드 품질이 높고 범용적이라 대부분 상황에서 잘 작동한다. 하지만 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려운 법이다. 디폴트 메서드는 (컴파일에 성공하더라도) 기존 구현체에 런타임 오류를 일으킬 수 있다. 흔한 일은 아니지만, 일어나지..

언어/JAVA

[Effective Java] 추상 클래스보다는 인터페이스를 우선하라

아이템 20 : 추상 클래스보다는 인터페이스를 우선하라 기존 클래스에소 손쉽게 새로운 인터페이스를 구현해넣을 수 있다. 인터페이스가 요구하는 메서드를 추가하고, 클래스 선언에 implements 구문만 추가하면 끝이다. 인터페이스는 믹스인 정의에 안성맞춤이다. 믹스인이란 클래스가 구현할 수 있는 타입으로, 믹스인을 구현한 클래스에 원래의 '주된 타입' 외에도 특정 선택적 행위를 제공한다고 선언하는 효과를 준다. 인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다. 타입을 계층적으로 정의하면 수많은 개념을 구조적으로 잘 표현할 수 있지만, 현실에는 계층을 엄격히 구분하기 어려운 개념도 있다. 인터페이스는 래퍼 클래스 관용구와 함께 사용하면 기능을 향상시키는 안전하고 강력한 수단이 된다. 타입을 ..

언어/JAVA

[Effective Java] 상속을 고려해 설계하고 문서화하라. 그렇지 않았다면 상속을 금지하라

아이템 19 : 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야 한다. 달리 말하면, 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 하지만 내부 메커니즘을 문서로 남기는 것만이 상속을 위한 설계의 전부는 아니다. 효율적인 하위 클래스를 큰 어려움 없이 만들 수 있게 하려면 클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있다. 드물게는 protected 필드로 공개해야 할 수도 있다. 상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 '유일'하다. 널리 쓰일 클래스를 상..

언어/JAVA

[Effective Java] 상속보다는 컴포지션을 사용하라

아이템 18 : 상속보다는 컴포지션을 사용하라 상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다. 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다. 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 다르게 말하면, 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다. 기존 클래스를 확장하는 대신, 새로운 클래스를 만들고 private 필드로 기존 클래스의 인스턴스를 참조하게 하자. 기존 클래스가 새로운 클래스의 구성요소로 쓰인다는 뜻에서 이러한 설계를 컴포지션 구성이라 한다. 새 클래스의 인스턴스 메서드들은 기존 클래스의 대응하는 메서드를 호출해 그 결과를 반환한다. 이 방식을 전달이라 하며, 새 클래스의 메서드들을 전달 메서드라 부른다. 그 결과 새로운..

언어/JAVA

[Effective Java] 변경 가능성을 최소화하라

아이템 17 : 변경 가능성을 최소화하라 불변 클래스란 간단히 말해 그 인스턴스의 내부 값을 수정할 수 없는 클래스다. 클래스를 불변으로 만들려면 다음 다섯 가지 규칙을 따르면 된다. 객체의 상태를 변경하는 메서드를 제공하지 않는다. 클래스를 확장할 수 없도록 한다. 모든 필드를 final로 선언한다. 모든 필드를 private으로 선언한다. 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 불변 객체는 단순하다. 불변 객체는 생성된 시점의 상태를 파괴될 때까지 그대로 간직한다. 또한 불변 객체는 근복적으로 스레드 안전하여 따로 동기화할 필요가 없다. 불변 객체에 대해서는 그 어떤 스레드도 다른 스레드에 영향을 줄 수 없으니 불변 객체는 안심하고 공유할 수 있다. 불변 객체는 자유롭게 공유할 ..

언어/JAVA

[Effective Java] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

아이템 16 : public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 패키지 바깥에서 접근할 수 있는 클래스라면 접근자를 제공함으로써 클래스 내부 표현 방식을 언제든 바꿀 수 있는 유연성을 얻을 수 있다. public 클래스가 필드를 공개하면 이를 사용하는 클라이언트가 생겨날 것이므로 내부 표현 방식을 마음대로 바꿀 수 없게 된다. package-private 클래스 혹은 pirvate 중첩 클래스라면 데이터 필드를 노출한다 해도 하등의 문제가 없다. 그 클래스가 표현하려는 추상 개념만 올바르게 표현해주면 된다. 핵심 정리 public 클래스는 절대 가변 필드를 직접 노출해서는 안 된다. 불변 필드라면 노출해도 덜 위험하지만 완전히 안심할 수는 없다. 하지만 package-priva..

언어/JAVA

[Effective Java] 클래스와 멤버의 접근 권한을 최소화하라

아이템 15 : 클래스와 멤버의 접근 권한을 최소화하라 정보 은닉의 장점은 정말 많다. 그중 대부분은 시스템을 구성하는 컴포넌트들을 서로 독립시켜서 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있게 해주는 것과 연관되어 있다. 정보 은닉의 장점을 구체적으로 한번 알아보자. 시스템 개발 속도를 높인다. 여러 컴포넌트를 병렬로 개발할 수 있기 때문이다. 시스템 관리 비용을 낮춘다. 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문이다. 정보 은닉 자체가 성능을 높여주지는 않지만, 성능 최적화에 도움을 준다. 완성된 시스템을 프로파일링해 최적화할 컴포넌트를 정한 다음 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화할 수 있기 때문이다. ..

언어/JAVA

[Effective Java] Comparable을 구현할지 고려하라

아이템 14 : Comparable을 구현할지 고려하라 compareTo 메서드의 일반 규약은 equals의 규약과 비슷하다. Comparable을 구현한 클래스는 모든 x,y에 대해 sgn(x.compareTo(y)) == -sgn(y.compareTo(x))여야 한다(따라서 x.compareTo(y)는 y.compareTo(x)가 예외를 던질 때에 한해 예외를 던져야 한다). Comparable을 구현한 클래스는 추이성을 보장해야 한다. 즉, (x.compareTo(y) > 0 && y.compareTo(z) > 0)이면 x.compareTo(z) > 0이다. Comparable을 구현한 클래스는 모든 z에 대한 x.compareTo(y) == 0 이면 sgn(x.compareTo(z)) == sgn..

지나가던 개발자
'언어/JAVA' 카테고리의 글 목록 (3 Page)