[이펙티브 자바. 아이템1] 생성자 대신 정적 팩터리 메서드를 고려하라.

박상준·2024년 5월 13일
0

이펙티브 자바

목록 보기
1/16
  • 정적 팩터리 메서드의 경우 클래스의 인스턴스를 생성하는 전통적인 public 생성자의 대안으로 사용가능하다.
  • 해당 메서드는 클래스 내부에 정의된 정적 메서드로, 인스턴스를 생성하고 반환하는 역할을 한다.

정적 팩토리 메서드의 장점

  1. 명확한 이름을 가질 수 있다.
    • 생성자보다 더 의미있는 이름을 가질 수 있다.
    • 반환될 객체의 특성을 쉽게 묘사할 수 있음.
    • 예를들어
      • BigInteger.probablePrime 의 경우 소수를 가진 BigInteger 를 반환할 것임으로 쉽게 유추가 가능하다.
  2. 호출되는 경우 인스턴스를 새로 생성할 필요가 없다.
    • 필요에 따라 미리 생성해 둔 인스턴스를 반환하거나 캐싱을 통해 인스턴스를 재사용할 수 있음.
    • Boolean.valueOf(boolean b)
      public static Boolean valueOf(boolean b) {
          return b ? Boolean.TRUE : Boolean.FALSE;
      }
      • 이미 정의된 Boolean.TRUE or FALSE 객체를 반환함으로서, 불필요한 객체 생성을 방지가능하다.
  3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
    • 예시
      • 연결 인터페이스 (Connection)
        public interface Connection {
            void connect();
            // 기타 연결 관련 메서드들...
        }
        
        public class MySqlConnection implements Connection {
            @Override
            public void connect() {
                // MySQL 데이터베이스에 연결하는 로직
            }
            // MySQL 연결에 특화된 메서드들...
        }
        
        public class PostgreSqlConnection implements Connection {
            @Override
            public void connect() {
                // PostgreSQL 데이터베이스에 연결하는 로직
            }
            // PostgreSQL 연결에 특화된 메서드들...
        }
        
        public class ConnectionFactory {
            public static Connection getConnection(String type) {
                if ("MySQL".equals(type)) {
                    return new MySqlConnection();
                } else if ("PostgreSQL".equals(type)) {
                    return new PostgreSqlConnection();
                }
                throw new IllegalArgumentException("Unsupported database type: " + type);
            }
        }
        • 의 경우 ConectionFactory 의 getConnection 정적 메서드의 경우 반환은 Connection 으로 반환된다.
        • 해당 반환타입에 대해 MYSQL 인 경우 MySQLConnection 으로 객체 반환
        • PostgreSqlConnection 으로 객체 반환
        • 등의 유연한 반환이 가능해지고, 클라이언트 코드에 대해 클래스 사용자는 별도로 고려하지 않아도 된다.
  4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
    • 함수의 반환 타입이 함수의 입력 매개변수에 의존적인 경우 유용함.
    • 위의 Connection 예시에 해당 사항이 정확하게 반영된다.
    • MySQL 의 경우 , PostgreSql 의 경우 각각 다른 클래스의 객체가 반환된다.
  5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다
    • 런타임시에 결정되는 것을 말한다. 해당 구현체의 경우 팩토리 메서드가 작성되는 경우 존재하지 않아도 된다는 것이다.
    • 어.. 예시를 들자면, 현재는 박상준DB 라는 것이 존재하지 않지만, 현재 Connection 의 정적 팩터리 메서드의 경우에 추가만 시켜줘도 등록이 가능해진다.

정적 팩토리 메서드의 단점

  1. 상속의 제한
    1. 정적 팩토리 메서드를 사용하는 클래스는 상속을 통한 확장이 제한된다.
    2. 정적 팩토리 메서드만 제공하고, public 이나 protected 생성자를 제공하지 않는 클래스의 경우 다른 클래스가 상속할 수 없다
    • java.lang.Math ( by GPT )
      public class Arrays {
          // ... 다른 메서드들 ...
      
          public static <T> List<T> asList(T... a) {
              return new ArrayList<>(a); // 실제로는 Arrays의 내부 private 클래스를 반환
          }
      
          // ... 내부 private 클래스 구현 ...
      }
      • 이런식으로 private 클래스를 반환하기에
        • 클라이언트코드는 해당 클래스를 직접 사용하거나 확장 불가능하다.
  2. 프로그래머가 찾기 어렵다 : 발견성의 문제
    • 생성자와 달리, 정적 팩토리 메서드는 API 설명에서 명확하게 드러나지 않는다.
    • 사용자는 클래스를 인스턴스화할 방법 을 직접 찾아내야 한다.
    • 자바독과 같은 문서화 도구는 생성자를 명확히 표시하지만, 정적 팩터리 메서드에 대해서는 그렇지 않음. 이로 인하여 사용자가 클래스의 인스턴스 생성 방법을 알아내기 위해 추가적인 노력이 필요함.
    • 문제의 완화 방법
      • 정적 팩터리 메서드의 이름을 잘 알려진 규약에 따라 지어주는 것이 중요!
      1. from

        • 단일 매개변수를 받아 해당 타입의 인스턴스를 반환하는 형변환 메서드이다.
        Date d = Date.from(instant);
      2. of

        • 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드이다.
        Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
profile
이전 블로그 : https://oth3410.tistory.com/

0개의 댓글