[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item3. private ์ƒ์„ฑ์ž๋‚˜ ์—ด๊ฑฐ ํƒ€์ž…์œผ๋กœ ์‹ฑ๊ธ€ํ†ค์ž„์„ ๋ณด์ฆํ•˜๋ผ. (private ์ƒ์„ฑ์ž + public static final ํ•„๋“œ )

2023. 1. 9. 13:22ใ†JAVA/Effective JAVA

728x90

 

์•„์ดํ…œ3. private ์ƒ์„ฑ์ž๋‚˜ ์—ด๊ฑฐ ํƒ€์ž…์œผ๋กœ ์‹ฑ๊ธ€ํ†ค์ž„์„ ๋ณด์ฆํ•˜๋ผ. 

 

 

์‹ฑ๊ธ€ํ†ค singleton ์ด๋ž€? 

: ์ธ์Šคํ„ด์Šค๋ฅผ ์˜ค์ง ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ์˜๋ฏธํ•œ๋‹ค. 

์‹ฑ๊ธ€ํ†ค์˜ ์˜ˆ๋กœ๋Š” ์„ค๊ณ„์ƒ ์œ ์ผํ•ด์•ผ ํ•˜๋Š” ์‹œ์Šคํ…œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๊ฒŒ์ž„์—์„œ ์–ธ์–ดํŒฉ ๊ฐ™์€ ๊ฒƒ์ด ์žˆ๋‹ค. (๋ณดํ†ต ์–ธ์–ด๋ฅผ '์˜์–ด'๋กœ ํ–ˆ๋‹ค ํ•˜๋ฉด ์–ด๋–ค ์„ค์ •์—์„œ๋Š” ํ•œ๊ตญ์–ด์ด๊ณ , ์–ด๋–ค ์„ค์ •์—์„œ๋Š” ์ผ๋ณธ์–ด์ด๊ณ  ํ•˜๋ฉด ์•ˆ๋˜๋‹ˆ๊นŒ ํ•˜๋‚˜์˜ ์–ธ์–ด๋กœ ์œ ์ง€ํ•œ๋‹ค.) 

 

๊ทธ๋Ÿฐ๋ฐ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค. 

์‹ฑ๊ธ€ํ†ค ํด๋ž˜์Šค ์ค‘์—์„œ๋„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•œ ๋‹ค์Œ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ๋งŒ๋“  ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์งœ mock ๊ตฌํ˜„์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค... 

 

 

์‹ฑ๊ธ€ํ†ค singleton ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• 1 

: private ์ƒ์„ฑ์ž + public static final ํ•„๋“œ 

๋จผ์ € ์ƒ์„ฑ์ž๋Š” private๋กœ ์ˆจ๊ธฐ๊ณ , ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋‹จ์„ public static final ๋ฐฉ์‹์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด๋‹ค. 

 

public class Elvis 
{
	// ์‹ฑ๊ธ€ํ†ค ์˜ค๋ธŒ์ ํŠธ
	public static final Elvis INSTANCE = new Elvis();
    
    private Elvis(){}
    
    public void leaveTheBuilding()
	{
		System.out.println("Whoa baby, I'm outta here!");
	}
	
	public void sing()
	{
		System.out.println("I'll have a blue ~ Christmas without you~");
	}
	
}

private ์ƒ์„ฑ์ž๋Š” public static final ํ•„๋“œ์ธ Elvis.INSTANCE๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋œ๋‹ค. 

public์ด๋‚˜ protected ์ƒ์„ฑ์ž๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— Elvis ํด๋ž˜์Šค๊ฐ€ ์ดˆ๊ธฐํ™” ๋  ๋•Œ ๋งŒ๋“ค์–ด์ง„ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ „์ฒด ์‹œ์Šคํ…œ์—์„œ ํ•˜๋‚˜๋ฟ์ž„์ด ๋ณด์žฅ๋œ๋‹ค. 

 

 

๊ทผ๋ฐ  ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์งˆ ์ˆ˜ ์žˆ๋Š”  ๋‘๊ฐ€์ง€์˜ ์˜ˆ์™ธ๊ฐ€ ์กด์žฌํ•œ๋‹ค. 

๊ถŒํ•œ์ด ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ API์ธ AccessibleObject.setAccessible ์„ ์‚ฌ์šฉํ•ด private ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

public static void main(String[] args)
{
   Elvis elvis = Elvis.INSTANCE;
   elvis.leaveTheBuilding();
   
   // ์ƒ์„ฑ์ž๋กœ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค ๋งŒ๋“ค๊ธฐ
   // ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค..!!!
   try
   {
      Constructor<Elvis> defaultConstructor = Elvis.class.getDeclaredConstructor();
      defaultConstructor.setAccessible(true); // true ๋กœ ์•ˆํ•˜๋ฉด Elvis๋Š” ์ƒ์„ฑ์ž๊ฐ€ private์—ฌ์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๊ฒŒ๋จ
      Elvis elvis1 = defaultConstructor.newInstance();
      Elvis elvis2 = defaultConstructor.newInstance();
      System.out.println("(elvis1 == elvis2) = " + (elvis1 == elvis2));
   }
   catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e)
   {
      throw new RuntimeException(e);
   }
   
   
}

์ด๋ ‡๊ฒŒ ๋ฆฌํ”Œ๋ ‰์…˜์—์„œ setAccessible์„ true๋กœ ์„ค์ •ํ•˜๋ฉด privae ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. 

์ด๋Ÿฐ ๊ณต๊ฒฉ์„ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ˆ˜์ •ํ•ด์„œ ๋‘๋ฒˆ์งธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋ ค ํ•  ๋•Œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๊ฒŒ ํ•˜๋ฉด ๋œ๋‹ค. 

 

 

public class Elvis implements Serializable
{
   // ์‹ฑ๊ธ€ํ†ค ์˜ค๋ธŒ์ ํŠธ
   public static final Elvis INSTANCE = new Elvis();
   private static boolean created;
   
   private Elvis()
   {
      if (created) {
         // ๋ฆฌํ”Œ๋ ‰์…˜ ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋ ค๋ฉด ์ƒ์„ฑ์ž๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ๋‘ ๋ฒˆ์งธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋ ค ํ•  ๋•Œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๊ฒŒ ํ•˜๋ฉด ๋œ๋‹ค.
         throw new UnsupportedOperationException("can't be created by constructor");
      }
      created = true;
   }
   
   public void leaveTheBuilding()
   {
      System.out.println("Whoa baby, I'm outta here!");
   }
   
   public void sing()
   {
      System.out.println("I'll have a blue ~ Christmas without you~");
   }
   
   // ์‹ฑ๊ธ€ํ†ค์ž„์„ ๋ณด์žฅํ•ด์ฃผ๋Š” readResolve ๋ฉ”์„œ๋“œ
   // ์—ญ์ง๋ ฌํ™”๋ฅผ ํ•  ๋•Œ readResolve๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ƒ์„ฑํ•œ INSTANCE๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ฉด
   // ์—ญ์ง๋ ฌํ™” ํ•  ๋•Œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.
   private Object readResolve()
   {
      return INSTANCE;
   }
   

   
}

created flag๋ฅผ ๋‘์–ด์„œ ์ด๋ฏธ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•ด์„œ true์ด๋ฉด UnsupportedOperationException์„ ๋ฐœ์ƒ์‹œํ‚ค๋„๋ก ํ–ˆ๋‹ค. 

 

๊ทธ๋ฆฌ๊ณ  ์‹ฑ๊ธ€ํ„ด ํด๋ž˜์Šค๋ฅผ ์ง๋ ฌํ™”ํ•˜๋ ค๋ฉด Serializable๋งŒ ๊ตฌํ˜„ํ•˜๋Š”๊ฒŒ ๋์ด ์•„๋‹ˆ๋ผ readResolve ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. 

์™œ๋ƒํ•˜๋ฉด ์—ญ์ง๋ ฌํ™”ํ•  ๋•Œ readResolve๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ฐธ์กฐํ•ด์„œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์œ„์— ์ฝ”๋“œ์ฒ˜๋Ÿผ readResolve๋ฐ˜ํ™˜ ๊ฐ’์„ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋กœ ๋ฐ˜ํ™˜ํ•ด์คฌ๋‹ค. 

 

public static void main(String[] args)
{
   // ์—ญ์ง๋ ฌํ™”๋กœ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค ๋งŒ๋“ค๊ธฐ
   // ์ €์žฅํ•˜๋Š” ์ฝ”๋“œ
   try (ObjectOutput output = new ObjectOutputStream(new FileOutputStream("elvis.obj")))
   {
      output.writeObject(Elvis.INSTANCE);
   }
   catch (IOException e)
   {
      e.printStackTrace();
   }
   
   // ์ฝ์–ด์˜ค๋Š” ์ฝ”๋“œ (์ €์žฅ์„ ํ–ˆ๋‹ค๊ฐ€ ์ฝ์–ด์˜ฌ ๋•Œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.)
   try (ObjectInput in = new ObjectInputStream(new FileInputStream("elvis.obj")))
   {
      Object elvis3 = in.readObject();
      System.out.println("(elvis3 == Elvis.INSTANCE) = " + (elvis3 == Elvis.INSTANCE)); // false
   }
   catch (IOException | ClassNotFoundException e) {
      e.printStackTrace();
   }
}

readResolve() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ๊ณ  ๋‚˜๋ฉด (elvis3 == Elvis.INSTANCE) = true๊ฐ€ ๋‚˜์˜จ๋‹ค. 

 

 

 

๐Ÿ“ข private ์ƒ์„ฑ์ž + public static final ํ•„๋“œ ๋ฐฉ๋ฒ• ์žฅ๋‹จ์  

 

์žฅ์ 

: ๊ฐ„๊ฒฐํ•˜๊ณ  ์‹ฑ๊ธ€ํ†ค์ž„์„ API์— ๋“ค์–ด๋‚ผ ์ˆ˜์žˆ๋‹ค. 

 

๋‹จ์ 

: ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค. 

  ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ private ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. 

  ์—ญ์ง๋ ฌํ™” ํ•  ๋•Œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.  

 

 

 

 

 

 

 

 

 

 

 

728x90