๊ท์น3 : private ์์ฑ์๋ enum ์๋ฃํ์ ์ฑ๊ธํด ํจํด์ ๋ฐ๋ฅด๋๋ก ์ค๊ณํ๋ผ
๊ท์น3 : private ์์ฑ์๋ enum ์๋ฃํ์ ์ฑ๊ธํด ํจํด์ ๋ฐ๋ฅด๋๋ก ์ค๊ณํ๋ผ ๊ด๋ จ
Enforce the singleton property with a private constructor or an enum type
์ฑ๊ธํด์ ๊ฐ์ฒด๋ฅผ ํ๋๋ง ๋ง๋ค ์ ์๋ ํด๋์ค๋ค. ๊ทธ๋ฐ๋ฐ ํด๋์ค๋ฅผ ์ฑ๊ธํด์ผ๋ก ๋ง๋ค๋ฉด ํด๋ผ์ด์ธํธ๋ฅผ ํ ์คํธํ๊ธฐ๊ฐ ์ด๋ ค์์ง ์๊ฐ ์๋ค. ์ฑ๊ธํด์ด ์ด๋ค ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์๋๋ฉด ๊ฐ์ง ๊ตฌํ์ผ๋ก ๋์ฒดํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
JDK 1.5 ์ด์ ์๋ ์ฑ๊ธํด์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ด ๋ ๊ฐ์ง์๋ค. ๋ ๋ฐฉ๋ฒ ๋ค ์์ฑ์๋ private๋ก ์ ์ธํ๊ณ , ์ฑ๊ธํด ๊ฐ์ฒด๋ ์ ์ (static) ๋ฉค๋ฒ๋ฅผ ํตํด ์ด์ฉํ๋ค.
์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ - ํ๋
public class Elvis {
public static final Elvis INSTANCE = new Elvis(); //public ํ๋๋ก ์ ์ธ
private Elvis() {}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
// This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
}
ํ๋ ๋ฐฉ์์ ์ฅ์ ์ ํด๋์ค๊ฐ ์ฑ๊ธํด์ธ์ง ํ๋ ์ ์ธ๋ง ๋ด๋ ๋ฐ๋ก ์ ์ ์๋ค(public static field is final, so it will always contain the same object reference). ๋๋ฒ์งธ ์ฅ์ ์ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ ๋ฐฉ์๋ณด๋ค ๋ ๊ฐ๋จํ๋ค.
๋ ๋ฒ์งธ ๋ฐฉ๋ฒ - ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
public class Elvis {
private static final Elvis INSTANCE = new Elvis(); //private ํ๋๋ก ์ ์ธ
private Elvis() {}
public static Elvis getInstance() {
return INSTANCE;
}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
// This code would normally appear outside the class!
public static void main(String[] args) {
Elvis elvis = Elvis.getInstance();
elvis.leaveTheBuilding();
}
}
์ด ๋ฐฉ์์ ์ฅ์ ์ API๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ ์ฑ๊ธํด ํจํด์ ํฌ๊ธฐํ ์ ์๋ค. ์ค๋ ๋๋ง๋ค ๋ณ๋์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋๋ก ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์์ ํ๋ ๊ฒ๋ ๊ฐ๋จํ๋ค. ๋๋ฒ์งธ ์ฅ์ ์ ์ ๋ค๋ฆญ ํ์
์ ์์ฉํ๊ธฐ ์ฝ๋ค. ๋ง์ง๋ง ์ฅ์ ์(3rd edition ์ถ๊ฐ) method reference๊ฐ supplier๋ก์จ ์ฌ์ฉ ๋ ์ ์๋ค. ์๋ฅผ ๋ค์ด Elvis::instance
๋ Supplier<Elvis>
๋ค. ์ด๋ฌํ ์ฅ์ ๋ค์ด ํ์ ์๋ค๋ฉด pulbic
ํ๋๋ฅผ ์ฌ์ฉํ๋ ์ชฝ์ด ๋ ๊ฐ๋จํ๋ค.
private
์์ฑ์์ด๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ๊ฐ ์ด ์ํ๋ฅผ ๋ณ๊ฒฝํ ๋ฐฉ๋ฒ์ ์์ง๋ง ์ฃผ์ํ ๊ฒ์ด ํ๋ ์๋ค.
AccessibleObject.setAccessible
๋ฉ์๋์ ๋์์ ๋ฐ์ ๊ถํ์ ํ๋ํ ํด๋ผ์ด์ธํธ๋ ๋ฆฌํ๋ ์
(reflection) ๊ธฐ๋ฅ์ ํตํด private
์์ฑ์๋ฅผ ํธ์ถ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
import java.lang.relfect.Constructor;
public class PrivateInvoker {
public static void main(String[] args) throws Exception {
//๋ฆฌํ๋ ์
๊ณผ setAccessible๋ฉ์๋๋ฅผ ํตํด private๋ก ์ ์ธ๋ ์์ฑ์์ ํธ์ถ ๊ถํ์ ํ๋ํ๋ค.
Constructor<?> con = Private.class.getDeclaredConstructors()[0];
con.setAccessible(true);
Private p = (Private)con.newInstance();
}
}
class Private {
private Private() {
System.out.println("hello");
}
}
๋ฆฌํ๋ ์ ๊ธฐ๋ฅ์ ์ด์ฉํ๋ฉด ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฌ๋ ํด๋์ค์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํ๋ก๊ทธ๋จ์ ์์ฑํ ์ ์๋ค. Class ๊ฐ์ฒด๊ฐ ์ฃผ์ด์ง๋ฉด, ํด๋น ๊ฐ์ฒด๊ฐ ๋ํ๋ด๋ ํด๋์ค์ ์์ฑ์, ๋ฉ์๋, ํ๋ ๋ฑ์ ๋ํ๋ด๋ Constructor, Method, Field ๊ฐ์ฒด๋ค์ ๊ฐ์ ธ์ฌ ์ ์๋๋ฐ, ์ด ๊ฐ์ฒด๋ค์ ์ฌ์ฉํ๋ฉด ํด๋์ค์ ๋ฉค๋ฒ ์ด๋ฆ์ด๋ ํ๋ ์๋ฃํ, ๋ฉ์๋ ์๊ทธ๋์ฒ ๋ฑ์ ์ ๋ณด๋ค์ ์ป์ด๋ผ ์ ์๋ค(์ด๋ฐ ๊ณต๊ฒฉ์ ๋ง์ผ๋ ค๋ฉด ๋๋ฒ์งธ instance๋ฅผ ์์ฑํ๋ ์์ฒญ์ด ์ฌ ๋ ์์ฑ์์์ Exception์ ๋ฐ์์ํค๊ฒ ์์ ํด์ผํ๋ค).
์ฑ๊ธํด ํด๋์ค๋ฅผ ์ง๋ ฌํ ๊ฐ๋ฅ(Serializable
) ํด๋์ค๋ก ๋ง๋ค๋ ค๋ฉด ํด๋์ค ์ ์ธ์ implements Serializable
์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก๋ ๋ถ์กฑํ๋ค. ์ฑ๊ธํด ํน์ฑ์ ์ ์งํ๋ ค๋ฉด ๋ชจ๋ ํ๋๋ฅผ transient๋ก ์ ์ธํ๊ณ readResolve
๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด serialize๋ ๊ฐ์ฒด๊ฐ ์ญ์ง๋ ฌํ๋ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๊ฐ ์๊ธฐ๊ฒ ๋๋ค.
//์ฑ๊ธํด ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ํ readResolve ๊ตฌํ
private Object readResolve() {
//๋์ผํ Elvis ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋๋ก ํ๋ ๋์์, ๊ฐ์ง Elvis ๊ฐ์ฒด๋
//GC๊ฐ ์ฒ๋ฆฌํ๋๋ก ๋ง๋ ๋ค.
return INSTANCE;
}
JDK 1.5๋ถํฐ๋ ์ฑ๊ธํด์ ๊ตฌํํ ๋ ์๋ก์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค. ์์๊ฐ ํ๋๋ฟ์ธ enum
์๋ฃํ์ ์ ์ํ๋ ๊ฒ์ด๋ค.
public enum Elvis {
INSTNACE;
public void leaveTheBuilding() {
// ...
}
}
public static void main(String[] args) {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
๊ธฐ๋ฅ์ ์ผ๋ก๋ public
ํ๋๋ฅผ ์ฌ์ฉํ๋ ๊ตฌํ๋ฒ๊ณผ ๋๋ฑํ๋ค. ํ ๊ฐ์ง ์ฐจ์ด๋ ์ข ๋ ๊ฐ๊ฒฐํ๋ค๋ ๊ฒ๊ณผ, ์ง๋ ฌํ๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ๋๋ค๋ ๊ฒ์ด๋ค. ์ง๋ ฌํ๊ฐ ์๋ฌด๋ฆฌ ๋ณต์กํ๊ฒ ์ด๋ฃจ์ด์ ธ๋ ์ฌ๋ฌ ๊ฐ์ฒด๊ฐ ์๊ธธ ์ผ์ด ์์ผ๋ฉฐ, ๋ฆฌํ๋ ์
์ ํตํ ๊ณต๊ฒฉ์๋ ์์ ํ๋ค. ์์๊ฐ ํ๋๋ฟ์ธ enum
์๋ฃํ์ด์ผ๋ง๋ก ์ฑ๊ธํด์ ๊ตฌํํ๊ธฐ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.