전체 글
-
toString을 항상 재정의하라JAVA/Effective java 2021. 1. 19. 12:30
Object의 기본 toString 메서드가 우리가 작성한 클래스에 적합한 문자열을 반환하는 경우는 거의 없다. 이 메서드는 단순히 클래스_이름@16진수로_표시한_해시코드 를 반환할 뿐이다. toString의 일반 규약에 따르면 '간결하면서 사람이 읽기 쉬운 형태의 유익한 정보'를 반환해야 한다. 이 같은 toString을 잘 구현한 클래스는 사용하기에 훨씬 즐겁고, 그 클래스를 사용한 시스템은 디버깅하기 쉽다. toString메서드는 객체를 println, printf, 문자열 연결, assert 구문에 넘길 때, 혹은 디버거가 객체를 출력할 때 자동으로 불리고 이는 직접 호출되지 않더라도 다른 어딘가에서 쓰일 거란 이야기이다. 또 작성한 객체를 참조하는 컴포넌트가 오류 메시지를 로깅할 때 자동으로 호..
-
equals를 재정의하려거든 hashCode도 재정의하라JAVA/Effective java 2021. 1. 14. 11:44
equals를 재정의한 클래스 모두에서 hashCOde도 재정의해야 한다. 그렇지 않는다면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. equals(Object0가 두 객체를 같다고 판단했다면 두 객체의 hashCode는 똑같은 값을 반환해야 하며 equals(Object) 가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode가 서로 다른 값을 반환할 필요는 없다. 단, 다른 객체에 대해서는 다른 값을 반환해야 해시 테이블의 성능이 좋아진다. 이 코드의 답은 null을 반환한다. PhoneNumber 클래스는 hashCode를 재정의하지 않았기 때문에 논리적 동치인 두 객체가 서로 다른..
-
DDD - Dependency Injection과 AOP 1부JAVA/DDD 2021. 1. 11. 19:29
애플리케이션의 모든 기억들은 종료되는 순간 깨끗하게 증발돼 버리고 만다. 애플리케이션은 상태를 끊임없이 기록하고, 기억을 재생하고, 현실을 재구성해야 한다. 유효 시간이 지나고 단기 기억 상실증으로 인해 모든 기억이 소멸되더라도 기록을 통해 어플리케이션의 기억을 되돌릴 수 있어야 한다. 애플리케이션이 기억을 재생할 수 있다고 해서 모든 기억을 동시에 복구하는 것은 소모적인 일이다. 살아오면서겪은 모든 일들을 일일이 다 기억하고 있을 수는 없다. 애플리케이션 역시 마찬가지다. 지금 처리하기 위해 필요한 최소한의 정보만 기억하고 있으면 된다. 시스템의 메모리는 한정된 자원이다. 지금 당장 필요하지도 않은 정보들을 유지하기 위해 값비싼 자원을 낭비할 필요는 없다. 잠시 잊어 버렸다가 필요할 때 기록을 들춰 보..
-
equals는 일반 규약을 지켜 재정의 하라JAVA/Effective java 2021. 1. 11. 13:41
equals 메서드는 재정의하기 쉬워 보이지만 자칫 잘못된 결과를 초래할 수 있다. 따라서 가장 쉬운 길은 아예 재정의 하지 않는 것이다. 그냥 두면 그 클래스의 인스턴스는 오직 자신과만 같게 된다. 따라서 다음 열거한 상황 중 하나에 해당되면 재정의하지 않는 것이 최선이다. 1. 각 인스턴스가 본질적으로 고유할 때 값을 표현하는 게 아닌 동작하는 개체를 표현하는 클래스, Thread 클래스는 하나의 좋은 예다. 2. '논리적 동치성'을 검사할 일이 없을 때 Object에 기본 equals는 객체를 식별하기 위해 주소 값을 비교한다. 만일 Pattern에 equals나 String에 equals 등 '논리적 동치성'의 경우가 없을 경우 재정의 하지 않아도 된다. 3. 상위 클래스에 재정의한 equals가..
-
AGGREGATE와 REPOSITORY 5부JAVA/DDD 2021. 1. 8. 19:48
ENTRY POINT와 REPOSITORY 주문은 주문 AGGREGATE의 ENTRY POINT이다. 따라서 주문이 필요한 경우 OrderRepository를 통해 해당 주문 객체를 얻을 수 있다. 그럼 특정한 고객에 대한 주문 목록을 얻어야 한다면 어떻게 해야 할까? 쉽게 생각해 볼 수 있는 방법은 CustomerRepository로부터 고객 객체를 얻은 후 연관을 통해 해당하는 Order 객체들에게 접근하는 것이다. 그러나 이 방법은 Order와 Customer 클래스 간에 양방향 연관 관계를 추가한다. 특정 객체에 속하는 다른 객체들을 조회하는 요구사항마다 양방향 연관 관계를 설정한다면 감당하기 어려울 정도로 모델이 복잡해질 것이다. 고객에 해당하는 주문 목록을 조회하는 적절한 방법은 OrderRe..
-
AGGREGATE와 REPOSITORY 4부JAVA/DDD 2021. 1. 5. 16:39
OrderLineItem은 상품 정보를 알고 있는 책임을 지닌 Product 클래스와 연관 관계를 가지며, 상품의 수량을 속성으로 포함한다. OrderLineItem의 생성자에 전달된 productName은 Product ENTRY POINT를 검색하기 위해 사용하는 검색 키이다. Product은 REFERENCE OBJECT인 동시에 ENTRY POINT이므로 productName을 가지는 Product 인스턴스는 시스템 내에서 유일해야 한다. 따라서 Product를 관리하는 ProductRepository로부터 해당 인스턴스를 얻어 OrderLineItem의 product 속성에 할당한다. getPrice() 메서드는 현재 주문 항목의 가격을 반환하는 메서드로 상품 가격에 상품 수량을 곱한 금액을 반..
-
Try-Finally 대신 Try-with-Resource 사용하라JAVA/Effective java 2021. 1. 4. 10:31
자바 라이브러리에는 InputStream, OutputStream 그리고 java.sql.Connection과 같이 정리(close)가 가능한 리소스가 많다. 하지만 그런 리소스를 사용하는 클라이언트 코드가 보통 리소스 정리를 잘 안 하거나 잘못하는 경우가 있다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class FirstError extends RuntimeException { } public class SecondException extends RuntimeException { } public class MyResource implements AutoCloseable { public void doSomething() throws FirstEr..
-
Finalizer와 Cleaner는 피하라JAVA/Effective java 2021. 1. 3. 23:16
Finalizer는 예측 불가능하고, 위험하며, 대부분 불필요하다. 그걸 쓰면 이상하게 동작하기도 하고, 성능도 안 좋아지고, 이식성에도 문제가 생길 수 있다. Finalizer를 유용하게 쓸 수 있는 경우는 극히 드물다. finalizer는 GC가 돌때 호출이 되는데 언제 호출되는지 예측할 수 없다. GC에 대상이 된다고 해서 바로 GC가 되는 것이 아니기 때문이다. 다음의 코드는 run() 실행 후 1초 있다가 종료되게 된다. run() 호출후의 finalizerExample의 레퍼런스는 유효하지 않게 되지만 실행해보면 Clean Up을 실행하지는 않는다. GC에 대상은 되지만 바로 되지는 않는다. 그럼 언제 써야 될까? 딱 두가지 경우 안전망 역할로 자원을 반납하고자 하는 경우. 네이티브 리소스를 ..