1. 싱글톤 패턴이란?
- 런타임 동안 "단 하나의 인스턴스만을 생성"하는 패턴
- 싱글톤 패턴이 적용된 객체는 하나의 인스턴스만 생성할 수 있고, 다른 객체에서 싱글톤 객체의 인스턴스를 생성하려 할 경우, 기존에 생성된 인스턴스가 있다면 해당 인스턴스를 반환하는 형태로 사용됨.
- 모든 데이터를 전역으로 관리하여 쉽게 접근할 수 있게 하는 것
- 객체의 메모리를 정적으로 할당하여 하나의 객체에만 접근하는 방법
2. 싱글톤 패턴을 사용하는 경우
1) 공통된 객체를 여러개 생성해서 사용해야 하는 경우
2) 인스턴스가 절대적으로 한 개만 존재해야 한다는 것을 명시하고 싶은 경우
3. 싱글톤 패턴의 장점
1) 편리성 : 최초로 생성된 객체 하나에만 접근하게 되므로 데이터를 접근하고 수정하는데 용이함.
2) 중복방지 : 생성자를 다른 곳에서 새롭게 선언을 하더라도 이미 정적으로 선언된 객체가 반환되기 때문에 중복되어 생성되는 것을 방지할 수 있음.
3) 빠른접근 : 초기 객체 생성시 정적 메모리에 올라가 이후 호출할 때 아주 빠르게 접근할 수 있음.
4) 메모리절약 : 많은 클래스에서 동일한 객체의 인스턴스를 생성해야하는 경우. 싱글톤 패턴을 사용하여 매번 인스턴스를 생성하지 않고 불러서 쓰는 형태로 사용할 수 있어 메모리 절약이 가능하다.
4. 싱글톤 패턴의 단점
1) 성능저하 : 정적 메모리에 할당할 수 있는 메모리 크기가 제한적이기 때문에, 정적 메모리에 할당된 객체로 너무 큰 메모리가 쌓이게 되면 프로그램 성능이 현저하게 낮아질 수 있음.
2) 높은결합도 : 프로그램이 복잡해지면서 싱글톤 인스턴스가 혼자 너무 많은 일을 하거나 많은 데이터를 공유하게 되면 다른 클래스들 간의 결합도가 높아지게 된다. 이는 OOP 설계원칙 중 개방-폐쇄 원칙에 위배되고, 디버깅 등의 협업에 어려움이 생겨 유지보수가 어려워질 수 있다.
3) 메모리접근 : 하나의 정적 메모리를 사용하기 때문에 병렬처리나 동기화와 같이 여러방법으로 메모리에 접근하는데 문제가 생길 수 있음. (병렬처리나 동기화를 위한 방법이 따로 존재함)
5. 코드 구현
1) 일반 싱글톤
public class Singleton
{
private static Singeton _instance;
public static Singleton Instance
{
get
{
// 생성된 인스턴스가 없는 경우 -> 새로 생성
if(_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
public Singleton() {}
}
2) Lazy 싱클톤
- 인스턴스의 생성시기를 선언 즉시 생성하는 것이 아닌, 인스턴스 내의 값에 접근하려 할 때 생성하는 방법
- 생성된 인스턴스에 접근을 위한 thread-safety를 고려하지 않아도 됨
- Lazy 싱글톤을 이용한 thread-safety는 인스턴스 생성에 대한 thread-safety를 보장하는 것임
public class LazySingleton<T> where T : LazySingleton<T>, new()
{
private static Lazy<T> lazyInstance = null;
public static T Instance
{
get
{
// 인스턴스가 존재하지 않는 경우에 새로 생성
// 존재하는 경우에는 기존의 것을 사용
if(Exists() == false)
{
var instance = new T();
lazyInstance = new Lazy<T>(() => instance);
}
return lazyInstance.Value;
}
}
// 인스턴스가 존재하는지 확인
public static bool Exists()
{
return lazyInstance != null && lazyInstance.IsValueCreated;
}
// 인스턴스를 초기화시킴
public static void ClearInstance()
{
lazyInstance = null;
}
}
3) Unity 싱글톤(MonoBehaviour)
public class Singleton : MonoBehaviour
{
private static Singleton _instance;
public static Singleton Instance
{
get
{
// 인스턴스가 생성되지 않은 경우 -> 새로 생성
// 이미 생성된 경우 -> 기존에 생성된 것을 사용
if(_instance == null)
{
_instance = (Singleton)FindObjectOfType(typeof(Singleton));
}
return _instance;
}
}
}
4) thread-safety 싱글톤
public sealed class Singleton
{
private static volatile Singleton _instance;
private static object syncRoot = new object();
private Singleton() {}
public static Singleton Instance
{
get
{
if(_instance == null)
{
lock(syncRoot)
{
if(_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
}
}
<참고 사이트>