C #의 싱글 톤은 무엇입니까?


181

싱글 톤이란 무엇이며 언제 사용해야합니까?



4
또한 Singleton은 OO 프로그래밍에서 가장 널리 사용되고 악용되는 디자인 패턴 중 하나입니다.
ChaosPandion

3
@Fabiano : 이해가되지 않는 커플 링을 만드는 방법이 있기 때문에 (어떻게 X이야기 할 수 Y있습니까? Y단일 톤을 만드십시오 !) 결과적으로 테스트 / 디버깅 및 절차 적 프로그래밍 스타일로 이어집니다. 때로는 싱글 톤이 필요합니다. 대부분은 아닙니다.
Aaronaught

3
이것은 내 표준 전화 인터뷰 질문 중 하나입니다. 정답은 : 결코.
jonnii

3
@ jonnii 그것은 좋은데, 그것은 보스가 무엇인지 예상 개발자에게 경고하는 데 도움이됩니다!
Mr. Boy

답변:


144

싱글 톤은 하나의 인스턴스 만 만들 수있는 클래스이며, 해당 인스턴스에 간단하고 쉽게 액세스 할 수 있습니다. 싱글 톤 전제는 소프트웨어 개발 전반에 걸친 패턴입니다.

스레드 안전성 에 대한 좋은 조언을 포함하여 알아야 할 대부분의 내용을 다루는 C # 구현 " C # 에서 싱글 톤 패턴 구현 "이 있습니다.

솔직히 말해서 싱글 톤을 구현 해야하는 경우는 매우 드-니다. 제 생각에 너무 자주 사용하지 않더라도 알아야 할 것들 중 하나 여야합니다.


2
좋은 튜토리얼이지만 거룩한 쓰레기 코드 들여 쓰기에
대해 한

다음은 2020 년에 이상적인 구현으로 간주되는 것에 대한 직접 링크입니다. 즉, " .NET 4의 Lazy <T> 유형 사용 "과 Microsoft 문서에 대한 링크 Lazy<T> Class입니다.
Chiramisu

52

C #을 요청했습니다. 사소한 예 :


public class Singleton
{
    private Singleton()
    {
        // Prevent outside instantiation
    }

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}

14
스레드 안전하지 않음. 두 개의 스레드는 동시에 호출 할 수 있으며 두 개의 별도 개체를 만들 수 있습니다.
Alagesan Palani

5
@Alagesan Palani, 정말로 맞습니다. 클래스 수준 초기화에 대한 저수준 세부 사항에 능숙하지 않지만 변경 사항이 스레드 안전 문제를 해결한다고 생각합니다.
Chris Simmons

3
확실히, 나는 당신이 틀렸다고 지적하지 않습니다. 독자에게 스레드 안전성에 대한 힌트를 제공하므로 처리 해야하는 경우 조심해야합니다.
Alagesan Palani

9
아니요, 귀하의 의견이 중요하다고 생각합니다. 싱글 톤이 하나의 인스턴스 만 전달한다고 가정하면 여기에서 경쟁 조건은 둘 이상이 전달 될 가능성을 엽니 다. 정적 필드 초기화로 버전을 확인하십시오. 내가 읽으면 나는이 수정에게 스레드 안전 문제를 생각 워드 프로세서이 SO의 대답을 제대로.
Chris Simmons

1
@AlagesanPalani, 다른 답변이 스레드 안전하지 않다고 말한 것으로 나타났습니다. 스레드로부터 안전한 솔루션을 제공 하시겠습니까?
Bonez024

39

의미 : 응용 프로그램 수명 동안 영구 인스턴스가 하나 뿐인 클래스입니다. 싱글 톤 패턴을 참조하십시오 .

사용해야 할 때 : 가능한 적은. 당신이 경우에만 절대적으로 확신 당신이 그것을 필요. "never"라고 말하지는 않지만 Dependency Injection 또는 정적 클래스와 같은 더 나은 대안이 있습니다.


16
정적 클래스가 싱글 톤보다 더 나은 대안인지 확실하지 않습니다 ... 실제로 상황과 언어에 달려 있습니다.
marcgg

5
정적 클래스는 싱글 톤과 같은 방식으로 동작하지 않으며 싱글 톤은 메소드로 매개 변수로 전달 될 수 있지만 정적 클래스는 그렇지 않습니다.
TabbyCool

4
marcgg에 동의-정적 클래스를 싱글 톤에 대한 좋은 대안으로 생각하지 않습니다. 예를 들어이 클래스에 의존하는 구성 요소를 테스트하는 동안 대체물을 제공하는 데 문제가 있기 때문입니다. 그러나 다른 용도로도 볼 수 있습니다. 정적 클래스는 일반적으로 상태와 독립적 인 독립 유틸리티 함수에 사용되며 싱글 톤은 실제 클래스 인스턴스이며 일반적으로 상태를 저장합니다. DI를 대신 사용하기로 동의 한 다음 DI 컨테이너에 해당 클래스의 단일 인스턴스 만 사용하도록 지시합니다.
Pete

9
나는이 답변을 언제 사용할 지에 대한 정보를 제공하지 않기 때문에 downvoted. "필요할 때만"실제로 싱글 톤을 처음 접하는 사람에 대한 정보는 전혀 없습니다.
Sergio Tapia

9
@Adkins : DI는 의존성 주입 (Dependency Injection)의 약자로, 클래스 의존성이 생성자 또는 공용 속성을 통해 전달되는 경우입니다. DI만으로는 "거리"문제를 해결할 수 없지만 일반적으로 종속성을 자동으로 초기화하는 방법을 알고있는 IoC (Inversion-of-Control) 컨테이너와 함께 구현됩니다. 따라서 "X가 Y를 찾거나 대화하는 방법을 모른다"라는 문제를 해결하기 위해 Singleton을 만드는 경우 DI와 IoC를 결합하면 느슨한 커플 링으로 동일한 문제를 해결할 수 있습니다.
Aaronaught

27

C #에서 싱글 톤을 구현하는 또 다른 방법은 개인적 으로이 방법을 선호합니다. 싱가 톤 클래스의 인스턴스를 메소드 대신 속성으로 액세스 할 수 있기 때문입니다.

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }

        //instance methods
    }

그러나 두 가지 방법 모두 '올바른'것으로 간주되는 한, 그것은 개인적인 취향의 일입니다.


11
스레드 안전하지 않음. 두 개의 스레드는 동시에 호출 할 수 있으며 두 개의 별도 개체를 만들 수 있습니다.
Alagesan Palani

11
using System;
using System.Collections.Generic;
class MainApp
{
    static void Main()
    {
        LoadBalancer oldbalancer = null;
        for (int i = 0; i < 15; i++)
        {
            LoadBalancer balancerNew = LoadBalancer.GetLoadBalancer();

            if (oldbalancer == balancerNew && oldbalancer != null)
            {
                Console.WriteLine("{0} SameInstance {1}", oldbalancer.Server, balancerNew.Server);
            }
            oldbalancer = balancerNew;
        }
        Console.ReadKey();
    }
}

class LoadBalancer
{
    private static LoadBalancer _instance;
    private List<string> _servers = new List<string>();
    private Random _random = new Random();

    private static object syncLock = new object();

    private LoadBalancer()
    {
        _servers.Add("ServerI");
        _servers.Add("ServerII");
        _servers.Add("ServerIII");
        _servers.Add("ServerIV");
        _servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
        if (_instance == null)
        {
            lock (syncLock)
            {
                if (_instance == null)
                {
                    _instance = new LoadBalancer();
                }
            }
        }

        return _instance;
    }

    public string Server
    {
        get
        {
            int r = _random.Next(_servers.Count);
            return _servers[r].ToString();
        }
    }
}

dofactory.com 에서 코드를 가져 왔지만 그렇게 멋진 것은 아니지만 Foo and Bar가있는 예제보다 C # 3.0 Design Patterns에 대한 Judith Bishop의 추가 책 보다 Mac 도크의 활성 응용 프로그램에 대한 예제가 있습니다.

코드를 보면 실제로 for 루프에 새 객체를 작성하고 있으므로 새 객체를 만들지 만 oldbalancer와 newbalancer가 동일한 인스턴스를 갖는 결과로 인스턴스를 재사용합니다. 어떻게? 그 인해 고정 기능을 사용 키워드 GetLoadBalancer () , 임의의리스트에서 정적 인 다른 서버의 값을 갖는 불구 GetLoadBalancer ()를 타입 자체보다는 특정 개체에 속한다.

또한 이중 확인 잠금이 있습니다.

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)

MSDN부터

lock 키워드는 한 스레드가 중요한 코드 섹션에 들어 가지 않고 다른 스레드가 중요한 섹션에 있도록합니다. 다른 스레드가 잠긴 코드를 입력하려고하면 객체가 해제 될 때까지 기다립니다.

따라서 매번 상호 배제 잠금이 필요합니다. 불필요하더라도 불필요하므로 null 검사가 있습니다.

잘하면 그것은 더 많은 것을 지우는 데 도움이됩니다.

내 이해가 잘못된 길을 가고 있다면 의견을 말하십시오.


6

Singleton (그리고 이것은 C #에 묶여 있지 않으며 OO 디자인 패턴입니다)은 응용 프로그램 전체에서 클래스의 인스턴스를 하나만 만들 수있게하려는 경우입니다. 개인적인 경험으로는 말할 것이지만, 종종 큰 고통의 원천이되지만 사용에는 일반적으로 전 세계 자원이 포함됩니다.


5

싱글 톤의 인스턴스는 하나만있을 수 있지만 정적 클래스와 동일하지 않습니다. 정적 클래스는 정적 메서드 만 포함 할 수 있으며 인스턴스화 할 수 없지만 싱글 톤 인스턴스는 다른 객체와 같은 방식으로 사용될 수 있습니다.


2

디자인 패턴이며 C #에만 국한되지 않습니다. 이 위키 백과 기사 와 같이 인터넷과 SO를 통해 더 많은 정보를 얻을 수 있습니다.

소프트웨어 엔지니어링에서 싱글 톤 패턴은 클래스의 인스턴스화를 하나의 객체로 제한하는 데 사용되는 디자인 패턴입니다. 시스템 전체에서 작업을 조정하는 데 정확히 하나의 개체가 필요한 경우에 유용합니다. 이 개념은 때때로 하나의 객체 만 존재할 때보다 효율적으로 작동하거나 인스턴스화를 특정 개수의 객체 (예 : 5)로 제한하는 시스템으로 일반화됩니다. 일부는 그것을 과도하게 사용한다고 판단하여 반 패턴으로 간주하고, 클래스의 유일한 인스턴스가 실제로 필요하지 않은 상황에서 불필요한 제한을 초래하며, 전역 상태를 애플리케이션에 도입합니다.

한 번만 등록 할 수있는 수업을 원할 경우 사용해야합니다.


2

조회 데이터에 사용합니다. DB에서 한 번로드하십시오.

public sealed class APILookup
    {
        private static readonly APILookup _instance = new APILookup();
        private Dictionary<string, int> _lookup;

        private APILookup()
        {
            try
            {
                _lookup = Utility.GetLookup();
            }
            catch { }
        }

        static APILookup()
        {            
        }

        public static APILookup Instance
        {
            get
            {
                return _instance;
            }
        }
        public Dictionary<string, int> GetLookup()
        {
            return _lookup;
        }

    }

2

싱글 톤이란 무엇인가 :
하나의 인스턴스 만 생성 할 수있는 클래스이며 일반적으로 해당 인스턴스에 대한 간단한 액세스를 제공합니다.

사용시기 :
상황에 따라 다릅니다.

참고 : DB 연결에서 사용하지 마십시오. 자세한 답변은 @Chad Grant의 답변을 참조하십시오

다음은 간단한 예입니다 Singleton.

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

Lazy<T>을 만들 수도 있습니다 Singleton.

자세한 사용 예는 여기참조하십시오.Lazy<T>


1

싱글 톤은 다음과 같습니다. http://en.wikipedia.org/wiki/Singleton_pattern

C #을 모르지만 실제로는 모든 언어에서 동일하지만 구현 만 다릅니다.

가능하면 일반적으로 싱글 톤을 피해야하지만 경우에 따라 매우 편리합니다.

내 영어 죄송합니다;)


영어는 괜찮습니다 :)
FrenkyB

1

Singleton 클래스는 전체 응용 프로그램 도메인에 대한 단일 인스턴스를 만드는 데 사용됩니다.

public class Singleton
{
    private static Singleton singletonInstance = CreateSingleton();

    private Singleton()
    {
    }

    private static Singleton CreateSingleton()
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

    public static Singleton Instance
    {
        get { return singletonInstance; }            
    }
}

에서 이 문서는 설명 우리는 읽기 전용 변수와 응용 프로그램에서의 실용화를 사용하여 스레드 안전한 싱글 톤 클래스를 만드는 방법.


1

질문에 대답하기가 너무 늦다는 것을 알고 있지만 자동 속성을 사용하면 다음과 같은 작업을 수행 할 수 있습니다.

public static Singleton Instance { get; } = new Singleton();

어디에서 Singleton수업을 할 수 있습니까? 이 경우에는 readonly 속성 Instance입니다.


0

EX 주입해야하는 글로벌 정보에 Singleton을 사용할 수 있습니다.

필자의 경우 Logged 사용자 세부 정보 (사용자 이름, 권한 등)를 Global Static Class에 유지했습니다. 그리고 단위 테스트를 구현하려고 할 때 컨트롤러 클래스에 종속성을 주입 할 수있는 방법이 없었습니다. 따라서 정적 클래스를 싱글 톤 패턴으로 변경했습니다.

public class SysManager
{
    private static readonly SysManager_instance = new SysManager();

    static SysManager() {}

    private SysManager(){}

    public static SysManager Instance
    {
        get {return _instance;}
    }
}

http://csharpindepth.com/Articles/General/Singleton.aspx#cctor


0

특정 클래스의 인스턴스 하나만 생성되도록하고 전체 애플리케이션에 대해 해당 인스턴스에 대한 간단한 글로벌 액세스를 제공해야하는 경우 C #에서 싱글 톤 디자인 패턴을 사용해야합니다.

싱글 톤 디자인 패턴을 사용할 수있는 실시간 시나리오 : 서비스 프록시 : 우리가 알고 있듯이 서비스 API를 호출하는 것은 애플리케이션에서 광범위한 작업입니다. 대부분의 시간이 걸리는 프로세스는 서비스 API를 호출하기 위해 서비스 클라이언트를 작성하는 것입니다. 서비스 프록시를 싱글 톤으로 작성하면 애플리케이션의 성능이 향상됩니다.

외관 : 응용 프로그램의 성능을 향상시킬 수있는 데이터베이스 연결을 Singleton으로 만들 수도 있습니다.

로그 : 응용 프로그램에서 파일에 대한 I / O 작업 수행은 비용이 많이 드는 작업입니다. Logger를 Singleton으로 만들면 I / O 작업의 성능이 향상됩니다.

데이터 공유 : 상수 값이나 구성 값이 있으면이 값을 Singleton으로 유지하여 응용 프로그램의 다른 구성 요소에서 읽을 수 있습니다.

캐싱 : 데이터베이스에서 데이터를 가져 오는 것은 시간이 많이 걸리는 프로세스입니다. 애플리케이션에서 마스터 및 구성을 메모리에 캐시하여 DB 호출을 피할 수 있습니다. 이러한 상황에서 Singleton 클래스를 사용하면 스레드 동기화로 캐싱을 처리하여 응용 프로그램의 성능을 크게 향상시킬 수 있습니다.

C #에서 싱글 톤 디자인 패턴의 단점 C #에서 싱글 톤 디자인 패턴을 사용하는 단점은 다음과 같습니다.

단위 테스트는 응용 프로그램에 전역 상태를 도입하기 때문에 매우 어렵습니다. 다중 스레드 환경에서 싱글 톤 인스턴스에 액세스하려면 잠금을 사용하여 오브젝트를 직렬화해야하므로 프로그램 내에서 병렬 처리의 가능성이 줄어 듭니다.

나는 다음 기사에서 이것을 취했다.

https://dotnettutorials.net/lesson/singleton-design-pattern/


0

잠금을 사용하지 않고 게으른 인스턴스화없이 Safe Singleton을 스레드합니다.

이 구현에는 정적 생성자가 있으므로 응용 프로그램 도메인 당 한 번만 실행됩니다.

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

    public static Singleton Instance { get; } = new Singleton();

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.