πŸ“– Effective java item 1 -μƒμ„±μž λŒ€μ‹  정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό κ³ λ €ν•˜λΌ


ν΄λž˜μŠ€λŠ” μƒμ„±μžμ™€ λ³„λ„λ‘œ 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ(static factory method)λ₯Ό μ œκ³΅ν•  수 μžˆλ‹€. λ””μžμΈ νŒ¨ν„΄μ˜ νŒ©ν„°λ¦¬ λ©”μ„œλ“œμ™€λŠ” λ‹€λ₯΄λ‹€.

μž₯점

1. 이름을 κ°€μ§ˆ 수 μžˆλ‹€.

μƒμ„±μžμ— λ„˜κΈ°λŠ” λ§€κ°œλ³€μˆ˜μ™€ μƒμ„±μžλ§ŒμœΌλ‘œλŠ” λ°˜ν™˜λ  객체의 νŠΉμ„±μ„ μ œλŒ€λ‘œ μ„€λͺ…ν•˜μ§€ λͺ»ν•œλ‹€.
ν•˜μ§€λ§Œ 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλŠ” λ°˜ν•œλ  객체의 νŠΉμ„±μ„ λ©”μ†Œλ“œλͺ…을 톡해 λ“œλŸ¬λ‚Ό 수 μžˆλ‹€.

  • Exmaple - μƒμ„±μž
    public Cars(List<String> names) {
      validateNonDuplicatedNames(names);
      for (String name : names) {
          cars.add(new Car(name));
      }
    }
    private void validateNonDuplicatedNames(final List<String> names) {
      if (new HashSet<>(names).size() != names.size()) {
          throw new IllegalArgumentException("μ€‘λ³΅λœ μžλ™μ°¨ μ΄λ¦„μž…λ‹ˆλ‹€.");
       }
    }
    
  • Example -정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ
      public static Cars makeFromCarNames(final List<Name> carNames) {
          List<Car> cars = carNames.stream()
                  .map(Car::new)
                  .collect(Collectors.toList());
          return new Cars(cars);
      }
    

    μžλ™μ°¨μ˜ μ΄λ¦„λ“€λ‘œ μžλ™μ°¨ 객체λ₯Ό μƒμ„±ν•˜λŠ” 행동을 더 λͺ…ν™•νžˆ λ“œλŸ¬λ‚Έλ‹€.

2. 호좜될 λ•Œλ§ˆλ‹€ μΈμŠ€ν„΄μŠ€λ₯Ό μƒˆλ‘œ μƒμ„±ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

이 덕뢄에 λΆˆλ³€ ν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό 미리 λ§Œλ“€μ–΄ λ†“κ±°λ‚˜ μƒˆλ‘œ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ₯Ό μΊμ‹±ν•˜μ—¬
μž¬ν™œμš©ν•˜λŠ” μ‹μœΌλ‘œ λΆˆν•„μš”ν•œ 객체 생성을 ν”Όν•  수 μžˆλ‹€.

  • Example - Boolean.valueOf()λŠ” 객체λ₯Ό μ•„μ˜ˆ μƒμ„±ν•˜μ§€ μ•ŠλŠ”λ‹€.
    public static Boolean valueOf(boolean b) {
      return (b ? TRUE : FALSE);
    }
    

    λ§Œμ•½ 생성 λΉ„μš©μ΄ 큰 같은 객체가 자주 μš”μ²­λ˜λŠ” 상황일 λ•Œ 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜λ©΄ μ„±λŠ₯ ν–₯상을 κΈ°λŒ€ν•  수 μžˆλ‹€.

λ˜ν•œ μ–Έμ œ μ–΄λŠ μΈμŠ€ν„΄μŠ€λ₯Ό μ‚΄μ•„μžˆκ²Œ 할지λ₯Ό μ² μ €νžˆ ν†΅μ œν•  수 μžˆλ‹€. (μΈμŠ€ν„΄μŠ€ ν†΅μ œ 클래슀)
πŸ€” μΈμŠ€ν„΄μŠ€λ₯Ό ν†΅μ œν•˜λŠ” 이유?

  • Singleton νŒ¨ν„΄μœΌλ‘œ λ§Œλ“€μˆ˜ μžˆλ‹€.
  • μΈμŠ€ν„΄μŠ€ν™” λΆˆκ°€λ‘œ λ§Œλ“€ 수 μžˆλ‹€.
  • λΆˆλ³€ ν΄λž˜μŠ€μ—μ„œ λ™μΉ˜μΈ μΈμŠ€ν„΄μŠ€κ°€ 단 ν•˜λ‚˜λΏμž„μ„ 보μž₯ν•  수 μžˆλ‹€. (a == b일 λ•Œλ§Œ a.equals(b)κ°€ 성립)

3. λ°˜ν™˜ νƒ€μž…μ˜ ν•˜μœ„ νƒ€μž… 객체λ₯Ό λ°˜ν™˜ν•  수 μžˆλŠ” λŠ₯λ ₯이 μžˆλ‹€.

λ°˜ν™˜ν•  객체의 클래슀λ₯Ό 자유둭게 선택할 수 μžˆκ²Œν•˜λŠ” μ—„μ²­λ‚œ μœ μ—°μ„±μ„ μ œκ³΅ν•œλ‹€.
μ΄λŠ” λ°˜ν™˜ν•˜λŠ” νƒ€μž…μ„ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ ν•  경우, ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ”
λ‹€λ₯Έ νƒ€μž…μ˜ 객체듀을 λ°˜ν™˜ν•  수 μžˆμŒμ„ λ§ν•œλ‹€. (상속)
특히 APIλ₯Ό λ§Œλ“€ λ•Œ 이 μœ μ—°μ„±μ„ μ‘μš©ν•˜λ©΄ κ΅¬ν˜„ 클래슀λ₯Ό κ³΅κ°œν•˜μ§€ μ•Šκ³ λ„ κ·Έ 객체λ₯Ό
λ°˜ν™˜ν•  수 μžˆμ–΄ APIλ₯Ό μž‘κ²Œ μœ μ§€ν•  수 μžˆλ‹€.
μ΄λŠ” μΈν„°νŽ˜μ΄μŠ€ 기반 ν”„λ ˆμž„μ›Œν¬λ₯Ό λ§Œλ“œλŠ” 핡심 κΈ°μˆ μ΄κΈ°λ„ ν•˜λ‹€.

특히 μžλ°” μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬λŠ” 핡심 μΈν„°νŽ˜μ΄μŠ€λ“€μ— μˆ˜μ • λΆˆκ°€, 동기화 λ“±μ˜ κΈ°λŠ₯을
덧뢙인 총 45개의 μœ ν‹Έλ¦¬ν‹° κ΅¬ν˜„μ²΄λ₯Ό μ œκ³΅ν•˜λŠ”λ°,
이 κ΅¬ν˜„μ²΄ λŒ€λΆ€λΆ„μ„ 단 ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€ν™” λΆˆκ°€ 클래슀인 java.util.Collectoinsμ—μ„œ 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό 톡해 얻도둝 ν–ˆλ‹€.
Collection을 μƒμ†λ°›λŠ” λͺ¨λ“  νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€κ°€ 리턴될 수 μžˆλŠ” 것이닀.

정적 νŒ©ν„°λ¦¬λ₯Ό μ‚¬μš©ν•˜λŠ” ν΄λΌμ΄μ–ΈνŠΈλŠ” 얻은 객체λ₯Ό μΈν„°νŽ˜μ΄μŠ€λ§ŒμœΌλ‘œ λ‹€λ£¨κ²Œ λœλ‹€.

4. μž…λ ₯ λ§€κ°œλ³€μˆ˜μ— 따라 맀번 λ‹€λ₯Έ 클래슀의 객체λ₯Ό λ°˜ν™˜ν•  수 μžˆλ‹€.

λ°˜ν™˜ νƒ€μž…μ˜ ν•˜μœ„ νƒ€μž…μ΄κΈ°λ§Œ ν•˜λ©΄ μ–΄λ–€ 클래슀의 객체λ₯Ό λ°˜ν™˜ν•˜λ“  상관없닀.

  • Example - EnumSet의 noneOf()
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
      Enum<?>[] universe = getUniverse(elementType);
      if (universe == null)
          throw new ClassCastException(elementType + " not an enum");
    
      if (universe.length <= 64)
          return new RegularEnumSet<>(elementType, universe);
      else
          return new JumboEnumSet<>(elementType, universe);
    }
    

    μ˜ˆμ‹œλ‘œ EnumSet ν΄λž˜μŠ€λŠ” publi μƒμ„±μž 없이 였직 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ§Œ μ œκ³΅ν•œλ‹€.
    λ§Œμ•½ μ›μ†Œκ°€ 64개 μ΄ν•˜μ΄λ©΄ μ›μ†Œλ“€μ€ long λ³€μˆ˜ ν•˜λ‚˜λ‘œ κ΄€λ¦¬ν•˜λŠ”
    RegularEnumSet의 μΈμŠ€ν„΄μŠ€λ₯Ό,
    65개 이상이면 long λ°°μ—΄λ‘œ κ΄€λ¦¬ν•˜λŠ” JunboEnumSet의 μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.
    ν΄λΌμ΄μ–ΈνŠΈλŠ” 이 두 클래슀의 쑴재λ₯Ό λͺ°λΌλ„ λœλ‹€.

5. 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•˜λŠ” μ‹œμ μ—λŠ” λ°˜ν™˜ν•  객체의 ν΄λž˜μŠ€κ°€ μ‘΄μž¬ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

이런 μœ μ—°ν•¨μ€ μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬λ₯Ό λ§Œλ“œλŠ” 근간이 λœλ‹€.
λŒ€ν‘œμ μΈ μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬λ‘œλŠ” JDBCκ°€ μžˆλŠ”λ°,
μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬μ—μ„œμ˜ μ œκ³΅μžλŠ” μ„œλΉ„μŠ€μ˜ κ΅¬ν˜„μ²΄μ΄λ‹€.
그리고 이 κ΅¬ν˜„μ²΄λ“€μ„ ν΄λΌμ΄μ–ΈνŠΈμ— μ œκ³΅ν•˜λŠ” 역할을 ν†΅μ œν•˜μ—¬,
ν΄λΌμ΄μ–ΈνŠΈλ₯Ό κ΅¬ν˜„μ²΄λ‘œλΆ€ν„° 뢄리해쀀닀.

βž• μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬μ˜ 3개 핡심 μ»΄ν¬λ„ŒνŠΈ

  • μ„œλΉ„μŠ€ μΈν„°νŽ˜μ΄μŠ€ : κ΅¬ν˜„μ²΄μ˜ λ™μž‘μ„ μ •μ˜ν•œλ‹€.
  • 제곡자 등둝 API : μ œκ³΅μžκ°€ κ΅¬ν˜„μ²΄λ₯Ό 등둝할 λ•Œ μ‚¬μš©ν•œλ‹€.
  • μ„œλΉ„μŠ€ μ ‘κ·Ό API : ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλΉ„μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 얻을 λ•Œ μ‚¬μš©ν•œλ‹€.

ν΄λΌμ΄μ–ΈνŠΈλŠ” μ„œλΉ„μŠ€ μ ‘κ·Ό APIλ₯Ό μ‚¬μš©ν•  λ•Œ μ›ν•˜λŠ” κ΅¬ν˜„μ²΄μ˜ 쑰건을 λͺ…μ‹œν•  수 μžˆλ‹€.
이 μ„œλΉ„μŠ€ μ ‘κ·Ό APIκ°€ λ°”λ‘œ μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬μ˜ 근간이 λ˜λŠ” 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ‹€.

이와 λ”λΆˆμ–΄ β€˜μ„œλΉ„μŠ€ 제곡자 μΈν„°νŽ˜μ΄μŠ€β€™λΌλŠ” 4 번째 μ»΄ν¬λ„ŒνŠΈκ°€ 쓰이기도 ν•œλ‹€.
이 μ»΄ν¬λ„ŒνŠΈλŠ” μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” νŒ©ν„°λ¦¬ 객체λ₯Ό μ„€λͺ…ν•΄μ€€λ‹€.

JDBCμ—μ„œλŠ” Connection이 μ„œλΉ„μŠ€ μΈν„°νŽ˜μ΄μŠ€ μ—­ν• , DriverManager.registerDriverκ°€ 제곡자 등둝 API μ—­ν• ,
DriverManager.getConnection이 μ„œλΉ„μŠ€ μ ‘κ·Ό API μ—­ν• ,
Driverκ°€ μ„œλΉ„μŠ€ 제곡자 μΈν„°νŽ˜μ΄μŠ€ 역할을 μˆ˜ν–‰ν•œλ‹€.

단점

1. 상속을 ν•˜λ €λ©΄ publicμ΄λ‚˜ protected μƒμ„±μžκ°€ ν•„μš”ν•˜λ‹ˆ 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ§Œ μ œκ³΅ν•˜λ©΄ ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€ 수 μ—†λ‹€.

μ˜ˆμ‹œλ‘œ Collection ν”„λ ˆμž„λ€„ν¬μ˜ μœ ν‹Έλ¦¬ν‹° κ΅¬ν˜„ ν΄λž˜μŠ€λ“€μ€ 상속할 수 μ—†λ‹€.

ν•˜μ§€λ§Œ 상속보닀 μ»΄ν¬μ§€μ…˜μ„ μ‚¬μš©ν•˜λ„λ‘ μœ λ„ν•˜κ³ , λΆˆλ³€ νƒ€μž…μœΌλ‘œ λ§Œλ“€λ„λ‘
μœ λ„ν•˜λ―€λ‘œ 였히렀 μž₯점이 될 μˆ˜λ„ μžˆλ‹€.

2. ν”„λ‘œκ·Έλž˜λ¨Έκ°€ μ°ΎκΈ° μ–΄λ ΅λ‹€.

μ‚¬μš©μžλŠ” 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ 방식 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•  방법을 μ•Œμ•„λ‚΄μ•Ό ν•œλ‹€.
λ•Œλ¬Έμ— 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œμ˜ 이름 κ·œμΉ™μ„ μ •ν•΄λ†“λŠ”λ‹€.

λͺ…λͺ… κ·œμΉ™

  • from : λ§€κ°œλ³€μˆ˜λ₯Ό ν•˜λ‚˜ λ°›μ•„ ν•΄λ‹Ή νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” ν˜•λ³€ν™˜ λ©”μ„œλ“œ
    ex) Date d = Date.from(instant);
  • of : μ—¬λŸ¬ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„ μ ν•©ν•œ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” 집계 λ©”μ„œλ“œ ex) Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf : fromκ³Ό of의 더 μžμ„Έν•œ 버전 ex) BingInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance / getInstance : (λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ”λ‹€λ©΄) λ§€κ°œλ³€μˆ˜λ‘œ λͺ…μ‹œν•œ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜μ§€λ§Œ, 같은 μΈμŠ€ν„΄μŠ€μž„μ„ 보μž₯ν•˜μ§€λŠ” μ•ŠλŠ”λ‹€. ex) StackWalker luke = StackWalker.getInstance(options);
  • create / newInstance : instance / getInstance와 κ°™μ§€λ§Œ, 맀번 μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό 생성해 λ°˜ν™˜ν•¨μ„ 보μž₯ν•œλ‹€. ex) Object newArray = Array.newInstance(calssObject, arrayLen);
  • getType : getInstance와 κ°™μœΌλ‚˜, 생성할 ν΄λž˜μŠ€κ°€ μ•„λ‹Œ λ‹€λ₯Έ ν΄λž˜μŠ€μ— νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λ•Œ μ“΄λ‹€. β€œType”은 νŒ©ν„°λ¦¬ λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•  객체의 νƒ€μž…μ΄λ‹€. ex) FileStore fs = Files.getFileStore(path);
  • newType : newInstance와 κ°™μœΌλ‚˜, 생성할 ν΄λž˜μŠ€κ°€ μ•„λ‹Œ λ‹€λ₯Έ ν΄λž˜μŠ€μ— νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λ•Œ μ“΄λ‹€. β€œType”은 νŒ©ν„°λ¦¬ λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•  객체의 νƒ€μž…μ΄λ‹€. ex) BufferedReader br = Files.newBufferedReader(path);
  • type : getTypeκ³Ό newType의 κ°„κ²°ν•œ 버전 ex) List<Complaint> litany = Collections.list(legacyLintany);