2009-08-19 4 views
108

우리는 응용 프로그램에 대한 구성 정보를 보유하는 클래스가 있습니다. 이전에는 싱글 톤이었습니다. 아키텍처 검토를 마친 후 우리는 싱글 톤을 제거하라는 지시를 받았다. 우리는 단위 테스트에서 싱글 톤을 사용하지 않는 이점을 보았습니다. 다른 구성을 한꺼번에 테스트 할 수 있기 때문입니다.싱글 톤의 대안

싱글 톤이 없으면 코드의 모든 곳에서 인스턴스를 전달해야합니다. 우리가 싱글 톤 래퍼 (singleton wrapper)를 썼을 정도로 지저분 해졌습니다. 이제 우리는 PHP와 .NET에 동일한 코드를 포팅하고 있습니다. 구성 객체에 사용할 수있는 더 나은 패턴이 있는지 궁금합니다.

답변

124

Google Testing blog에는 테스트 할 수있는 코드를 만들기 위해 싱글 톤을 피하는 일련의 항목이 있습니다. 어쩌면이 당신을 도울 수 있습니다

방법 공장에 새로운 객체의 생성을 이동하기 때문에, 싱글 톤 사용을 피할 수 있습니다.읽을만한 가치가있는 책.

간단히 말해서 모든 새 연산자를 팩토리로 이동합니다. 비슷한 수명의 모든 개체를 단일 팩토리로 그룹화합니다.

+11

구글 테스트 블로그는 독서가 필요합니다. – koen

+3

*** 의존성 삽입을 사용하여 싱글 톤을 피하십시오 – Justin

+0

이 기사는 Google C++ 프로그래밍 표준만큼 좋습니다! –

0

정적 메서드 및 필드 만 포함하는 클래스를 사용할 수 있습니까? 나는 당신의 상황이 무엇인지 정확히 알지 못하지만, 조사할만한 가치가있을 것입니다.

+1

클래스가 상태 비 저장 인 경우 정적 클래스 여야합니다. – AlbertoPL

+1

이것은 C++입니다. 패턴은 Monostate로 알려져 있습니다. –

15

가장 좋은 방법은 대신 공장 패턴을 사용하는 것입니다. 클래스의 새 인스턴스를 만들 때 (공장에서), 새로 생성 된 객체에 '전역'데이터를 삽입 할 수 있습니다.이 데이터는 단일 인스턴스 (팩토리 클래스에 저장)에 대한 참조 또는 관련 인스턴스를 복사하여 데이터를 새 객체에 추가합니다.

모든 개체에는 싱글 톤에서 살았던 데이터가 포함됩니다. 차이점이 많이 있다고는 생각하지 않지만 코드를 읽기 쉽게 만들 수 있습니다.

+1

"최선의 방법"에 동의하지 않지만 좋은 대안으로 +1합니다. – tylermac

+0

이 접근법의 문제점은 모든 새로운 객체가 잠재적으로 엄청난 양의 데이터를 포함 할 수 있다는 것입니다. var_dump()는 멍청이를 포함하고있는 객체들 중 하나에서 ** recursion ** 경고로 자유롭게 후퇴하는 커다란 목록에서 매우 빠르게 결과를 낳습니다. 그것은 못 생기고, 끔찍하게 효율적이어서는 안되며, 일들이 끔찍한 것처럼 보입니다. 그러나 나는 개인적으로 더 나은 방법을 찾지 못했습니다. 전역을 참조하기 위해 __construct()를 사용하여 "factory"메서드를 구부 렸습니다. 그러나 무시 무시한 싱글 톤을 피하기 위해 모든 것을 구부릴 것 같은 느낌입니다 ... – FYA

+2

@EastGhostCom : 우리는 싱글 톤을 사용하고 스스로를 어렵게 만들려고 노력하지 않을 것입니다 :) – gbjbaanb

5

내가 여기에 명백하게 말할 수도 있지만 Spring 또는 Guice과 같은 의존성 주입 프레임 워크를 사용할 수없는 이유가 무엇입니까? (저는 스프링이 .NET에서도 사용 가능하다고 믿습니다).

그런 식으로 프레임 워크는 구성 객체의 단일 사본을 보유 할 수 있으며 bean (서비스, DAO 등)은 그것을 찾는 것에 대해 걱정할 필요가 없습니다.

이것은 일반적으로 취하는 접근 방식입니다. 하나

0

어쩌면 매우 깨끗하지,하지만 당신은 아마 당신이 싱글을 생성하는 방법을 변경하고자하는 정보 비트를 전달할 수 - 당신은 응용 프로그램 시작에 직접 createSingleton(Information info) 부를 수있는 대신

public static Singleton getInstance() { 
    if(singleton != null) 
     createSingleton(); 
     return singleton; 
    } 
} 

를 사용을 (그리고 단위 테스트의 setUp-Methods에서).

4

Spring Framework을 사용하는 경우 일반 bean을 만들면됩니다. 기본적으로 (또는 명시 적으로 scope="singleton"을 설정 한 경우) Bean의 한 인스턴스 만 작성되며 해당 인스턴스에서 Bean이 종속성에서 사용될 때마다 리턴되거나 getBean()을 통해 검색됩니다.

싱글 톤 패턴의 결합없이 단일 인스턴스의 이점을 얻을 수 있습니다.

+1

Oh 아이러니 - 사용 (싱글 톤) 스프링 콩 당신의 싱글 톤을 대체 할 수 있습니다 ... –

0

사용중인 툴링/프레임 워크 등에 따라 다릅니다. 의존성 주입/ioc 도구를 사용하면 di/ioc 컨테이너가 클래스의 인스턴스 하나만 생성하여 필수 클래스 (예 : IConfigSettings 인터페이스)에 대한 싱글 톤 동작을 사용하도록함으로써 종종 싱글 톤 성능/최적화를 얻을 수 있습니다. 이것은 여전히 ​​다른 방법 하나는 클래스를 만드는 공장을 사용하고 동일한 인스턴스에게 당신이 그것을 요청할 때마다 반환 할 수

을 테스트하기 위해 밖으로 대체 될 수 -하지만 테스트하기 위해이

4

대안 스텁/조롱 버전을 반환 할 수 물건을 물어 보는 대신 필요한 것을 전달하고 있습니다.

0

콜백 인터페이스로 구성 할 수 있는지 검토하십시오. 그래서 구성에 민감한 코드는 모양 :

MyReuseCode.Configure(IConfiguration) 

시스템 초기화 코드는 모양 :이 때문에

Library.init(MyIConfigurationImpl) 
4

는 하나의 구성 개체에 맞는 책임을 축적하지 않는 매우 큰의 끝 이해하기 어렵고 깨지기 쉬운 물건.

예를 들어 특정 클래스에 다른 매개 변수가 필요한 경우 Configuration 개체를 변경 한 다음 해당 클래스를 사용하는 모든 클래스를 다시 컴파일하십시오. 이것은 다소 문제가 있습니다.

일반적인 글로벌이고 큰 Configuration 개체를 피하려면 코드를 리팩토링하십시오. 클라이언트 클래스에만 필요한 매개 변수를 전달합니다 여기에 많은 도움이 될 것입니다

class Server { 

    public Server(int port) { 
     this.port = port; 
    } 
} 

의존성 주입 프레임 워크 있지만 stricly 필요하지 않습니다 :

class Server { 

    int port; 

    Server(Configuration config) { 
     this.port = config.getServerPort(); 
    } 

} 

가에 리팩토링해야한다.

+0

네, 정말 좋은 지적입니다. 나는 이것을 전에했다. 내 큰 구성 객체는 MailServiceConf, ServerConf ..와 같은 인터페이스를 구현하는 것이 었습니다. Dependency Injection 프레임 워크가 클래스에 구성을 전달하므로 클래스가 큰 Configuration 객체에 종속되지 않았습니다. – mcaaltuntas

0

종속성 주입 프레임 워크를 사용하여 구성 객체 전달의 어려움을 완화 할 수 있습니다. 괜찮은 것은 ninject이고 xml 대신 코드를 사용하는 장점이 있습니다.

0

정적 메서드를 사용하여 동일한 싱글턴 동작을 수행 할 수 있습니다. Steve yegge는 this 지위에서 매우 잘 설명합니다.

+0

실제로이 기사는 꽤 좋으며 대신 정적 메서드를 사용해야한다고 말하지는 않습니다. 대신 정적 메서드는 단순한 메서드 일 뿐이며 결국 팩토리 메서드 패턴을 사용하는 것이 좋습니다. "아직 Singleton 개체를 사용해야하는 경우 Factory Method 패턴을 사용하는 것이 좋습니다. 대신 ... " – FrankS

-1

싱글 톤은 악조건이 아니지만 디자인 패턴에 결함이 있습니다. 런타임 중에 단 하나의 인스턴스 만 만들고 싶지만 단위 테스트 중에 여러 개의 독립 인스턴스를 만들어 결정적 결과를 보장하려는 클래스가 있습니다.

봄을 사용하는 DI 등은 매우 좋은 옵션이지만 유일한 옵션은 아닙니다.

+1

다른 옵션은 무엇입니까? – hakre