본문 바로가기

STUDY/이펙티브자바

(44)
4-6) 추상 클래스보다는 인터페이스를 우선하라 추상 클래스와 인터페이스 자바에서는 코드의 재사용성을 높이기 위해 공통으로 쓰일 수 있는 내용들을 상속해서 사용하도록 추상 클래스나 인터페이스로 정의할 수 있다. 추상 클래와 인터페이스 모두 상속을 위해 만들어진 것으로 그 자체로 인스턴스를 만들 수 없다. 그리고 추상 클래스나 인터페이스에 존재하는 추상 메소드는 상속/구현하는 하위 클래스에서 구현해야 한다. 이 둘은 비슷한 역할을 하고 있지만 차이점도 존재한다. 먼저 추상 클래스는 일반 메소드도 가질 수 있고 멤버 변수도 가질 수 있다. 하지만 단일 추상클래스만을 상속 시킬 수 있다. 인터페이스는 추상 메소드만을 가져야하고 멤버변수를 가질 수 없지만 다중상속을 시킬 수 있다. 인터페이스와 믹스인 정의 // 비교 기능(Comparable)과 반복 기능(I..
4-5) 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 상속을 고려한 문서화 public abstract class AbstractCollection implements Collection { ... /** * {@inheritDoc} * * @implSpec * This implementation iterates over the collection looking for the * specified element. If it finds the element, it removes the element * from the collection using the iterator's remove method. * * Note that this implementation throws an * {@code UnsupportedOperationException} if th..
4-4) 상속보다는 컴포지션을 사용하라 상속 상속은 코드의 재사용성을 올려주고 유연한 개발을 가능하게 해주는 강력한 수단이다. 하지만 상속은 캡슐화를 깨뜨린다는 문제가 있다. 캡슐화는 클래스의 필드와 메소드의 동작방식을 외부에 숨기는 것을 말한다. 이를 통해 클래스와 외부 사용자는 서로에 대한 독립성을 가지고 서로에 대한 영향을 최소화할 수 있다. 하지만 상위 클래스를 상속받은 하위클래스는 상위클래스의 구현방식이 바뀌면 그에 따라 영향을 받는다. public class InstrumentedHashSet extends HashSet { private int addCount = 0; public InstrumentedHashSet() { } public InstrumentedHashSet(int initCap, float loadFactor) ..
4-3) 변경 가능성을 최소화하라 불변 클래스 불변 클래스란 인스턴스 내부 값을 수정할 수 없는 클래스를 말한다. Java에서는 String, BigInteger, BigDecimal 등 여러 클래스가 불변 클래스로 설계되었다. 불변 클래스 방식은 설계 및 구현이 쉽고 사용하기에도 쉽다. 또 오류가 생길 여지도 적어서 훨씬 안전하다. 이러한 장점을 가진 불변 클래스를 만들기 위해서는 다음 다섯가지 규칙을 따르면 된다. 1. 객체의 상태를 변경하는 메소드를 제공하지 않는다. 2. 클래스를 확장할 수 없도록 한다. 3. 모든 필드를 final로 선언한다. 4. 모든 필드를 private로 선언한다. 5. 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 불변 복소수 클래스 public final class Complex { pri..
4-2) public 클래스에서는 public 필드가 아닌 접근자 메소드를 사용하라 접근자 메소드 // Point 클래스의 x, y 값은 아무곳에서나 접근 가능하고 // 그 결과 x, y에 대한 관리 책임은 Point가 가지고있지 않는다. class Point { public double x; public double y; } 위 Point 클래스는 x, y 좌표를 나타내는 실수형 필드를 가지고 있다. 정말 그뿐이다. 연관된 정보를 모아둔 것 이외의 역할을 하지않는 C언어 시절의 클래스이다. OOP의 철학을 따르는 Java의 개발자라면 이런 퇴보한 클래스는 만들면 안된다. Point 클래스를 만들었다면 x, y 값에 대한 책임도 함께 가지고 있는 클래스를 만들어야 한다. // x, y의 값은 Point 클래스 내부에서만 수정하기때문에 // x, y에 대한 관리책임은 Point 클래스에 ..
4-1) 클래스와 멤버의 접근 권한을 최소화하라 캡슐화(정보 은닉) 잘 만들어진 컴포넌트의 특징 중 하나는 내부 구현 내용을 외부에 잘 숨긴다는 것이다. 외부의 사용자는 내부의 구현에 신경쓰지 않고 컴포넌트를 사용한다. 이는 OOP와 소프트웨어 설계의 기본이 캡슐화(정보 은닉)와 같은 뜻이다. 캡슐화는 내부의 상태나 정보를 외부에서 접근할수 없도록 하여 감추는 것인데, 이렇게 하면 여러 장점을 얻을 수 있다. 1. 시스템 개발 속도를 높인다 > 여러 컴포넌트를 병렬로 개발 할 수 있다. 2. 시스템 관리 비용을 낮춘다 > 디버깅 하기 쉽고, 컴포넌트 교체 부담도 적다. 3. 성능 최적화에 좋다 > 내부 컴포넌트의 코드 수정이 외부 컴포넌트에 주는 영향이 적기 때문에 성능최적화 하기에 좋다. 4. 소프트웨어 재사용성을 높인다 > 캡슐화(정보은닉)을 지킨..
3-5) Comparable을 구현할지 고려하라 Comparable 인터페이스, compareTo 메소드 public class Customer implements Comparable { private int customerId; ... @Override public int compareTo(Customer o) { return Integer.compare(this.customerId, o.customerId); } ... } // customerList가 customerId 기준으로 정렬된다. Arrays.sort(customerList); Comparable 인터페이스는 compareTo 메소드를 가지고있다. compareTo 메소드는 두 객체를 비교하고 그 결과를 반환한다. 얼핏 equals 메소드와 비슷해 보일 수 있지만, equals는 두 객..
3-4) clone 재정의는 주의해서 진행하라 clone 메소드와 Cloneable 인터페이스 public class MyClass{ ... } // 컴파일 에러, clone 메소드를 찾을 수 없다. myClass.clone(); public class MyClass{ ... public MyClass clone() throws CloneNotSupportedException { return super.clone(); } ... } // 런타임 에러, CloneNotSupportedException 발생 myClass.clone(); public class MyClass implements Cloneable{ ... public MyClass clone() throws CloneNotSupportedException { return super.clo..