JAVA/Design Pattern

싱글톤 패턴 (Singleton Pattern)

반응형

대게 

공용으로 사용하는 유틸성 클래스의 경우

하나의 공용 인스턴스 객체를 생성하고 

필요로 할 때마다, 해당 이스턴스 객체에 접근 하여 사용한다.

이를 싱글톤 패턴이라고 한다.

싱글톤 패턴
- 하나의 인스턴스만을 생성하는 책임이 있으며, getInstance 메소드를 통해 모든 클라이언트에게 동일한 인스턴스를 반환한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
// 유틸성 클래스의 경우 인스턴스 객체를 만들거나 상속을 할 필요가 없으므로 final과 private 생성자를 만든다.
public final class Util {
  private Utill () {}
  private Util util = null;
 
  public static Util getUtil() {
   if (util == null ) {
     util = new Util();
   }
 
   return util;
  } 
}
cs



하지만 이경우 동시에 여러 스레드가 Util 클래스의 접근하였을 때

경합 조건이 발생하여 두 개 이상의 스레드가 인스턴스 객체를 만들려고 시도 할 수 있다. 

이런경우에 문제가 싱글톤의 장점이 사라진다.

또한 단순히 정보만을 전달해주는 클래스일 경우에는 큰 문제가 없을 수 있으나,

스태틱 변수가 아닌 멤벼 변수 값의 경우 여러 인스턴스 객체가 만들어지면 

잘못된 데이터가 출력되기 때문에 문제가 발생할 수 있다.

ex)
int count = 10;

public void upCount() {
count++;
}

해결방법
1. 정적 변수에 인스턴스를 만들어 초기화 하기 




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 방법 1 
public class Util {
 private static Util = new Util();
 private Util() {}
 
}
 
 
// 방법 2. (Lazy 방식)
public class Util {
  private Util() {}
  public static Util getInstance() {
    return LazyHolder.INSTANCE;
  }
  
  private static class LazyHolder {
    private static final Util INSTANCE = new Util();  
  }
}
cs



클래스가 로드 되는 경우에는 초기화가 한번만 이루어 지기 때문에 인스턴스 객체가 여러개 발생할 수 있는 문제가 야기되지 않는다.

2. Enum 클래스로 사용하기
 Enum은 인스턴스가 여러 개 생기지 않도록 확실하게 보장해주고 복잡한 직렬화나 리플렉션 상황에서도 직렬화가 자동으로 지원된다는 장점이 있어서 

Enum 을 사용해서 싱글톤 패턴을 사용하면 좋다.



1
2
3
4
5
6
7
8
9
10
11
12
13
// Enum
public enum Util {
    INSTANCE;
    
    public void getData() {
        System.out.println("db");
    }
}
 
// Main 사용
public void main(String args[]) {
  Util.INSTANCE.getData();
}
cs



3. 인스턴스 생성 메서드 동기화 하기

1
2
3
4
5
6
7
8
9
10
11
12
public final class Util {
  private Utill () {}
  private Util util = null;
 
  public synchronized static Util getUtil() {
   if (util == null ) {
     util = new Util();
   }
 
   return util;
  } 
}
cs



정적 클래스 VS 싱글톤 객체

정적 클래스는 굳이 인스턴스 객체를 공유해서 사용하지 않고, 정적 클래스를 이용해서 유틸성 클래스를 사용할 수 있다.

또한 정적 메서드를 사용하므로 인스턴스를 사용하는것 보다 성능적으로 우수하다. (컴파일 바인딩 부분에서)

하지만 이런 정적 클래스가 장점이 있어도 사용하지 못하는 경우가 있었다.

항상 모든 메서드가 정적 메서드이어야 하는 정적 클래스의 경우 
공통으로 사용하는 인터페이스의 메서드 또한 정적 메서드여야 한다.

하지만 인터페이스에서 구현된 static 메서드는 상속받아서 구현할 수 없기 때문에 문제가 발생할 수 있다.

하지만 

싱글톤 패턴의 경우 스태틱 메서드를 사용하지 않으므로 인터페이스의 내용을 구현하여 
인스턴스 메서드를 사용할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
public interface Utils {
    static void getData() {
            System.out.println("dbs");
    }
}
 
public class UtilClass implements Utils {
    @Override
    public static void getData() { // 오류 발생
        
    }
}
cs



위와 같은 문제가 아니라면
정적 클래스를 사용하는 것이 싱글톤보다 더욱 편해보인다.



반응형