[Effective Java] item 03. private μμ±μλ μ΄κ±° νμ μΌλ‘ μ±κΈν΄μμ 보μ¦νλΌ
Item 3. private μμ±μλ μ΄κ±° νμ μΌλ‘ μ±κΈν΄μμ 보μ¦νλΌ
1. μ±κΈν΄(Singleton)μ΄λ?
μ±κΈν΄(singleton)μ΄λ μΈμ€ν΄μ€λ₯Ό μ€μ§ νλλ§ μμ±ν μ μλ ν΄λμ€λ₯Ό λ§νλ€.
μ±κΈν΄μ μ νμ μΈ μλ‘λ μ€κ³ μ μ μΌν΄μΌ νλ μμ€ν
μ»΄ν¬λνΈλ 무μν(stateless) κ°μ²΄(Spring bean component)κ° μλ€.
μ±κΈν΄ κ°μ²΄μλ λ¨μ μ΄ μλλ°, λ°λ‘ μ±κΈν΄ κ°μ²΄λ₯Ό μ΄μ©νλ ν΄λΌμ΄μΈνΈλ₯Ό ν
μ€νΈνκΈ° μ΄λ ΅λ€λΌλ κ²μ΄λ€.
λ§μΌ ν΄λΉ νμ
μ `interface`λ‘ μ μν λ€μ κ·Έ `interface `ꡬνν΄μ λ§λ μ±κΈν΄μΈ κ²½μ°,
μ±κΈν΄ μΈμ€ν΄μ€λ₯Ό `mock(κ°μ§ κ°μ²΄)`μΌλ‘ ꡬννμ¬ λ체ν μ μμ§λ§, κ·Έλ μ§ μμ κ²½μ°μλ ν
μ€νΈ νλλ°μ μ΄λ €μμ κ²ͺμ μ μλ€.
2. μ±κΈν΄μ λ§λλ μΈ κ°μ§ λ°©λ²
μ±κΈν΄μ λ§λλ λ κ°μ§ λ°©λ² λͺ¨λ, μμ±μλ privateλ‘ κ°μΆ°μ£Όκ³ , public staticλ©€λ²λ₯Ό ν΅ν΄ μ κ·Όνλ λ°©μμ μ¬μ©νλ€.
1οΈβ£ `public static` λ©€λ²κ° `final` νλμΈ λ°©μ
public class Bean {
public static final Bean INSTANCE = new Bean();
private Bean() { }
...
}
publicμ΄λ protected μμ±μκ° μκ³ private μμ±μλ§ μ‘΄μ¬νλ©°, private μμ±μλ public static final νλμΈ Bean.INSTANCEλ₯Ό μ΄κΈ°νν λ λ± ν λ²λ§ νΈμΆλλ€.
λ°λΌμ Bean ν΄λμ€κ° μ΄κΈ°νλλ©° λ§λ€μ΄μ§ μΈμ€ν΄μ€κ° λ¨ νλλΏμμ 보μ₯ν μ μλ€.
μ΄λ¬ν λ°©μμ μ₯μ μ λ°κ³Ό κ°λ€.
- ν΄λΉ ν΄λμ€κ° μ±κΈν΄(singleton)μμ΄ APIμ λͺ
λ°±ν λλ¬λλ€λ κ²
public static νλκ° finalμ΄λ―λ‘ μ λλ‘ λ€λ₯Έ κ°μ²΄λ₯Ό μ°Έμ‘°ν μ μλ€. - λ³λμ λ©μλλ₯Ό λ°λ‘ μμ±νμ§ μμλ λκΈ° λλ¬Έμ κ°κ²°νλ€
β οΈ νμ§λ§ μμΈλ νλ μ‘΄μ¬νλλ°, κΆνμ΄ μλ ν΄λΌμ΄μΈνΈκ° Reflection APIμΈ AccssibleObject.setAccessible()μ μ¬μ©ν΄ private μμ±μλ₯Ό νΈμΆν μ μλ€.
μ΄λ¬ν μμΈλ₯Ό μ²λ¦¬νλ €λ©΄, μμ±μλ₯Ό μμ νμ¬ λ λ²μ§Έ κ°μ²΄κ° μμ±λλ €ν λ μμΈλ₯Ό λμ§κ² νλ©΄ λλ€.
2οΈβ£ μ μ ν©ν°λ¦¬ λ©μλλ₯Ό public static
λ©€λ²λ‘ μ 곡νλ λ°©μ
public class Bean {
private static final Bean INSTANCE = new Bean();
private Bean() { }
public static Bean getInstance() {
return INSTANCE;
}
...
}
μ°λ¦¬λ Item 1μμ μ μ ν©ν°λ¦¬ λ©μλμ λν΄ μμ보μλ€.
'μ μ ν©ν°λ¦¬ λ©μλλ₯Ό μ°ΎκΈ° νλ€λ€'λΌλ λ¨μ μ 보μνκΈ° μν΄ μ£Όλ‘ μ¬μ©νλ λͺ λͺ λ°©μμ μ¬μ©νλ€.
κ·Έ μ€, `getInstance()`λ μΈμ€ν΄μ€λ₯Ό λ°νν λ μ¬μ©νλ λͺ
λͺ
λ²μΈλ°, ν΄λΉ λ©μλλ νμ κ°μ κ°μ²΄μ μ°Έμ‘°λ₯Ό λ°ννκΈ° λλ¬Έμ
μΈμ€ν΄μ€κ° λ¨ νλ λΏμμ 보μ₯ν μ μλ€.
λ¨, 첫λ²μ§Έ λ°©λ²κ³Ό κ°μ΄ Reflectionμ μ¬μ©νμ¬ private μμ±μλ₯Ό νΈμΆν μ μλ κ²μ λ§μ°¬κ°μ§μ΄λ―λ‘, μΆκ°μ μΈ μμΈ μ²λ¦¬κ° νμνλ€.
μ΄λ¬ν λ°©μμ μ₯μ μ λ€μκ³Ό κ°λ€.
1. λ§μΌ, ν΄λΉ ν΄λμ€λ₯Ό λμ΄μ μ±κΈν΄μΌλ‘ μ μ§νκ³ μΆμ§ μλ€λ©΄, `APIλ₯Ό λ°κΎΈμ§ μκ³ λ λ³κ²½`ν μ μλ€.
public class Bean {
private Bean instance;
private Bean() { }
// μ μ ν©ν°λ¦¬ λ©μλλ§ μ μ©
public static Bean from() { return new Bean(); }
}
2. μ μ ν©ν°λ¦¬λ₯Ό `μ λλ¦ μ±κΈν΄ ν©ν°λ¦¬(Generic Singleton factory); item 30`λ‘ λ³κ²½ν μ μλ€λ κ²μ΄λ€.
public class Bean {
private static final Bean INSTANCE = new Bean();
private Bean() { }
public static Bean getInstance() { return (Bean) INSTANCE; }
public void say(T t) { System.out.println(t); }
}
3. μ μ ν©ν°λ¦¬μ λ©μλ μ°Έμ‘°λ₯Ό `Supplier`λ‘ μ¬μ©ν μ μλ€λ μ μ΄λ€.
public class Bean {
private static final Bean INSTANCE = new Bean();
private Bean() { }
public static Bean getInstance() { return INSTANCE; }
}
public static void main(String[] args) {
Supplier supplier = Bean::getInstance;
Bean bean = supplier.get();
// μ΄νμλ beanμ λ©μλ νΈμΆ
}
λ§μΌ μμ μ₯μ μ νμ©νμ§ μμλ λλ€λ©΄, 첫λ²μ§Έ λ°©λ²(public νλ λ°©μ)μ΄ λ μ’λ€.
3οΈβ£ μ΄κ±° νμ (Enum)μ μ¬μ©νλ λ°©λ²
public enum Bean {
INSTANCE;
//λ°μ λ©μλ μΆκ° ꡬν
}
1λ² λ°©μ(public static final νλ)κ³Ό λΉμ·νμ§λ§, λ κ°κ²°νκ³ μΆκ°μ μΈ κ΅¬νμμ΄ μ§λ ¬ν(Serialize)λ ν μ μλ€.
μ¬μ§μ΄ μμ£Ό 볡μ‘ν μ§λ ¬ν μν©μ΄λ, Reflection 곡격μλ μ 2μ μΈμ€ν΄μ€κ° μκΈ°λ μΌμ μλ²½νκ² λ§μμ€λ€.
λΆμμ°μ€λ¬μ λ³΄μΌ μ μμΌλ, λλΆλΆμ μν©μμλ μμκ° νλ λΏμΈ μ΄κ±° νμ
μ΄ μ±κΈν΄μ λ§λλ κ°μ₯ μ’μ λ°©λ²μ΄λ€.
νμ§λ§ μ΄ λ°©λ²μλ ν κ°μ§ λ¨μ μ΄ μλ€.
μ±κΈν΄μ΄ Enum μΈμ Concrete classλ₯Ό μμ(extends)μ ν μ μκΈ° λλ¬Έμ, λ§μΌ νΉμ ν΄λμ€λ₯Ό μμν΄μΌ νλ€λ©΄ μ΄ λ°©λ²μμ¬μ©ν μ μλ€.
3. μ±κΈν΄ ν΄λμ€λ₯Ό μ§λ ¬ν(Serialize)νλ λ°©λ²
1λ² λ°©λ²(public static final νλ)λ 2λ² λ°©λ²(μ μ ν©ν°λ¦¬ μ μ©)μΌλ‘ λ§λ μ±κΈν΄ ν΄λμ€λ₯Ό μ§λ ¬ννκΈ° μν΄μλ
Serialize interface
λ₯Ό ꡬννλ€κ³ μ μΈνλ κ²λ§μΌλ‘λ λΆμ‘±νλ€.
λͺ¨λ μΈμ€ν΄μ€ νλλ₯Ό μΌμμ (transient)λΌκ³ μ μΈνκ³ , readResolve λ©μλλ₯Ό μ 곡ν΄μΌ νλ€.
λ§μΌ μ 곡νμ§ μμ κ²½μ°μλ μ§λ ¬νν μΈμ€ν΄μ€λ₯Ό μμ§λ ¬νν λλ§λ€ μλ‘μ΄ μΈμ€ν΄μ€κ° λ§λ€μ΄μ§λ€.
public class Bean implements Serializable{
private static final Bean INSTANCE = new Bean();
private Bean() { }
public static Bean getInstance() {
return INSTANCE;
}
private Object readResolve() {
return INSTANCE;
}
}