본문 바로가기
책/이펙티브 코틀린

2부 코드설계 > 5장 객체 생성

by 정선한 2022. 9. 27.
728x90
반응형
2부 코드설계 > 5장 객체 생성 > 생성자 대신 팩토리 함수를 사용하라.
2부 코드설계 > 5장 객체 생성 > 기본 생성자에 이름 있는 옵션 아규먼트를 사용하라.
2부 코드설계 > 5장 객체 생성 > 복잡한 객체를 생성하기 위한 DSL을 정의하라.
 

오늘의 TIL 3줄 요약

  • 팩토리 함수에 대하여
  • named argument에 대하여
  • DSL에 대하여

1. 책에서 기억하고 싶은 내용

코틀린으로 더 좋은 코드를 작성하기 위한 내용.

팩토리 함수

클라이언트가 클래스의 인스턴스를 만들게 하는 가장 일반적인 방법은 기본 생성자(primary constructor)를 사용하는 것이다.
하지만 생성자가 객체를 만들 수 있는 유일한 방법은 아니며, 디자인 패턴으로 다양한 생성 패턴(creational pattern)들이 만들어져 있다.

팩토리 함수 : 생성자의 역할을 대신하는 함수

생성자 대신 팩토리 함수를 사용할 때 얻을 수 있는 장점

  • 함수에 이름을 붙일 수 있다.
    이름이 있으므로 동일한 파라미터 타입을 가지는 생성자의 충돌을 줄일 수 있다는 장점도 따라온다.
  • 함수가 원하는 형태의 타입을 리턴할 수 있다.
    다른 객체를 생성할 때 사용, 인터페이스 뒤에 실제 객체의 구현을 숨길 때 유용하게 사용
  • 호출될 때마다 새 객체를 만들 필요가 없다.
    함수를 이용하여 객체를 생성하면 싱글턴 패턴처럼 객체를 하나만 생성하도록 강제하거나 최적화를 위한 캐싱 매커니즘을 사용할 수 있다. 또한 객체를 만들지 못하는 경우 null를 반환하도록 할 수 있다.
  • 아직 존재하지 않는 객체를 반환할 수 있다.
  • 객체 외부에 팩토리 함수를 만들면 가시성을 원하는 대로 제어할 수 있다.
  • 인라인으로 만들 수 있으며 해당 파라미터들을 reified로 만들 수 있다.
  • 생성자로 만들기 복잡한 객체도 만들어 낼 수 있다.
  • 원하는 때에 생성자를 호출 할 수 있다.

팩토리 함수의 제한

  • 서브 클래스 생성에는 슈퍼클래스의 생성자가 필요하기 때문에 서브클래스를 만들 수 없다.
    (단, 서브 클래스에도 팩토리 함수를 만들면 해결된다.)

팩토리 함수의 종류

  • companion 객체 팩토리 함수
    • 팩토리 함수를 정의하는 가장 일반적인 방법.
    • java에서의 static factory function과 같다.
    • c++에서는 named constructor idiom 이라고 부른다.
    • Interface 내부 에서도 companion 객체를 통해 구현 가능.
    • from : 파라미터를 하나 받고, 같은 타입의 인스턴스 하나를 반환하는 타입 변환 함수
    • of : 파라미터를 여러개 받고, 이를 통합하여 인스턴스를 생성하는 함수
    • valueOf : from, of와 비슷한 기능을 하고, 의미를 조금 더 쉽게 읽을 수 있게 이름을 붙인 함수
    • instance, getInstance : singlton으로 인스턴스 하나를 반환하는 함수
    • createInstance, newInstance : getInstance처럼 동작,
      singleton이 적용되지 않고 함수를 호출할 때마다 새로운 인스턴스를 생성하여 반환
    • getType : getInstance처럼 동작,
      팩토리 함수가 다른 클래스에 있을 때 사용하는 이름, 타입은 팩토리 함수에서 반환하는 타입.
    • newType : newInstance처럼 동작,
      팩토리 함수가 다른 클래스에 있을 때 사용하는 이름, 타입은 팩토리 함수에서 반환하는 타입.
    • 경험이 없는 코틀린 개발자는 companion 객체 멤버를 단순한 정적 멤버처럼 다루는 경우가 많다.
      하지만 companion 객체는 많은 기능을 가지고 있으므로 코틀린 구현을 확인해볼 .
  • 확장 팩토리 함수
    • 이미 companion 객체가 존재할 , 객체의 함수처럼 사용할 있는 함수를 만들어야 확장 함수를 활용한다.
  • top-level 팩토리 함수
    • 예) listOf, setOf, mapOf
    • 톱레벨 팩토리 함수는 굉장히 광범위하게 사용.
    • 이름을 신중하게 지정, public 톱레벨 함수는 모든 곳에서 사용할 있기 때문.
  • 가짜 생성자
    • fake constructor
    • 개발자가 진짜 생성자 대신 가짜 생성자를 만드는 이유
      • 인터페이스를 위한 생성자를 만들고 싶을 때
      • reified 타입 argument를 갖게 하고 싶을 때
    • 가짜 생성자는 진짜 생성자처럼 동작해야 한다. 생성자처럼 보여야 하며, 생성자와 같은 동작을 해야 한다.
    • invoke 연산자를 가지는 companion객체를 사용하면 가짜 생성자를 선언하는 비슷한 결과를 얻을 있다.
      (
      거의 사용하지는 않는 방식)
  • 팩토리 클래스의 메서드
    • 팩토리 클래스는 프로퍼티를 가질 있고 이를 활용하여 다양한 종류로 최적화하고 기능을 도입할 있다.

코틀린은 팩토리 함수를 만들 있는 다양한 방법을 제공하며 방법은 여러 특징이 있으므로 파악하여 사용하여야 한다.

이름 있는 옵션 아규먼트

기본 생성자(primary constructor)를 사용하여 객체를 정의하고 생성하는 방법은 가장 기본적인 방법이다.
기본 생성자는 매우 편리하기 때문에 일반적으로는 이를 활용해서 객체를 만드는 것이 좋다.

기본 생성자가좋은 방식이라는 것을 이해하기 위하여 생성자와 관련한 자바 패턴을 이해해야 한다.

  • 점층적 생성자 패턴 (telescoping constructor pattern)
    • ‘여러 가지 종류의 생성자를 사용하는’ 패턴이다.
    • 코틀린에서는 일반적으로 디폴트 아규먼트(default argument) 사용한다.
      • 코드를 단순하고 깔끔하게 만들어 줄 뿐 아니라 점층적 생성자 보다 훨씬 다양한 기능을 제공
      • 장점
        • 파라미터들의 값을 원하는 대로 지정가능
        • 아규먼트를 원하는 순서대로 지정가능
        • 명시적으로 이름을 붙여서 아규먼트를 지정하므로 의미가 훨씬 명확하다.
          named argument를 활용하여 이름을 붙여주면 의미는 명확해 진다.
  • 빌더 패턴 (builder pattern)
    • 장점
      • 파라미터에 이름을 붙일 수 있다.
      • 파라미터를 원하는 순서로 지정가능
      • 디폴트 값을 지정가능
    • 빌더 패턴보다 이름 있는 파라미터를 사용하는 것이 더 좋은 이유
      • 더 짧다 : 디폴트 아규먼트가 있는 생성자 또는 팩토리 메서드가 빌더 패턴보다 구현하기 더 쉽다.
      • 더 명확하다 : 디폴트 아규먼트가 있는 코드느 생성자 주변 부분만 확인하면 된다. 거대하게 빌더 패턴으로 만들어진 객체는 디폴트로 어떤 값을 가지는지 그리고 내부적으로 어떤 처리가 일어나는지 이해하기 어렵다.
      • 더 사용하기 쉽다 : 기본 생성자는 언어에 내장된 개념이며 빌더 패턴은 언어 위에 추가로 구현한 개념이므로 추가적인 knowledge가 필요하다.
      • 동시성과 관련한 문제가 없다 : 코틀린의 함수 파라미터는 항상 immutable이며 빌더패턴에서의 프로퍼티는 mutable이기 때문에 thread-safe하게 구현하는 것이 빌더패턴에서는 어렵다.

DSL 정의

DSL (Domain Specific Language) : 복잡한 객체, 계층 구조를 갖고 있는 객체들을 정의할 때 굉장히 유용하다.
DSL을 만드는 것은 힘든 일이지만 한 번 만들고 나면 보일러 플레이트와 복잡성을 숨기면서 개발자의 의도를 명확하게 표현할 수 있다.

DSL은 정보를 정의하는 방법을 제공한다. 하지만 DSL을 정의한다는 것은 개발자의 인지적 혼란과 성능이라는 비용이 모두 발생하는 일이므로 특수한 상황에서 유용하게 쓰일 수 있도록 해야 한다.

  • 복잡한 자료 구조
  • 계층적 구조
  • 거대한 양의 데이터

DSL 없이 빌더 또는 단순하게 생성자만을 활용해도 원하는 모든 것을 표현할 있다.
하지만 위와 같이 많이 사용되는 구조의 반복을 제거하는 데에 DSL 유용하게 쓰인다.

728x90
반응형