싱글 톤 사용 과 정적 클래스 사용 사이를 결정할 때 설계 고려 사항의 이름을 지정합니다 . 이렇게 할 때, 당신은 두 가지를 대조하도록 강요받습니다. 그래서 당신이 생각 해낼 수있는 어떤 대조는 당신의 사고 과정을 보여주는 데에도 유용합니다! 또한 모든 면접관은 예시를보고 싶어합니다. :)
싱글 톤 사용 과 정적 클래스 사용 사이를 결정할 때 설계 고려 사항의 이름을 지정합니다 . 이렇게 할 때, 당신은 두 가지를 대조하도록 강요받습니다. 그래서 당신이 생각 해낼 수있는 어떤 대조는 당신의 사고 과정을 보여주는 데에도 유용합니다! 또한 모든 면접관은 예시를보고 싶어합니다. :)
답변:
Hide Dependencies이 점에 대한 작은 정보 : 예를 들어 Ninject 를 사용하여 Inversion of Control 패턴을 구현할 수 있습니다 . 이를 통해 유형의 인스턴스를에 바인딩하여 하나의 인스턴스 만 사용할 수 있습니다. SingletonScope즉 , 동일한 인스턴스를 항상 주입 하지만 클래스는 싱글 톤이 아닙니다.
이 문제에 대해 제가 가장 좋아하는 토론 중 하나는 여기입니다 (원래 사이트 다운, 이제 Internet Archive Wayback Machine에 연결됨 ).
Singleton의 유연성 이점을 요약하면 다음과 같습니다.
정적 변수가 많은 정적 클래스는 약간의 해킹입니다.
/**
* 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의 내부는 분명히 다르지만 스레드 안전성 문제를 제외하고는 둘 다 클라이언트 코드와 관련하여 동일하게 수행됩니다.
싱글 톤은 절대 사용해서는 안됩니다 (변경 가능한 상태가없는 클래스를 싱글 톤으로 간주하지 않는 한). "정적 클래스"는 스레드로부터 안전한 캐시 등을 제외하고 변경 가능한 상태가 없어야합니다.
싱글 톤의 거의 모든 예는이를 수행하지 않는 방법을 보여줍니다.
둘은 매우 유사 할 수 있지만 진정한 싱글 톤은 자체적 으로 인스턴스화 (허용, 한 번) 된 다음 제공되어야합니다. 인스턴스를 반환하는 PHP 데이터베이스 클래스mysqli 는 인스턴스가 정적 멤버로있는 클래스의 인스턴스가 아니라 다른 클래스의 인스턴스를 반환하기 때문에 실제로 Singleton이 아닙니다.
따라서 코드에서 하나의 인스턴스 만 허용하려는 새 클래스를 작성하는 경우 Singleton으로 작성하는 것이 좋습니다. 일반 제인 클래스를 작성하고 여기에 추가하여 단일 인스턴스 요구 사항을 지원하는 것으로 생각하십시오. 수정할 수없는 다른 사람의 클래스 (예 mysqli:)를 사용하는 경우 정적 클래스를 사용해야합니다 (정의에 키워드를 접두사로 붙이지 않더라도).
싱글 톤에는 생성자와 소멸자가있을 수 있습니다. 언어에 따라 생성자는 싱글 톤이 처음 사용될 때 자동으로 호출되거나 싱글 톤이 전혀 사용되지 않으면 절대로 호출되지 않을 수 있습니다. 정적 클래스에는 이러한 자동 초기화가 없습니다.
싱글 톤 객체에 대한 참조를 얻으면 다른 객체와 마찬가지로 사용할 수 있습니다. 클라이언트 코드는 싱글 톤에 대한 참조가 이전에 저장된 경우 싱글 톤 사용을 알 필요조차 없습니다.
Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton
이것은 IoC와 같은 실제 패턴을 선호하여 Singleton 패턴을 버리도록 선택할 때 분명히 일을 더 쉽게 만듭니다.
데이터의 효율적인 캐싱을 강제하려는 경우 싱글 톤도 좋은 생각입니다. 예를 들어 xml 문서에서 정의를 조회하는 클래스가 있습니다. 문서를 구문 분석하는 데 시간이 걸릴 수 있으므로 정의 캐시를 설정했습니다 (OutOfmemeoryErrors를 피하기 위해 SoftReferences를 사용합니다). 원하는 정의가 캐시에 없으면 값 비싼 xml 구문 분석을 수행합니다. 그렇지 않으면 캐시에서 복사본을 반환합니다. 캐시가 여러 개인 경우 동일한 정의를 여러 번로드해야 할 수도 있으므로 정적 캐시가 필요합니다. 이 클래스를 싱글 톤으로 구현하여 일반 (비 정적) 데이터 멤버 만 사용하여 클래스를 작성할 수 있습니다. 이렇게하면 어떤 이유로 든 (직렬화, 단위 테스트 등) 필요한 경우 클래스의 istantiation을 만들 수 있습니다.
Singleton은 이미 언급했듯이 서비스와 같습니다. Pro는 유연성입니다. 정적, 음, Singleton을 구현하려면 정적 부분이 필요합니다.
Singleton에는 실제 개체의 인스턴스화를 처리하는 코드가 있으므로 레이싱 문제가 발생하는 경우 큰 도움이 될 수 있습니다. 정적 솔루션에서는 여러 코드 위치에서 레이싱 문제를 처리해야 할 수 있습니다.
그러나 일부 정적 변수로 Singleton을 구성 할 수있는 것과 동일하게 'goto'와 비교할 수 있습니다. 다른 구조를 만드는 데 매우 유용 할 수 있지만 실제로 사용하는 방법을 알아야하며 '남용'해서는 안됩니다. 따라서 일반적인 권장 사항은 Singleton을 고수하고 필요한 경우 정적을 사용하는 것입니다.
또한 다른 게시물을 확인하십시오 . 싱글 톤 구현보다 정적 클래스를 선택하는 이유는 무엇입니까?
단일 클래스에 상태가 필요한 경우. 싱글 톤은 전역 상태를 유지하지만 정적 클래스는 그렇지 않습니다.
예를 들어 레지스트리 클래스 주위에 도우미 만들기 : 변경 가능한 하이브 (HKey 현재 사용자 대 HKEY 로컬 컴퓨터)가있는 경우 다음을 수행 할 수 있습니다.
RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine
이제 해당 싱글 톤에 대한 추가 호출은 로컬 머신 하이브에서 작동합니다. 그렇지 않으면 정적 클래스를 사용하여 Local Machine 하이브 everytiem을 지정하거나 ReadSubkeyFromLocalMachine.