정적 클래스 대신 싱글톤 패턴을 사용해야 하는 경우는 언제인가요?[닫은]

StackOverflow https://stackoverflow.com/questions/46541

  •  09-06-2019
  •  | 
  •  

문제

사용 여부를 결정할 때 설계 고려 사항을 설명하세요. 하나씩 일어나는 것 정적 클래스와 비교.이렇게 하면 두 가지를 대조해야 하기 때문에 어떤 대조를 생각해 내더라도 사고 과정을 보여주는 데 유용합니다!또한 모든 면접관은 예시를 보는 것을 좋아합니다.:)

도움이 되었습니까?

해결책

  • 싱글톤은 인터페이스를 구현하고 다른 클래스에서 상속할 수 있습니다.
  • 싱글톤은 지연 로드될 수 있습니다.실제로 필요할 때만.초기화에 비용이 많이 드는 리소스 로딩이나 데이터베이스 연결이 포함된 경우 매우 편리합니다.
  • 싱글톤은 실제 객체를 제공합니다.
  • 싱글톤은 팩토리로 확장될 수 있습니다.배후에 있는 개체 관리는 추상적이므로 유지 관리가 더 쉽고 코드가 더 좋습니다.

다른 팁

"둘 다 피하는 것"은 어떻습니까?싱글톤 및 정적 클래스:

  • 전역 상태를 도입할 수 있음
  • 다른 여러 클래스와 긴밀하게 결합
  • 종속성 숨기기
  • 격리된 단위 테스트 클래스를 어렵게 만들 수 있음

대신에 살펴보세요 의존성 주입 그리고 제어 컨테이너의 반전 도서관.여러 IoC 라이브러리가 수명 관리를 대신 처리합니다.

(항상 그렇듯이 정적 수학 클래스 및 C# 확장 메서드와 같은 예외가 있습니다.)

유일한 차이점은 구문이라고 생각합니다.MySingleton.Current.Whatever() 대 MySingleton.Whatever().David가 언급했듯이 상태는 두 경우 모두 궁극적으로 "정적"입니다.


편집하다:매장 여단이 디그에서 왔습니다 ...어쨌든 나는 싱글톤이 필요한 경우를 생각했습니다.정적 클래스는 기본 클래스에서 상속할 수도 없고 인터페이스를 구현할 수도 없습니다(적어도 .Net에서는 불가능합니다).따라서 이 기능이 필요한 경우 싱글톤을 사용해야 합니다.

이 문제에 관해 제가 가장 좋아하는 토론 중 하나는 다음과 같습니다. 여기 (원래 사이트가 다운되었으나 이제 링크됨 인터넷 아카이브 웨이백 머신.)

싱글톤의 유연성 이점을 요약하면 다음과 같습니다.

  • 싱글 톤은 공장으로 쉽게 변환 할 수 있습니다
  • 싱글 톤을 쉽게 수정하여 다른 서브 클래스를 반환 할 수 있습니다.
  • 이로 인해 더 유지 관리하기 쉬운 응용 프로그램이 될 수 있습니다.

정적 변수가 많이 포함된 정적 클래스는 약간의 해킹입니다.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

실제 인스턴스가 있는 싱글톤이 더 좋습니다.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

상태는 인스턴스에만 있습니다.

따라서 싱글톤은 나중에 풀링, 스레드 로컬 인스턴스 등을 수행하도록 수정될 수 있습니다.그리고 이점을 얻기 위해 이미 작성된 코드를 변경할 필요가 없습니다.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

정적 클래스를 사용하여 유사한 작업을 수행하는 것이 가능하지만 간접 디스패치에는 호출별 오버헤드가 있습니다.

인스턴스를 가져와 함수에 인수로 전달할 수 있습니다.이렇게 하면 코드를 "올바른" 싱글톤으로 보낼 수 있습니다.우리는 당신에게 그 중 하나만 필요하다는 것을 알고 있습니다 ...그렇지 않을 때까지.

가장 큰 이점은 상태 저장 싱글턴을 스레드로부터 안전하게 만들 수 있는 반면, 정적 클래스는 비밀 싱글턴으로 수정하지 않는 한 그렇게 할 수 없다는 점입니다.

싱글톤을 서비스로 생각해보세요.특정 기능 세트를 제공하는 객체입니다.예:

ObjectFactory.getInstance().makeObject();

개체 팩토리는 특정 서비스를 수행하는 개체입니다.

대조적으로, 정적 메소드로 가득 찬 클래스는 수행하려는 작업의 모음이며 관련 그룹(클래스)으로 구성됩니다.예:

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

여기의 StringUtils 예제는 어디에나 적용할 수 있는 기능 모음입니다.싱글톤 팩토리 객체는 필요한 곳에 생성하고 전달할 수 있는 명확한 책임이 있는 특정 유형의 객체입니다.

정적 클래스는 런타임에 인스턴스화됩니다.시간이 많이 걸릴 수 있습니다.싱글톤은 필요한 경우에만 인스턴스화할 수 있습니다.

싱글톤은 정적 클래스와 같은 방식으로 사용하면 안 됩니다.본질적으로,

MyStaticClass.GetInstance().DoSomething();

본질적으로 다음과 같습니다

MyStaticClass.DoSomething();

실제로 당신이 해야 할 일은 싱글톤을 또 다른 객체로 취급.서비스에 싱글톤 유형의 인스턴스가 필요한 경우 해당 인스턴스를 생성자에 전달합니다.

var svc = new MyComplexServce(MyStaticClass.GetInstance());

서비스는 개체가 싱글톤이라는 사실을 인식해서는 안 되며 개체를 단순한 개체로 처리해야 합니다.

개체는 구현 세부 사항 및 전체 구성의 측면으로 확실히 구현될 수 있으며, 그렇게 하면 작업이 더 쉬워집니다.그러나 그 객체를 사용하는 것들은 그 객체가 싱글톤인지 아닌지를 알 필요는 없습니다.

"정적 클래스"가 정적 변수만 포함하는 클래스를 의미하는 경우 실제로 상태를 유지할 수 있습니다.내 이해는 유일한 차이점은 이 항목에 액세스하는 방법이라는 것입니다.예를 들어:

MySingleton().getInstance().doSomething();

~ 대

MySingleton.doSomething();

MySingleton의 내부는 분명히 서로 다르지만 스레드 안전성 문제를 제외하고 클라이언트 코드와 관련하여 둘 다 동일하게 수행됩니다.

싱글톤 패턴은 일반적으로 여러 스레드가 동시에 데이터에 액세스할 수 있는 인스턴스 독립 또는 정적 데이터를 서비스하는 데 사용됩니다.한 가지 예로 주 코드를 들 수 있습니다.

싱글톤은 절대 사용하면 안 됩니다(변경 가능한 상태가 없는 클래스를 싱글톤으로 간주하지 않는 한)."정적 클래스"에는 스레드로부터 안전한 캐시 등을 제외하고는 변경 가능한 상태가 없어야 합니다.

싱글톤의 거의 모든 예는 이를 수행하지 않는 방법을 보여줍니다.

싱글톤을 폐기하고 정리할 수 있는 경우 리소스가 제한적일 때(예:단 1개만) 항상 필요하지는 않으며 할당 시 일종의 메모리 또는 리소스 비용이 발생합니다.

정리 코드는 정적 상태 필드를 포함하는 정적 클래스와 달리 싱글톤이 있을 때 더 자연스러워 보입니다.

그러나 코드는 어느 쪽이든 동일하게 보일 것이므로 요청해야 할 더 구체적인 이유가 있는 경우 자세히 설명해야 할 것입니다.

둘은 상당히 유사할 수 있지만, 진정한 싱글톤은 다음과 같아야 한다는 점을 기억하세요. 그 자체 인스턴스화(부여, 한 번)된 다음 제공됩니다.인스턴스를 반환하는 PHP 데이터베이스 클래스 mysqli 인스턴스를 정적 ​​멤버로 갖는 클래스의 인스턴스가 아니라 다른 클래스의 인스턴스를 반환하기 때문에 실제로는 싱글톤(일부 사람들이 부르는 것처럼)이 아닙니다.

따라서 코드에서 하나의 인스턴스만 허용하려는 새 클래스를 작성하는 경우 해당 클래스를 싱글톤으로 작성하는 것이 좋습니다.단일 인스턴스화 요구 사항을 용이하게 하기 위해 일반 클래스를 작성하고 추가하는 것으로 생각하십시오.수정할 수 없는 다른 사람의 클래스를 사용하는 경우(예: mysqli), 정적 클래스를 사용해야 합니다(해당 정의 앞에 키워드를 붙이지 못한 경우에도 마찬가지입니다).

싱글톤은 더 유연하므로 Instance 메서드가 일부 컨텍스트에 따라 싱글톤 유형의 다양한 구체적인 하위 클래스를 반환하도록 하려는 경우에 유용할 수 있습니다.

정적 클래스는 인수로 전달될 수 없습니다.싱글톤의 인스턴스가 될 수 있습니다.다른 답변에서 언급했듯이 정적 클래스의 스레딩 문제를 살펴보세요.

rp

싱글톤에는 생성자와 소멸자가 있을 수 있습니다.언어에 따라 생성자는 싱글톤이 처음 사용될 때 자동으로 호출될 수도 있고, 싱글톤이 전혀 사용되지 않는 경우에는 호출되지 않을 수도 있습니다.정적 클래스에는 이러한 자동 초기화가 없습니다.

싱글톤 객체에 대한 참조를 얻은 후에는 다른 객체와 마찬가지로 사용할 수 있습니다.싱글톤에 대한 참조가 이전에 저장된 경우 클라이언트 코드는 싱글톤을 사용하는지 알 필요조차 없습니다.

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

이는 IoC와 같은 실제 패턴을 선호하여 싱글톤 패턴을 버리기로 선택한 경우 분명히 작업을 더 쉽게 만듭니다.

조회 테이블과 같이 가능하다면 컴파일 타임에 계산할 항목을 런타임에 계산해야 하는 경우 싱글톤 패턴을 사용하세요.

내 생각에 Singleton이 정적 클래스보다 더 적합한 곳은 비용이 많이 드는 리소스 풀(예: 데이터베이스 연결)을 구성해야 할 때라고 생각합니다.아무도 풀을 사용하지 않는다면 풀을 만드는 데 관심이 없을 것입니다(정적 클래스는 클래스가 로드될 때 비용이 많이 드는 작업을 수행한다는 것을 의미합니다).

데이터를 효율적으로 캐싱하려는 경우에도 싱글톤을 사용하는 것이 좋습니다.예를 들어 XML 문서에서 정의를 조회하는 클래스가 있습니다.문서를 구문 분석하는 데 시간이 걸릴 수 있으므로 정의 캐시를 설정했습니다(outOfmemeoryErrors를 방지하기 위해 SoftReferences를 사용합니다).원하는 정의가 캐시에 없으면 값비싼 XML 구문 분석을 수행합니다.그렇지 않으면 캐시에서 복사본을 반환합니다.캐시가 여러 개 있으면 동일한 정의를 여러 번 로드해야 할 수도 있으므로 정적 캐시가 필요합니다.나는 일반(비정적) 데이터 멤버만 사용하여 클래스를 작성할 수 있도록 이 클래스를 싱글톤으로 구현하기로 선택했습니다.이를 통해 어떤 이유로든 필요할 경우(직렬화, 단위 테스트 등) 클래스의 인스턴스화를 계속 생성할 수 있습니다.

싱글톤은 이미 언급했듯이 서비스와 같습니다.Pro는 유연성입니다.정적, 싱글톤을 구현하려면 정적 부분이 필요합니다.

싱글톤에는 실제 객체의 인스턴스화를 처리하는 코드가 있는데, 이는 레이싱 문제가 발생할 경우 큰 도움이 될 수 있습니다.정적 솔루션에서는 여러 코드 위치에서 경주 문제를 처리해야 할 수도 있습니다.

그러나 Singleton이 일부 정적 변수로 구성될 수 있는 것과 마찬가지로 'goto'와 비교할 수 있습니다.이는 다른 구조를 구축하는 데 매우 유용할 수 있지만 실제로는 사용 방법을 알아야 하며 '과용'해서는 안 됩니다.따라서 일반적인 권장 사항은 Singleton을 고수하고 필요한 경우 static을 사용하는 것입니다.

다른 게시물도 확인하세요. 싱글톤 구현 대신 정적 클래스를 선택하는 이유는 무엇입니까?

나타내다 이것

요약:

ㅏ.따를 수 있는 쉬운 경험 법칙 중 하나는 상태를 유지할 필요가 없으면 Static 클래스를 사용할 수 있고, 그렇지 않으면 Singleton을 사용해야 한다는 것입니다.

비.특히 "무거운" 개체인 경우에는 싱글톤을 사용합니다.개체가 크고 적당한 양의 메모리를 차지하는 경우 n/w 호출(연결 풀) 등이 많이 발생합니다.여러 번 인스턴스화되지 않도록 합니다.Singleton 클래스는 이러한 경우가 발생하는 것을 방지하는 데 도움이 됩니다.

단일 클래스에 상태가 필요한 경우.싱글톤은 전역 상태를 유지하지만 정적 클래스는 그렇지 않습니다.

예를 들어 레지스트리 클래스를 중심으로 도우미를 만드는 경우:변경 가능한 하이브가 있는 경우(HKey 현재 사용자 대HKEY 로컬 머신) 다음과 같이 갈 수 있습니다.

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

이제 해당 싱글톤에 대한 추가 호출은 로컬 머신 하이브에서 작동됩니다.그렇지 않으면 정적 클래스를 사용하여 항상 로컬 머신 하이브를 지정하거나 다음과 같은 메서드가 있어야 합니다. ReadSubkeyFromLocalMachine.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top