Design patterns
하나씩 일어나는 것
수색…
비고
싱글 톤 디자인 패턴은 때로는 " 안티 패턴 "으로 간주됩니다. 이것은 약간의 문제가 있다는 사실 때문입니다. 당신이 그것을 사용하는 것이 적절하다고 생각한다면 스스로 결정해야합니다. 이 주제는 StackOverflow에서 여러 번 논의되었습니다.
참조 : http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
싱글 톤 (C #)
싱글 톤은 객체의 하나의 인스턴스 만 생성되도록하기 위해 사용됩니다. 싱글 톤은 자신의 단일 인스턴스 만 만들어 지도록 허용합니다. 즉, 싱글 톤은 자신의 생성을 제어합니다. 싱글 톤은 Gang of Four 디자인 패턴 중 하나이며 창조적 인 패턴 입니다.
스레드 안전 싱글 톤 패턴
public sealed class Singleton
{
private static Singleton _instance;
private static object _lock = new object();
private Singleton()
{
}
public static Singleton GetSingleton()
{
if (_instance == null)
{
CreateSingleton();
}
return _instance;
}
private static void CreateSingleton()
{
lock (_lock )
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
}
Jon Skeet 은 게으른 스레드 안전 싱글 톤에 대해 다음과 같은 구현을 제공합니다.
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
싱글 톤 (Java)
Java에서의 싱글 톤은 C #과 매우 유사합니다. 두 언어 모두 객체 지향적입니다. 아래는 단일 톤 클래스의 예입니다.이 프로그램의 수명 기간 동안 하나의 객체 버전 만이 살아있을 수 있습니다 (하나의 스레드에서 프로그램이 작동한다고 가정)
public class SingletonExample {
private SingletonExample() { }
private static SingletonExample _instance;
public static SingletonExample getInstance() {
if (_instance == null) {
_instance = new SingletonExample();
}
return _instance;
}
}
다음은 해당 프로그램의 스레드 안전 버전입니다.
public class SingletonThreadSafeExample {
private SingletonThreadSafeExample () { }
private static volatile SingletonThreadSafeExample _instance;
public static SingletonThreadSafeExample getInstance() {
if (_instance == null) {
createInstance();
}
return _instance;
}
private static void createInstance() {
synchronized(SingletonThreadSafeExample.class) {
if (_instance == null) {
_instance = new SingletonThreadSafeExample();
}
}
}
}
자바는 또한 ThreadLocal
이라는 객체를 가지고 있는데, 스레드 기반 객체에 대한 단일 인스턴스를 생성한다. 이것은 각 스레드가 객체의 자체 버전을 필요로하는 응용 프로그램에서 유용 할 수 있습니다
public class SingletonThreadLocalExample {
private SingletonThreadLocalExample () { }
private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();
public static SingletonThreadLocalExample getInstance() {
if (_instance.get() == null) {
_instance.set(new SingletonThreadLocalExample());
}
return _instance.get();
}
}
다음은 enum
(단일 요소 만 포함)을 사용하는 Singleton 구현입니다.
public enum SingletonEnum {
INSTANCE;
// fields, methods
}
모든 Enum 클래스 구현은 각 요소가 하나만 존재한다는 것을 보장합니다.
빌 Pugh 싱글 톤 패턴
Bill Pugh Singleton Pattern은 동기화가 필요하지 않으므로 Singleton 클래스에서 가장 널리 사용되는 방법입니다.
public class SingletonExample {
private SingletonExample(){}
private static class SingletonHolder{
private static final SingletonExample INSTANCE = new SingletonExample();
}
public static SingletonExample getInstance(){
return SingletonHolder.INSTANCE;
}
}
내부 정적 클래스를 사용하면 누군가가 getInstance 메소드를 호출 할 때까지 홀더가 메모리에로드되지 않습니다. Bill Pugh 솔루션은 스레드로부터 안전하며 동기화가 필요하지 않습니다.
Java documentation 태그 아래 Singletons 항목에는 더 많은 Java 싱글 톤 예제가 있습니다.
싱글 톤 (C ++)
Wiki 별 : 소프트웨어 엔지니어링에서 싱글 톤 패턴은 클래스의 인스턴스화를 하나의 객체로 제한하는 디자인 패턴입니다.
이는 시스템 전체에서 작업을 조정하기 위해 정확히 하나의 객체를 생성하는 데 필요합니다.
class Singleton
{
// Private constructor so it can not be arbitrarily created.
Singleton()
{}
// Disable the copy and move
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
public:
// Get the only instance
static Singleton& instance()
{
// Use static member.
// Lazily created on first call to instance in thread safe way (after C++ 11)
// Guaranteed to be correctly destroyed on normal application exit.
static Singleton _instance;
// Return a reference to the static member.
return _instance;
}
};
자바에서 게으른 싱글 톤 실용 예제
싱글 톤 패턴의 실제 사용 사례;
클라이언트 - 서버 응용 프로그램을 개발중인 경우, 클라이언트 연결의 수명주기를 관리하는 ConnectionManager
단일 인스턴스가 필요합니다.
ConnectionManager의 기본 API :
registerConnection
: 기존 연결 목록에 새 연결 추가
closeConnection
: 클라이언트 또는 서버에 의해 트리거 된 이벤트에서 연결을 닫 closeConnection
.
broadcastMessage
: 때때로 구독 한 모든 클라이언트 연결에 메시지를 보내야합니다.
예제가 매우 길어질 것이므로 완전한 소스 코드 구현을 제공하지는 않습니다. 높은 수준에서 코드는 다음과 같습니다.
import java.util.*;
import java.net.*;
/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class LazyConnectionManager {
private Map<String,Connection> connections = new HashMap<String,Connection>();
private LazyConnectionManager() {}
public static LazyConnectionManager getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
}
/* Make sure that De-Serailzation does not create a new instance */
private Object readResolve() {
return LazyHolder.INSTANCE;
}
public void registerConnection(Connection connection){
/* Add new connection to list of existing connection */
connections.put(connection.getConnectionId(),connection);
}
public void closeConnection(String connectionId){
/* Close connection and remove from map */
Connection connection = connections.get(connectionId);
if ( connection != null) {
connection.close();
connections.remove(connectionId);
}
}
public void broadcastMessage(String message){
for (Map.Entry<String, Connection> entry : connections.entrySet()){
entry.getValue().sendMessage(message);
}
}
}
샘플 서버 클래스 :
class Server implements Runnable{
ServerSocket socket;
int id;
public Server(){
new Thread(this).start();
}
public void run(){
try{
ServerSocket socket = new ServerSocket(4567);
while(true){
Socket clientSocket = socket.accept();
++id;
Connection connection = new Connection(""+ id,clientSocket);
LazyConnectionManager.getInstance().registerConnection(connection);
LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
}
}catch(Exception err){
err.printStackTrace();
}
}
}
싱글 톤을위한 다른 실제 사용 사례 :
-
ThreadPool, ObjectPool, DatabaseConnectionPool
등의 전역 자원 관리 -
DEBUG,INFO,WARN,ERROR
등 다양한 로그 수준의Logging
어플리케이션 데이터와 같은 중앙 집중식 서비스 - 글로벌
RegistryService
. 시작시 중앙 서비스 구성 요소에 다른 서비스가 등록됩니다. 글로벌 서비스는 응용 프로그램의Facade
로 작동 할 수 있습니다.
C # 예제 : 다중 스레드 싱글 톤
정적 초기화는 대부분의 상황에 적합합니다. 응용 프로그램이 인스턴스화를 연기해야하거나 인스턴스 생성 전에 기본이 아닌 생성자를 사용하거나 다른 작업을 수행하고 다중 스레드 환경에서 작업해야하는 경우 다른 솔루션이 필요합니다. 그러나 정적 초기화 예제에서와 같이 공용 언어 런타임에 의존하여 스레드 안전을 보장 할 수없는 경우가 있습니다. 이 경우 특정 언어 기능을 사용하여 여러 스레드가있는 상태에서 하나의 개체 인스턴스 만 생성되도록해야합니다. 보다 일반적인 해결책 중 하나는 Double-Check Locking [Lea99] 관용구를 사용하여 개별 스레드가 동시에 단일 인스턴스의 새 인스턴스를 작성하지 못하도록하는 것입니다.
다음 구현은 Singleton 인스턴스가 아직 생성되지 않은 경우 단일 스레드 만 잠금 블록이 식별하는 중요 영역에 들어갈 수 있습니다.
using System;
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;
}
}
}
이 방법을 사용하면 하나의 인스턴스 만 생성되고 인스턴스가 필요할 때만 생성됩니다. 또한 변수는 인스턴스 변수에 액세스하기 전에 인스턴스 변수에 대한 할당이 완료되도록 volatile로 선언됩니다. 마지막으로,이 접근법은 교착 상태를 피하기 위해 syncRoot 인스턴스를 사용하여 유형 자체를 잠그지 않고 잠급니다.
이 이중 점검 잠금 방식은 인스턴스 속성 메서드에 대한 모든 호출에서 배타적 잠금을 피하면서 스레드 동시성 문제를 해결합니다. 또한 객체에 처음 액세스 할 때까지 인스턴스화를 지연 할 수 있습니다. 실제로 응용 프로그램에서는 이러한 유형의 구현이 거의 필요하지 않습니다. 대부분의 경우 정적 초기화 방식으로 충분합니다.
참조 : MSDN
감사 인사
[감마 95] 감마, 조타 장치, 존슨 및 Vlissides. 디자인 패턴 : 재사용 가능한 객체 지향 소프트웨어의 요소. Addison-Wesley, 1995.
레아, 더그. Java, Second Edition에서의 동시 프로그래밍. Addison-Wesley, 1999.
[Sells03] Sells, Chris. "봉인 된 녀석들." sellsbrothers.com 뉴스. http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 에서 다운로드 할 수 있습니다.
싱글 톤 (PHP)
<?php class Singleton { /** * @var Singleton The reference to *Singleton* instance of this class */ private static $instance; /** * Returns the *Singleton* instance of this class. * * @return Singleton The *Singleton* instance. */ public static function getInstance() { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } /** * Protected constructor to prevent creating a new instance of the * *Singleton* via the `new` operator from outside of this class. */ protected function __construct() { } /** * Private clone method to prevent cloning of the instance of the * *Singleton* instance. * * @return void */ private function __clone() { } /** * Private unserialize method to prevent unserializing of the *Singleton* * instance. * * @return void */ private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); // bool(true) $anotherObj = SingletonChild::getInstance(); var_dump($anotherObj === Singleton::getInstance()); // bool(false) var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)
싱글 톤 디자인 패턴 (일반적으로)
참고 : 싱글 톤은 디자인 패턴입니다.
그러나 그것은 또한 반 패턴을 고려했다.
싱글 톤 사용은 사용하기 전에 신중하게 고려해야합니다. 일반적으로 더 나은 대안이 있습니다.
싱글 톤의 주요 문제점은 전역 변수의 문제와 동일합니다. 그들은 외부 글로벌 가변 상태를 도입합니다. 즉, 싱글 톤을 사용하는 함수는 입력 매개 변수뿐 아니라 싱글 톤의 상태에도 종속되지 않습니다. 이는 테스트가 심하게 손상 될 수 있음을 의미합니다.
싱글 톤 문제는 생성 패턴과 함께 사용하여 완화 할 수 있습니다. 따라서 싱글 톤의 초기 생성을 제어 할 수 있습니다.