[Effective Java] Item 3. private ์์ฑ์๋ enum ํ์ ์ผ๋ก ์ฑ๊ธํค์์ ๋ณด์ฅํ์.
by rlaehddnd0422์ฑ๊ธํค์ด๋?
์ฑ๊ธํค์ด๋ ์ธ์คํด์ค๋ฅผ ๋จ 1๊ฐ๋ง ์์ฑํ ์ ์๋ ํด๋์ค๋ฅผ ๋งํฉ๋๋ค.
ex) ๋ฌด์ํ ๊ฐ์ฒด, ์ค๊ณ ์ ์ ์ผํด์ผ ํ๋ ์์คํ ์ปดํฌ๋ํธ (service, repository)
์ฑ๊ธํค ์ฅ์
- ํ ๋ฒ์ ๊ฐ์ฒด ์์ฑ์ผ๋ก ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์, ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
- ์ฑ๊ธํค์ผ๋ก ์์ฑ๋ ๊ฐ์ฒด๋ ์ ์ญ์ฑ์ ๋๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๊ฐ์ฒด์ ๊ณต์ ๊ฐ ์ฉ์ดํฉ๋๋ค.
์ฑ๊ธํค ๋จ์
- ํด๋ผ์ด์ธํธ๋ฅผ ํ ์คํธํ๊ธฐ ์ด๋ ต์ต๋๋ค.
- private ์์ฑ์๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์์์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
- ์๋ฒ์์ ํด๋์ค ๋ก๋๋ฅผ ์ด๋ป๊ฒ ๊ตฌ์ฑํ๊ณ ์๋์ง์ ๋ฐ๋ผ ๋๋ ์ฌ๋ฌ ๊ฐ์ JVM์ ๋ถ์ฐ๋์ด ์๋ ๊ฒฝ์ฐ ์ฑ๊ธํค ํด๋์ค์ฌ๋ ํ๋ ์ด์์ ์ธ์คํด์ค๊ฐ ๋ง๋ค์ด์ง ์ ์์ต๋๋ค.
- ์ ์ญ ์ํ๋ก ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋์งํ์ง ๋ชปํฉ๋๋ค.
- ์ฌ์ค ์๋ฌด ๊ฐ์ฒด๋ ์์ ๋กญ๊ฒ ์ ๊ทผํ๊ณ ์์ ํ๊ณ ๊ณต์ ํ ์ ์๋ ์ ์ญ ์ํ๋ฅผ ๊ฐ๋ ๊ฒ์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋จ์ด์์๋ ๊ถ์ฅ๋์ง ์์ต๋๋ค.
์ฑ๊ธํค ๋ง๋๋ ๋ฐฉ์ 1 - public static final
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis(){}
}
class ElvisTest {
@Test
void singleToneTest() {
Elvis elvis = Elvis.INSTANCE;
Elvis elvis2 = Elvis.INSTANCE;
assertEquals(elvis, elvis2);
}
}
- ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์, ํด๋์ค ๋ด๋ถ์ public static ๋ฉค๋ฒ๋ฅผ ํ๋ ์์ฑํด ๋๊ณ final๋ก ์ค์ ํ์ฌ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
- ์ฌ๊ธฐ์ private ์์ฑ์๋ public static final ํ๋์ธ Elvis.INSTANCE๋ฅผ ์ด๊ธฐํ ํ ๋ ๋ฑ ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค.
- public์ด๋ protected ์์ฑ์๊ฐ ์์ผ๋ฏ๋ก ๋ค๋ฅธ ํจํค์ง์์ ์์ฑํ ์ ์์์ ๋ณด์ฅํด์ฃผ๋ฉฐ, ์ด๊ธฐํ ํ ๋ ๋ฑ ํ ๋ฒ ํธ์ถํจ์ผ๋ก์จ ์ธ์คํด์ค๊ฐ ์ ์ฒด ์์คํ ์์ ํ๋ ๋ฟ์์ด ๋ณด์ฅ๋ฉ๋๋ค.
- ์ด ๋ฐฉ์์ ํด๋น ํด๋์ค๊ฐ ์ฑ๊ธํค์์ ํ์คํ ๋๋ฌ๋ด๊ณ , ๊ฐ๊ฒฐํ๋ค๋ ๊ฒ์ด ์ฅ์
์์ธ ์ผ์ด์ค : ์๋ ์ฝ๋์ ๊ฐ์ด ๋ฆฌํ๋ ์ API ( AccessibleObject.setAccessible)์ ์ฌ์ฉํด private ์์ฑ์๋ฅผ ํธ์ถํ๋ ๋ฐฉ๋ฒ
@Test
void reflectionBreakSingleton()
throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Elvis elvis = Elvis.INSTANCE;
Constructor<Elvis> constructor = (Constructor<Elvis>) elvis.getClass().getDeclaredConstructor();
constructor.setAccessible(true);
Elvis elvis2 = constructor.newInstance();
assertNotSame(elvis, elvis2);
}
- ์ด๋ฐ ๊ณต๊ฒฉ์ ๋ง๊ธฐ ์ํด, ์์ฑ์๋ฅผ ์์ ํ์ฌ ๋ ๋ฒ์งธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ ค ํ ๋ ์์ธ๋ฅผ ๋์ง์ผ๋ก์จ ๋ง์ ์ ์๊ฒ ์ต๋๋ค.
public class Presley {
public static final Presley INSTANCE = new Presley();
private Presley() {
if (INSTANCE != null) {
throw new RuntimeException("์์ฑ์๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.");
}
}
}
์ฑ๊ธํค ๋ง๋๋ ๋ฐฉ์ 2 - ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ public static ๋ฉค๋ฒ๋ก ์ ๊ณตํ๊ธฐ
public class Greenday {
private static final Greenday INSTANCE = new Greenday();
private Greenday() {}
public static Greenday getInstance() {
return INSTANCE;
}
}
class GreendayTest {
@Test
void singletonTest() {
Greenday greenday1 = Greenday.getInstance();
Greenday greenday2 = Greenday.getInstance();
assertEquals(greenday1, greenday2);
}
}
- ๋ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ฒซ ๋ฒ์งธ ๋ฐฉ์์ ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ์์ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ ๋ฐฉ์์ผ๋ก ์ ์ํ ๋ฐฉ์์ ๋๋ค.
- ์ด ๋ฐฉ์์ ์ฅ์ ์ ์ฑ๊ธํค ๋ฐฉ์์ ํ๊ณ ์ถ์ ๋ API๋ฅผ ๋ฐ๊พธ์ง ์๊ณ ๋ ๋ณ๊ฒฝํ ์ ์๋ค๋ ์ ์
๋๋ค.
- ์๋ ์ฝ๋์ฒ๋ผ ๋ด๋ถ์์ INSTANCE๊ฐ ์๋ ์ ์ธ์คํด์ค๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋๊ฒ ์ต๋๋ค.
public class Greenday {
private static final Greenday INSTANCE = new Greenday();
private Greenday() {}
public static Greenday getInstance() {
return new Greenday();
}
}
class GreendayTest {
@Test
void singletonTest() {
Greenday greenday1 = Greenday.getInstance();
Greenday greenday2 = Greenday.getInstance();
assertNotEquals(greenday1, greenday2);
}
}
- ๋ ๋ฒ์งธ ์ฅ์ ์ ์ํ๋ค๋ฉด ์ ์ ํฉํ ๋ฆฌ๋ฅผ ์ฑ๊ธํค ํฉํ ๋ฆฌ๋ก ๋ง๋ค ์ ์๋ค๋ ์ ์ ๋๋ค. (Item 30 ์ฐธ๊ณ )
- ์ ์ ํฉํ ๋ฆฌ์ ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ๊ณต๊ธ์๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. (Item 43, Itme 44 ์ฐธ๊ณ )
- Greenday::getInstance๋ฅผ Supplier<Greenday>๋ก ์ฌ์ฉํด์ ์๋์ฒ๋ผ ์ฌ์ฉํ ์ ์์
Supplier<Greenday> greendaySupplier = Greenday::getInstance;
Greenday greenday = greendaySupplier.get();
์ ๋๊ฐ์ง ๋ฐฉ์์ ๋ฌธ์ ์
์ ๋ ๊ฐ์ง ๋ฐฉ์์ ๋ฌธ์ ์ ์ ๊ฐ ํด๋์ค๋ฅผ ์ง๋ ฌํ(๊ฐ์ฒด๋ฅผ ์ ์ฅ, ์ ์กํ ์ ์๋ ํน์ ํฌ๋งท์ผ๋ก ๋ณํํ๋ ๊ณผ์ )ํ ํ ์ญ์ง๋ ฌํ(ํน์ ํฌ๋งท ์ํ์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ฒด๋ก ๋ณํ)ํ ๋ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค๋ ์ ์ ๋๋ค.
- ์ญ์ง๋ ฌํ๋ ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ํธ์ถํ์ง ์๊ณ ์ธ์คํด์ค์ ๊ฐ์ ๋ณต์ฌํด์ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ฐํํฉ๋๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด readResolve ๋ฉ์๋๋ฅผ ํ๋ ๋ง๋ค์ด ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ๋ฐํํ๊ณ , ๋ชจ๋ ํ๋์ transient ํค์๋๋ฅผ ๋ฃ์ด์ฃผ๋ ๋ฐฉ์์ด ์์ต๋๋ค.
transient ํค์๋ : ํ๋์ ์ํ๊ฐ์ ์ ์กํ์ง ์๋๋ค๋ ํค์๋
public class Greenday {
// transient private static final Greenday INSTANCE = new Greenday();
private static final Greenday INSTANCE = new Greenday();
private Greenday() {}
public static Greenday getInstance() {
return INSTANCE;
}
private Greenday readResolve() {
// '์ง์ง' Greenday๋ฅผ ๋ฆฌํดํ๊ณ , ๊ฐ์ง Greenday๋ ๊ฐ๋น์ง ์ปฌ๋ ํฐ์ ๋งก๊ธด๋ค.
return INSTANCE;
}
}
- readResolve ๋ฉ์๋๋ ์ญ์ง๋ ฌํ ๊ณผ์ ์์ ๋ฐ๋์ ํธ์ถ๋ฉ๋๋ค.
- ์ด๋ ๊ฒ ์ค์ ํ๋ฉด ์ญ์ง๋ ฌํ ๊ณผ์ ์์ ์ฑ๊ธํค์ผ๋ก ๋ง๋ค์ด๋ ์ง์ง ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋๋ก ์ค์ ๋์ด, ๊ฐ์ ๋ณต์ฌํ ์๋ก์ด ์ธ์คํด์ค๋ ๊ฐ๋น์ง ์ปฌ๋ ํฐ๋ก ๋์ด๊ฐ๊ฒ ๋ฉ๋๋ค.
- ๋ฐฉ์ด์ ์ผ๋ก transient ํค์๋๋ฅผ ๋ฃ์ด ์ง๋ ฌํ ๊ณผ์ ์์ ํ๋์ ์ํ๊ฐ ์ ์ก์ ๋ง์ ์ญ์ง๋ ฌํ ๊ณผ์ ์์ ๋ณต์ฌํ ๊ฐ ์์ฒด๋ฅผ ์์ ๋ณด๋ด์ง ์๋๋ก ์ค์ ํ ์๋ ์๊ฒ ์ต๋๋ค.
์ฑ๊ธํค ๋ง๋๋ ๋ฐฉ์ 3 - enum ํ์
public enum ColdBrew {
INSTANCE;
}
- ์ธ ๋ฒ์งธ ๋ฐฉ๋ฒ์ enumํ์
์ผ๋ก ์ฑ๊ธํค์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ผ๋ก ,public ํ๋ ๋ฐฉ์๊ณผ ๋น์ทํ์ง๋ง, ํจ์ฌ ๊ฐ๊ฒฐํ๊ฒ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ์์ผ๋ก, ๋ณต์กํ ์ง๋ ฌํ ์ํฉ์ด๋ ๋ฆฌํ๋ ์
๊ณต๊ฒฉ์์๋ ์ 2์ ์ธ์คํด์ค๊ฐ ์๊ธฐ๋ ์ผ์ ์๋ฒฝํ ๋ง์์ค๋๋ค.
- ์ด๊ฑฐํ ํ์ ์ผ๋ก ์ฑ๊ธํค์ ์ ์ฉํ๋ ๊ฒ์ด ์กฐ๊ธ ์ด์ํ ์ ์์ง๋ง, ๋๋ถ๋ถ ์ํฉ์์๋ ์์๊ฐ ํ๋๋ฟ์ธ ์ด๊ฑฐ ํ๋น์ด ์ฑ๊ธํค์ ๋ง๋๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋๋ค.
- ๋ง๋๋ ค๋ ์ฑ๊ธํค์ด enum์ธ์ ํด๋์ค๋ฅผ ์์ํด์ผ ํ๋ค๋ฉด ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. (์ธํฐํ์ด์ค๋ ๊ตฌํํ๋๋ก ์ ์ธํ ์๋ ์์)
- public enum ColdBrew extends ~ (X), public enum ColdBrew implements ~ (O)
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422