분류 전체보기

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

    자바에서 제공하는 다주우 구현 메커니즘 인터페이스 추상 클래스 자바 8 이후에 인터페이스도 디폴트 메서드를 제공할 수 있게 되어 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 상속을 통해 하위 클래스가 되어야 된다라는 말인거 같다. 자바는 단일 상속만 지원 추상 클래스 방식은 새로운 타입을 정의하는 데 제약을 안게 되는 셈이다. 하위 클래스가 되어야 하는 제약 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 차이점 정리 추상 클래스를 구현한 클래스는 하위 클래스가 되는 제약을 갖는다. 인터페이스는 ..

    [Item 19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

    [Item 19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

    상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 앞서 item 18에서 HashSet 클래스를 상속하여 add를 재정의 한 것이 addAll 까지 영향을 준다는 사실을 알 수 없었다. 이러한 문제점을 문서화하여 주석처리만 해줘도 add 메서드로 내부 구현이 되있구나 라는 것을 알 수 있다. 좋은 문서화는 무엇일까? 문서화를 좋게 작성 하려면 어떻게가 아닌 무엇을 하는지를 설명해야한다. 즉, 내부 구현 방식을 설명해야 한다. 효율적인 하위 클래스를 만들려면? 클래스 내부 동작 과정 중간에 끼어들 수 있는 훅(hook)을 잘 선변하여 protected 메서드 형태로 공개해야 할 수 도 있다. java.util.AbstractList 의 removeRange 메서..

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

    코드를 재사용하는데 상속은 강력한 수단이다. 하지만 항상 재사용하는데에 있어 좋은 것은 아니다. 같은 패키지 내에서 상위 클래스와 하위 클래스를 모두 통제한다면 좋지만 다른 패키지 내에서 상속을 한다면 관리가 쉽지 않을 것이다. 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 상위 클래스를 확장을 고려하지 않고 설계하면 하위 클래스에서 에러가 날 수 있기에 충분히 고려해서 설계하자. HashSet을 잘못 상속한 코드 예 @Getter @NoArgsConstructor @AllArgsConstructor public class InstrumentedHashSet extends HashSet { private int addCount = 0; @Override public boolean add(E e) { ad..

    [Item 17] 변경 가능성을 최소화 하라

    불변 클래스란 그 인스턴스의 내부 값을 수정할 수 없는 클래스다. 불변 인스턴스가 가지고 있는 정보는 고정되어 객체가 파괴되는 순간까지 달라지지 않는다. 자바 라이브러리에도 다양한 불변 클래스가 있다. String 기본 타입의 박싱된 클래스 BigInteger BigDecimal 가변 클래스보다 설계와 구현이 쉬우며 오류가 생길 여지도 적고 안전하다. 불변 클래스를 만드는 다섯가지 규칙 객체의 상태를 변경하는 메서드를 제공하지 않는다 setter() 메서드를 예를 들 수 있겠다. 클래스를 확장할 수 없도록 한다. final 키워드를 사용한다. 모든 필드를 final로 선언한다. 새로 생성된 인스턴스를 동기화 없이 다른 스레드로 건네도 문제없이 동작하게끔 보장하는 데 필요 모든 필드를 private 으로 ..

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

    객체 지향 프로그램은 public 클래스에 public 필드를 사용하는 것은 위험한 일이다. private 으로 변경하고 이를 제공 할 접근자를 추가한다. 접근자는 getter() 이다. 아래 코드는 lombok으로 대체 했다. @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Point { // public 필드 말고 private 필드를 사용하고 접근자를 추가하여 사용하자 private int x; private int y; } 접근자를 제공함으로써 클래스 내부 표현 방식을 언제들 바꿀수 있는 유연성을 제공한다. package-private(default) 클래스 혹은 private 중첩 클래스라면 데이터 필드를 노출할 때가 좋을..

    ModelMapper

    ModelMapper

    [Spring] ModelMapper ModelMapper는 엔티티와 DTO 간에 변환 시 자동으로 Object를 매핑시켜주는 라이브러리다. 기본적으로 제공해주는 map() 메서드로 소스로 제공 할 object와 매핑할려는 object를 매개 변수로 받는다. 아래와 같은 UserSaveRequestDto 라는 DTO 가 있다. @Data @NoArgsConstructor public class UserSaveRequestDto { ....// 코드 생략 } 이를 User 엔티티로 매핑을 시켜주고 싶을 때 modelMapper 를 사용한다. @Getter @Entity @Table(name = "users") @NoArgsConstructor(access = AccessLevel.PROTECTED) @To..

    [Git] 변경 사항 확인

    [Git] 변경 사항 확인

    -p 옵션은 커밋과 커밋 사이의 변경된 소스의 차이점을 확인할 수 있다. git log -p 커밋한 내용은 고유한 값을 가지고 있다. 내가 원하는 커밋의 버전과 버전사이의 소스코드를 비교해보고 싶다면 diff 명령어 를 사용하자 git diff 커밋주소값..커밋주소값

    [Git] commit 도전

    [Git] commit 도전

    작업을 누가하고 커밋을 누가 찍었는지의 정보를 설정해봅시다. git config --global user.name "name" git config --global user.email "email" 이 명령어는 깃을 처음 시작시에 한번만 설정하면 된다. 앞서 깃에게 hello.txt 파일을 버전 관리 하라고 add 명령어를 입력했다. 그러면 이제 commit을 찍을 수 있다. commit을 한번 해보자. git commit hello.txt vim 파일이 실행되고 insert 모드로 변환 후 커밋 메시지를 적어주고 저장을 한다. 위의 방법은 vim 파일을 실행하여 안에서 메시지 작성을 하는데 아래와 같은 명령어 옵션으로 커밋 메시지를 작성할 수 있다. git commit hello.txt -m "versi..

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

    어설프게 설계한 컴포넌트와 잘 설계된 컴포넌트의 차이점은 내부 데이터를 얼마나 잘 숨겼냐에 따른다. 캡슐화 혹은 정보 은닉이 설계의 기반이되는 원리이다. 캡슐화의 장점 여러 컴포넌트를 병렬로 개발이 가능하므로 시스템 개발 속도를 높인다. 각 컴포넌트를 빠르게 파악할 수 있고 시스템 교체하는 부담도 적기 때문에 시스템 관리 비용을 낮춘다. 캡슐화 자체만으로 성능을 높여주지 않지만 각 컴포넌트에 영향을 주지 않고 해당 컴포넌트만을 최적화 할 수 있기 때문에 성능 최적화에 도움을 준다. 소프트웨어 재사용을 높인다. 개발 난이도를 낮춰준다. 캡슐화의 접근성은 접근제어자로 정해진다. 기본원칙 모든 클래스와 멤버의 접근성을 가능한 한 좁혀야 한다. 패키지 외부에서 쓸 이유가 없으면 package-private으로 ..

    [Git] init, add

    mkdir 명령어로 git 파일을 관리해주는 디렉토리 생성해준다. mkdir -p gitfth -pv 옵션에서 p는 상위 디렉토리안에 하위 디렉토리를 생성할 때 붙여주는 옵션이다. -v옵션은 디렉토리 생성 정보를 상세하게 출력해주고 디렉토리를 생성해준다. 생성한 디렉토리로 진입 한다. cd gitfth git 파일을 init 명령어로 생성해준다. git init 생성된 파일을 확인해준다. .git파일이 생성되면 성공이다. ls -al -a 옵션은 all의 줄임말로 모든 파일(숨김 파일 및 디렉터리 포함) 형식을 출력한다. -l 옵션은 long의 줄임말로 파일 출력 형식을 긴 목록 형식으로 출력한다. -al 옵션을 조합하여 사용한다. 이제는 내가 관리 해 주어야 되는 파일을 생성 해보자. vim hello..

    [Item 14] Comparable을 구현할지 고려하라

    CompareTo는 동치성 비교에 순서까지 비교할 수 있으며 제네릭 하다. Comparable을 구현했다는 것은 해당 클래스의 순서가 있음을 뜻한다. Arrays의 클래스는 Comparable을 구현하여 아래와 같이 손쉽게 정렬할 수 있다. Arrays.sort(arr); 검색, 극단값 계산, 자동 정렬되는 컬렉션 관리도 쉽게 할 수 있다. 자바의 라이브러리의 모든 값 클래스와 열거타입이 Comparable을 구현했다. 알파벳, 숫자, 연대 같이 순서가 명확한 값 클래스를 작성한다면 반드시 Comparable을 구현하자. comparTo 메서드 규약 이 객체와 주어진 객체의 순서를 비교한다. 이 객체가 주어진 객체보다 작으면 음의 정수, 같으면 0, 크면 양의 정수를 반환한다. 객체와 비교할 수 없는 타..

    [Jpa] Dirty Checking

    [Jpa] Dirty Checking

    엔티티를 수정하고 repository에서 save를 안했는데 update 쿼리가 발생하는 현상을 본적이 있을 것이다. 이를 더티 체킹이라 하는데 트랜잭션 단위에서 엔티티를 가져와 영속 상태로 만들고 엔티티의 update메서드를 이용해 속성을 변경해준 다음 트랜잭션이 끝나는 시점에 변경을 감지하여 update 쿼리가 동작한다. 다음 코드는 더티 체킹이 동작하는 코드다. @Transactional public PostSaveResponseDto updateByIdPost(Long postId, PostUpdateRequestDto postUpdateRequestDto) { Post post = getEntity(postId); post.updateEntity(postUpdateRequestDto); retu..

    [Jpa] Projections

    [Jpa] Projections

    아래와 같은 엔티티의 조회 시도를 하려고 한다. select 문을 날리면 해당 엔티티의 속성들이 모두 조회가 될 것이다. 속성들이 이보다 더 많다면 아마 성능에 문제가 되지 않을까 싶다. 그래서 해당 속성만 뽑아내려고 시도 해봤다. public class Post { private Long id; private String userName; private String title; private String description; private LocalDateTime createDateTime; private LocalDateTime updateDateTime; } 당연히 받는 타입은 PostDto로 title 과 description 만 받게 해 놓았다. @Query("select p.title, p...

    [Java] Decorator Pattern

    [Java] Decorator Pattern

    데코레이터 패턴은 디자인 패턴 중 하나이다. 데코레이터 패턴을 사용하여 정적으로 또는 동적으로 객체에 추가 책임을 추가할 수 있다. 데코레이터는 원래 객체에 대한 향상된 인터페이스를 제공한다. 이 패턴을 구현할 시 상속보단 구성을 위주로 각 데코리에터 요소에 대해 반복해서 상속하는 오버헤드를 줄일 수 있다. 코테를 준비하시는 분이시라면 아래와 같은 코드를 작성 해본적이 있을 것이다. BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 기반 스트림으로 읽고 보조 스트림으로 추가적인 기능을 제공하는 구조로 테코레이터 패턴의 대표적인 예시가 된다. 이는 객체의 결합을 통해 기능을 동적으로 유연하게 확장할 수 있는 장점이 있다. 크..

    [Java] Exception

    [Java] Exception

    예외 처리의 중요성 비정상 종료를 방지 로그를 잘 기록하여 버그의 상황이 어떤 것인지 확인 아래 예제 코드를 보면 예외 처리의 중요성을 잘 알게 될 것이다. int[] arr = new int[10]; try { for (int i = 0; i < arr.length + 1; i++) { arr[i] = i; } } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); String message = e.getMessage(); System.out.println(message); } // 예외를 처리하고 정상 수행이 된다. // 비정상 종료가 되지 않는다. System.out.println(Arrays.toString(arr)); 배열의 길이에 ..