정적 클래스 대신 싱글 톤 패턴을 언제 사용해야합니까? [닫은]


85

싱글 톤 사용 과 정적 클래스 사용 사이를 결정할 때 설계 고려 사항의 이름을 지정합니다 . 이렇게 할 때, 당신은 두 가지를 대조하도록 강요받습니다. 그래서 당신이 생각 해낼 수있는 어떤 대조는 당신의 사고 과정을 보여주는 데에도 유용합니다! 또한 모든 면접관은 예시를보고 싶어합니다. :)


자바 클래스하지 않는 한 자사의 내부 클래스 정적을 할 수 없습니다
Harshana

1
객체의 상태가 중요하다면 싱글 톤을 사용하고 그렇지 않으면 정적 클래스를 사용하십시오.
Levent Divilioglu 2015

답변:


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

2
이 링크도 살펴보세요 : codeofdoom.com/wordpress/2008/04/20/…
Amit

4
"Singletons can be lazy loaded"-C #에서 정적 생성자는 정적 멤버가 처음 참조 될 때만 호출됩니다. PHP에서는 자동 로딩을 사용하여 클래스를 처음 사용할 때만 실행할 수 있습니다.
mpen 2013 년

Java 정적 초기화도 지연됩니다. 싱글 톤에 대한 점수가 없습니다.
MikeFHay dec

13

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

  • 글로벌 상태를 소개 할 수 있습니다.
  • 여러 다른 클래스와 긴밀하게 연결
  • 종속성 숨기기
  • 격리 된 단위 테스트 클래스를 어렵게 만들 수 있습니다.

대신 종속성 주입제어 컨테이너 라이브러리의 반전을 . 여러 IoC 라이브러리가 수명 관리를 대신 처리합니다.

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


1
작은 nits : 싱글 톤 클래스는 의존성 주입 기술과 호환됩니다 (종속 클래스에 주입하고 아무것도 하드 코딩 할 필요가 없습니다). 또한 제한된 플랫폼으로 알려진 리소스를 관리하기위한 유효한 디자인 패턴입니다. (전통적인 예는 경합 관리가없는 프린터입니다.)
cdleary

@cdleary-동의 함; 그러나 고전적인 구현은 종종 코드베이스 전체에 Singleton.getInstance ()를 남깁니다. 리소스, 캐시 등을 관리하기위한 "싱글 톤"은 수명 관리를 지원하는 POCO / POJO 및 IoC 컨테이너 프레임 워크로 구현할 수 있습니다 (유형을 컨테이너 수명으로 등록하면 모든 해결에 동일한 인스턴스가 적용됨).
TrueWill

9
Singleton에 적절한 매장을 제공하려면 singletonfuneralservice.com으로
TrueWill

1
Hide Dependencies이 점에 대한 작은 정보 : 예를 들어 Ninject 를 사용하여 Inversion of Control 패턴을 구현할 수 있습니다 . 이를 통해 유형의 인스턴스를에 바인딩하여 하나의 인스턴스 만 사용할 수 있습니다. SingletonScope즉 , 동일한 인스턴스를 항상 주입 하지만 클래스는 싱글 톤이 아닙니다.
LuckyLikey

8

유일한 차이점은 구문 인 MySingleton.Current.Whatever () 대 MySingleton.Whatever ()입니다. 데이비드가 언급했듯이 국가는 두 경우 모두 궁극적으로 "정적"입니다.


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


7

이 문제에 대해 제가 가장 좋아하는 토론 중 하나는 여기입니다 (원래 사이트 다운, 이제 Internet Archive Wayback Machine에 연결됨 ).

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

  • Singleton은 공장으로 쉽게 변환 될 수 있습니다.
  • Singleton은 다른 하위 클래스를 반환하도록 쉽게 수정할 수 있습니다.
  • 이것은 더 유지 보수가 가능한 응용 프로그램을 만들 수 있습니다.

5

정적 변수가 많은 정적 클래스는 약간의 해킹입니다.

/**
 * 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;
       }     

정적 클래스로 유사한 작업을 수행 할 수 있지만 간접 디스패치에는 호출 당 오버 헤드가 있습니다.

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

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


4

싱글 톤을 서비스라고 생각하십시오. 특정 기능 집합을 제공하는 개체입니다. 예

ObjectFactory.getInstance().makeObject();

오브젝트 팩토리는 특정 서비스를 수행하는 오브젝트입니다.

반대로 정적 메서드로 가득 찬 클래스는 관련 그룹 (클래스)으로 구성되어 수행 할 수있는 작업 모음입니다. 예

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

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


4

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


13
싱글 톤도 런타임에 인스턴스화됩니다 ...
재귀 적입니다

1
@recursive : 싱글 톤 인스턴스화를 제어 할 수 있습니다.
Nikit Batale 2010

3
아마도 더 나은 단어는 (인스턴스화보다는) 초기화 일 것입니다
Marlon

3

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

MyStaticClass.GetInstance().DoSomething();

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

MyStaticClass.DoSomething();

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

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

서비스는 객체가 싱글 톤이라는 것을 인식하지 않아야하며 객체를 단순한 객체로 취급해야합니다.

객체는 구현 세부 사항 및 전체 구성의 측면으로 확실히 구현 될 수 있습니다. 그러나 객체를 사용하는 것은 객체가 싱글 톤인지 아닌지 알 필요가 없습니다.


2

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

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

MySingleton.doSomething();

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


2
싱글 톤은 그 자체로 객체입니다.-> 인자로 전달 될 수 있습니다.
Christian Klauser

2

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


1

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

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


4
하드웨어 리소스를 제어하는 ​​관리자 클래스는 어떻습니까? 로그 파일 클래스는 어떻습니까?
RJFalconer 2009

0

싱글 톤이 처분 할 수있는 것이라면, 그 후에 정리하기 위해 항상 필요하지 않은 제한된 리소스 (즉, 그중 하나만) 일 때 고려할 수 있고 일종의 메모리 또는 할당 될 때 자원 비용.

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

그러나 코드는 어느 쪽이든 똑같이 보일 것이므로 더 구체적인 이유가 있다면 자세히 설명해야 할 것입니다.


0

둘은 매우 유사 할 수 있지만 진정한 싱글 톤은 자체적 으로 인스턴스화 (허용, 한 번) 된 다음 제공되어야합니다. 인스턴스를 반환하는 PHP 데이터베이스 클래스mysqli 는 인스턴스가 정적 멤버로있는 클래스의 인스턴스가 아니라 다른 클래스의 인스턴스를 반환하기 때문에 실제로 Singleton이 아닙니다.

따라서 코드에서 하나의 인스턴스 만 허용하려는 새 클래스를 작성하는 경우 Singleton으로 작성하는 것이 좋습니다. 일반 제인 클래스를 작성하고 여기에 추가하여 단일 인스턴스 요구 사항을 지원하는 것으로 생각하십시오. 수정할 수없는 다른 사람의 클래스 (예 mysqli:)를 사용하는 경우 정적 클래스를 사용해야합니다 (정의에 키워드를 접두사로 붙이지 않더라도).


0

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


0

정적 클래스는 인수로 전달할 수 없습니다. 싱글 톤의 인스턴스가 될 수 있습니다. 다른 답변에서 언급했듯이 정적 클래스의 스레딩 문제를 확인하십시오.

rp


0

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

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

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

이것은 IoC와 같은 실제 패턴을 선호하여 Singleton 패턴을 버리도록 선택할 때 분명히 일을 더 쉽게 만듭니다.


0

룩업 테이블과 같이 가능하다면 컴파일 타임에 계산할 무언가를 런타임에 계산해야 할 때 싱글 톤 패턴을 사용하십시오.


0

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


0

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


0

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

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

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

또한 다른 게시물을 확인하십시오 . 싱글 톤 구현보다 정적 클래스를 선택하는 이유는 무엇입니까?


0

이것을 참조 하십시오

요약:

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

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


-1

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

예를 들어 레지스트리 클래스 주위에 도우미 만들기 : 변경 가능한 하이브 (HKey 현재 사용자 대 HKEY 로컬 컴퓨터)가있는 경우 다음을 수행 할 수 있습니다.

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

이제 해당 싱글 톤에 대한 추가 호출은 로컬 머신 하이브에서 작동합니다. 그렇지 않으면 정적 클래스를 사용하여 Local Machine 하이브 everytiem을 지정하거나 ReadSubkeyFromLocalMachine.


1
나는 이런 식으로 Singleton을 사용하는 것에 반대합니다. 다음 호출자가 하이브를 설정하는 것을 잊고 잘못된 하이브의 레지스트리에 쓸 수 있기 때문에 상태를 계속 유지하는 것은 매우 위험합니다 ... :-( 이것은 사람들이 싱글 톤이 나쁘다고 생각하게 만드는 오용의 예일 것입니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.