상속을 위한 문서화 상속을 위한 문서화란 상속이 가능한 클래스의 재정의 가능 메서드에 해당 메서드를 내부적으로 어떻게 이용하고 있는지, 그래서 어떤 식으로 동작하도록 구현되어야 하는지 문서로 남겨두는 것을 말한다. 이렇게 해야 하는 이유는 클래스를 상속받아 구현된 클래스에서 해당 메서드를 부모 클래스에서의 의도와 다르게 구현할 경우 의도치 않은 동작으로 이어질 수 있기 때문이다. 자바 API에서는 이러한 문서를 Implementation Requirements (코드에선 @ImplSpec)라는 항목으로 문서화하여 제공하고 있다. 아래는 AbstractCollection.remove() 메서드 일부이다. 이를 통해 Abstract iterator()가 반환하는 Iterator의 remove() 동작을 임의..
아이템 13에서는 객체의 복제를 위해 사용하는 Object.clone() 메서드를 제대로 재정의하기 위해서는 어떻게 해야 하는지에 대해 설명하고 있다. 또한, Object.clone() 이 동작하도록 하기 위해 구현해야 하는 Cloneable 인터페이스의 문제점에 대해 이야기하고 결론적으로는 새로운 인터페이스/클래스는 절대 Cloneable을 확장/구현하면 안 되고, 객체의 복제 기능을 구현하기 위해서는 생성자와 팩토리를 사용해야 한다는 조언을 하고 있다. Object.clone()과 Cloneable의 동작 방식 먼저 이 메서드의 동작 방식에 대해 알아보자. 일반적인 경우와 달리 이 메서드는 선언은 Object 클래스에 되어있지만 빈 인터페이스인 Cloneable을 구현해야만 제대로 작동하도록 설계되어..
아이템 10번은 equals를 재정의할 때 지켜야 할 규칙들과 주의해야 하는 점들에 대해 설명하고 있다. 자바에서 equals()를 재정의하지 않으면 오직 자기 자신의 인스턴스와만 같게 되기 때문에 필요한 경우 equals() 메서드를 재정의해서 사용해야 한다. 책에서는 equals가 만족해야 하는 규칙들 모두에 대해 상황을 제시해 예제 코드로 설명하고 있지만 이를 모두 정리할 필요는 없을 것 같아 중요한 내용만 옮겼으니 자세한 내용은 책을 참고하시길 바랍니다. equals가 필요 없는 상황 equals() 를 재정의해서 불필요한 문제가 발생할 수도 있으므로 아래의 경우에 해당된다면 equals()를 아예 재정의하지 않는 것도 좋은 방법이다. 이 경우 기본 Object.equals() 가 호출되어 (주소..
개요 자바는 가비지 컬렉터가 있으므로 메모리 관리에 전혀 신경쓰지 않아도 된다고 생각하지만 이는 사실이 아니다! 예를 들어 스택을 아래와 같이 구현하면 지속적인 메모리 누수가 발생해 프로그램이 종료될 수도 있다. public class Stack { private Object[] elements; private int size = 0; // 생성자 public void push(Object obj) { ensureCapacity(); // 배열이 모자라면 늘리기 elements[size++] = obj; } public Object pop() { if (size == 0) { throw new EmptyStackException(); } return elements[--size]; } } 위와 같은 스택..
개요 정적 메서드와 정적 필드만을 담은 클래스는 객체 지향적으로 보이지 않긴하지만 자바 API의 Arrays나 Collections가 그런 것처럼 특정 인터페이스를 구현하는 객체의 정적 팩토리 메서드를 넣어둘 수도 있고 (자바 8부터는 인터페이스에서도 가능) 상속이 불가능한 final 클래스와 관련된 메서드를 구현하고 모아둘 때도 사용한다. 이러한 클래스는 인스턴스로 만들어 쓰려고 설계한게 아니다. 하지만 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어준다. 컴파일 전 public class UtilClass { private static int value = 0; public static int getValue() { return value; } } 컴파일 후 public class ..
정적 팩토리 메서드란 정적 팩토리 메서드는 클래스에서 인스턴스를 생성하는 용도로 생성자와 별도로 제공할 수 있는 또 다른 수단이다. 예를 들어 Boolean 클래스의 경우 아래와 같이 인스턴스를 생성할 수 있는 정적 팩토리 메서드를 제공한다. public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; } 정적 팩토리 메서드의 장점 그럼 생성자 대신 정적 팩토리 메서드를 사용할 때 어떤 장점이 있을까? 책에서는 크게 5가지를 제시한다. 이름을 가질 수 있다. 인스턴스를 생성하는 메서드가 이름을 가지게 되면 반환될 객체의 특성을 쉽고 정확하게 묘사할 수 있다는 장점이 생긴다. 예를 들어 BigInteger의 proba..
추상화 기법 추상화 -> 도메인의 복잡성을 단순화하고 직관적 멘탈 모델을 만드는 데 사용할 수 있는 가장 기본적인 인지 수단 추상화 기법들은 복잡성을 낮추기 위해 사물의 특정한 측면을 감춘다 동일한 추상화 기법을 프로그램의 분석, 설계, 구현 단계에 걸쳐 일관성 있게 적용할 수 있다는 것이 객체지향이 갖는 장점 1. 분류와 인스턴스화 개념과 범주 객체를 분류하고 범주로 묶는 것은 객체들의 특정 집합에 공통의 개념을 적용하는 것을 의미함 분류 -> 세상에 존재하는 객체에 개념(타입)을 적용하는 과정 즉, 객체를 타입(개념)과 연관시키는 것 타입 객체가 타입에 속하는지 검증하기 위해 필요한 타입의 정의 3가지 심볼(타입의 이름), 내연(타입의 정의), 외연(타입에 속하는 객체들의 집합) 외연과 집합 외연은 ..
객체지향 설계 안에 존재하는 세 가지 상호 연관된 관점 개념 관점 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현 실제 도메인의 규칙과 제약을 최대한 유사하게 반영 명세 관점 소프트웨어로 초점이 옮겨짐 살아 움직이는 객체들의 책임에 초점. 즉, 객체의 인터페이스를 바라보게 됨 '무엇'을 할 수 있는가에 초점 구현 관점 실제 작업을 수행하는 코드와 연관 객체의 책임을 '어떻게' 수행할 것인가에 초점을 두고 필요한 속성과 메서드를 클래스에 추가 위 3가지 관점은 시간 순이 아니며, 동일한 클래스를 세 가지 다른 방향에서 바라보는 것을 의미 하나의 클래스 안에 세 가지 관점을 모두 포함하면서도 각 관점에 대응되는 요소를 명확하고 깔끔하게 드러낼 수 있어야 한다! 도메인 모델 -> 최종 코드 구현 과정 ..
기능을 중심으로 구조를 종속시키는 적근법은 범용적이지 않고 재사용이 불가능하며 변경에 취약한 모델을 낳게 된다. 이와 달리 안정적인 구조를 중심으로 기능을 종속시키는 접근법은 범용적이고 재사용 가능하며 변경에 유연하게 대처할 수 있는 모델을 만든다. (중략) 자주 변경되는 기능이 아니라 안정적인 구조를 따라 역할, 책임, 협력을 구성하라. (p.180) 기능 설계 vs 구조 설계 성공적인 소프트웨어 -> 사용자가 원하는 새로운 기능을 빠르고 안정적으로 추가할 수 있다 이는 훌륭한 구조가 뒷받침되어 있기에 가능한 것 비록 최종 사용자들은 내부 구조를 볼 수 없지만, 좋은 설계는 사용자의 요구사항을 빠르게 반영할 수 있기에 중요하다 설계라는 행위를 중요하게 만드는 것은 변경에 대한 필요성이다 설계를 하는 목..
자율적인 책임 자율적 객체 -> 스스로의 의지와 판단에 따라 각자 맡은 책임을 수행하는 객체 객체가 책임을 자율적으로 수행하기 위해선 -> 객체에게 할당되는 책임이 자율적이어야 한다 상세한 수준의 책임은 협력의 최종 목표는 만족시킬지 몰라도 객체가 가져야 하는 선택의 자유를 크게 훼손한다 이런 경우, 자신의 판단이 아닌 외부의 명령에 의존하게 된다 책임은 자율성을 보장할 수 있도록 포괄적이고 추상적이면서도 할 일을 명확하게 명시하는 것이어야 한다 '어떻게'가 아닌, '무엇'을 책임으로 사용하라 너무 추상적인 책임 단, 협력의 의도를 명확하게 표현하지 못할 정도로 추상적인 책임 역시 문제다 책임은 협력에 참여하는 의도를 명확하게 설명할 수 있는 수준 안에서 추상적이어야 한다 책임의 적합성은 협력이 무엇인지..