kkkkkkkkkkkk
kkkkk
kkkkkkkkkkkk
전체 방문자
오늘
어제
  • 분류 전체보기
    • CS & OS
    • Algorithms
    • Laguage
    • Book
      • 객체지향의 사실과 오해
      • Effective Java
      • Spring boot 와 AWS로 혼자 구현하는 ..
      • 도메인 주도 계발 시작하기
    • DB
    • Spring
    • Spring Boot
    • JPA
    • Git
    • Clean Code
    • HTTP

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 설계 원칙
  • 응집도
  • 책임
  • 객체지향 프로그래밍
  • 결합도
  • 역할

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
kkkkkkkkkkkk

kkkkk

Book/Effective Java

[Book] ITEM 4) private 생성자로 noninstantiability를 강제할 것

2022. 3. 1. 20:21

모든 클래스들이 인스턴스화가 필요한 것이 아닙니다.

static 메서드와 static 필드들을 담은 클래스들을 인스턴스화를 시키지 않아도 기능들을 사용 할 수 있는데 굳이 인스턴스화를 시킬 필요는 없다고 봅니다.

역직렬화 기능을 담은 클래스가 있다고 가정해봅시다.

public class ObjectDeSerialization{

    private static ByteArrayInputStream byteArrayInputStream;
    private static ObjectInputStream objectInputStream;

    public static byte[]makeByteDecodeArray(String encodeObject) {
        return Base64.getDecoder().decode(encodeObject);
    }

    public static Object makeDecodeObject(byte[]bytes)throws 예외생략 {
        byteArrayInputStream= new ByteArrayInputStream(bytes);
        objectInputStream= new ObjectInputStream(byteArrayInputStream);
        return objectInputStream.readObject();
    }
}

이러한 클래스는 굳이 인스턴스를 만들지 않아도 됩니다. static 메서드와 static 필드들을 담고 있는데 인스턴스를 만들 필요는 없습니다.

그러면 인스턴스화를 막는 방법은 무엇이 있을까요??

👻  private 생성자

첫번째 방법으로는 private 생성자 를 사용하는 방법이 있습니다.

하지만 reflection 기능으로 인스턴스를 생성하는 방법이 있었죠??

@Test
@DisplayName("역직렬화 인스턴스 생성 테스트")
void ObjectDeSerializationTest()throws 예외 생략{
    // given & when
    // reflection 사용
    Class<ObjectDeSerialization> objectDeSerializationClass = ObjectDeSerialization.class;
    Constructor<ObjectDeSerialization> declaredConstructor = objectDeSerializationClass.getDeclaredConstructor();
    declaredConstructor.setAccessible(true);
    ObjectDeSerialization objectDeSerialization = declaredConstructor.newInstance();

    // then
    assertThat(objectDeSerialization.getClass().getName()).isEqualTo(ObjectDeSerialization.class.getName());
}

그러면 예외를 던져 막아볼까요??

// 인스턴스 생성시에 AssertionError 예외 발생
private ObjectDeSerialization() {
    throw new AssertionError();
}

인스턴스 생성시에 private 생성자에 AssertionError 예외를 던졌으니 예외가 발생 될 것입니다.

@Test
@DisplayName("역직렬화 인스턴스 생성 테스트")
void ObjectDeSerializationTest()throws 예외 생략{
    // given & when
    // reflection 사용
    Class<ObjectDeSerialization> objectDeSerializationClass = ObjectDeSerialization.class;
    Constructor<ObjectDeSerialization> declaredConstructor = objectDeSerializationClass.getDeclaredConstructor();
    declaredConstructor.setAccessible(true);
    ObjectDeSerialization objectDeSerialization = declaredConstructor.newInstance();

    // then
    assertThat(objectDeSerialization.getClass().getName()).isEqualTo(ObjectDeSerialization.class.getName());
}

private 생성자를 사용한 경우 주석으로 왜 private 를 사용했는지 설명을 해야합니다.

// 인스턴스화를 막기위한 생성자입니다.
private ObjectDeSerialization() {
    throw new AssertionError();
}

👻  abstract Class

두번째 방법으로는 abstract 를 사용하여 인스턴스를 생성하는 것을 막을 수 있습니다.

public abstract class ObjectDeSerialization{

    private static ByteArrayInputStream byteArrayInputStream;
    private static ObjectInputStream objectInputStream;

    public static byte[]makeByteDecodeArray(String encodeObject) {
        return Base64.getDecoder().decode(encodeObject);
    }

    public static Object makeDecodeObject(byte[]bytes)throws IOException, ClassNotFoundException{
        byteArrayInputStream= new ByteArrayInputStream(bytes);
        objectInputStream= new ObjectInputStream(byteArrayInputStream);
        returnobjectInputStream.readObject();
    }
}

인스턴스를 생성할려고하면 컴파일 에러가 나옵니다.

@Test
@DisplayName("역직렬화 인스턴스 생성 테스트")
void ObjectDeSerializationTest() {
    // given & when & then
    ObjectDeSerialization objectDeSerialization = new ObjectDeSerialization(); // 컴파일 에러!!!

}

또한 reflection 기능으로 생성을 하면 InstantiationException 예외가 발생합니다.

@Test
@DisplayName("역직렬화 인스턴스 생성 테스트")
void ObjectDeSerializationTest()throws 예외 생략 {
    // given & when
    // reflection 사용
    Class<ObjectDeSerialization> objectDeSerializationClass = ObjectDeSerialization.class;
    Constructor<ObjectDeSerialization> declaredConstructor = objectDeSerializationClass.getDeclaredConstructor();
    declaredConstructor.setAccessible(true);

    // then
    assertThrows(InstantiationException.class,()-> declaredConstructor.newInstance());
}

private 생성자를 사용해서 인스턴스 생성을 막아도 좋지만 abstract 를 사용하여 인스턴스를 막는 것만으로 충분할 것 같다는 생각이듭니다.

'Book > Effective Java' 카테고리의 다른 글

[Book] ITEM 9) try-finally 대신 try-with-resource 를 사용하라  (0) 2022.03.19
[Book] ITEM 8) finalizer 와 cleaner는 피하라  (0) 2022.03.07
[Book] ITEM 7) 더이상 쓰지 않는 객체 레퍼런스는 없애자  (0) 2022.03.04
[Book] ITEM 6) 불필요한 객체는 만들지 말자  (0) 2022.03.03
[Book] ITEM 5) 리소스를 엮을 때는 의존성 주입을 선호하라  (0) 2022.03.03
[Book] ITEM 3) private 생성자 또는 enum 타입을 사용해서 싱글톤으로 만들것  (0) 2022.03.01
[Book] ITEM 2) 생성자의 매개변수가 많다면 빌더를 고려하라  (0) 2022.02.26
[Book] ITEM 1) 생성자 대신 정적 (static) 팩토리 메서드를 고려해 볼 것  (0) 2022.02.26
    'Book/Effective Java' 카테고리의 다른 글
    • [Book] ITEM 6) 불필요한 객체는 만들지 말자
    • [Book] ITEM 5) 리소스를 엮을 때는 의존성 주입을 선호하라
    • [Book] ITEM 3) private 생성자 또는 enum 타입을 사용해서 싱글톤으로 만들것
    • [Book] ITEM 2) 생성자의 매개변수가 많다면 빌더를 고려하라
    kkkkkkkkkkkk
    kkkkkkkkkkkk

    티스토리툴바