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;
}
}