Singleton의 대안


114

애플리케이션에 대한 구성 정보를 보유하는 클래스가 있습니다. 예전에는 싱글 톤이었습니다. 아키텍처 검토 후 싱글 톤을 제거하라는 지시를 받았습니다. 한 번에 다른 구성을 테스트 할 수 있기 때문에 단위 테스트에서 싱글 톤을 사용하지 않는 몇 가지 이점을 확인했습니다.

싱글 톤이 없으면 코드의 모든 곳에서 인스턴스를 전달해야합니다. 너무 지저분 해져서 싱글 톤 래퍼를 작성했습니다. 이제 동일한 코드를 PHP와 .NET으로 포팅하고 있습니다. 구성 객체에 사용할 수있는 더 나은 패턴이 있는지 궁금합니다.

답변:


131

구글 테스트 블로그 (테스트 가능한 코드를 생성하기 위해) 싱글 방지에 관한 항목의 시리즈가있다. 아마도 이것은 당신을 도울 수 있습니다 :

마지막 기사에서는 싱글 톤 사용을 피할 수 있도록 새 오브젝트 생성을 팩토리로 이동하는 방법을 자세히 설명합니다. 확실히 읽을 가치가 있습니다.

요컨대 우리는 모든 신규 작업자를 공장으로 옮깁니다. 수명이 비슷한 모든 개체를 하나의 공장으로 그룹화합니다.


3
*** 싱글 톤을 피하기 위해 의존성 주입 사용
Justin

이 기사는 Google C ++ 프로그래밍 표준만큼 훌륭합니다!

2
글쎄,별로. 예를 들어 '정적 방법을 사용하지 말라'는 조언은 Scott Meyers / Herb Sutters의 최소 인터페이스 원칙에 반합니다. 유용한 조언이 있지만 여러 마음의 기여가 부족합니다.
Matthieu M.

@FrankS 왜 링크 순서를 바꿨나요? 처음에는 좋은 연대순이었습니다.
cregox 2013.11.13

@Cawas 실제로 내가 :-) 다시 다음 몇 가지 이유가 생각 때문에, 4 년 이상 전 아무 생각이 없다,
프랭크

15

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

그러면 모든 개체에 싱글 톤에 살던 데이터가 포함됩니다. 전반적으로 큰 차이는 없다고 생각하지만 코드를 더 쉽게 읽을 수 있습니다.


1
나는 "최선의 방법"진술에 동의하지 않지만 좋은 대안을 위해 +1합니다.
tylermac 2009-08-19

이 접근 방식의 문제점은 모든 새로운 객체가 잠재적으로 엄청난 양의 데이터가 될 수있는 것을 포함 (또는 참조)한다는 것입니다. 이러한 gob 포함 객체에 대한 var_dump ()는 재귀 경고 와 함께 자유롭게 뒤덮인 거대한 목록을 매우 빠르게 생성 합니다. 그것은 추악하고 끔찍하게 효율적일 수 없으며 일이 혼란스러워 보입니다. 그러나 개인적으로 더 나은 방법을 찾지 못했습니다. __construct ()를 사용하여 전역을 참조하도록 "factory"메서드를 구부 렸습니다. 하지만 끔찍한 싱글 톤을 피하기 위해 모든 것이 뒤로 구부러진 것처럼 느껴집니다 ...
FYA

2
@EastGhostCom : 우리는뿐만 아니라 싱글을 사용하고 :) 자신을위한 일을 어렵게 만들려고 노력 중지 될 수 있습니다
gbjbaanb

5

여기에 명백한 내용이 있지만 Spring 또는 Guice 와 같은 종속성 주입 프레임 워크를 사용할 수없는 이유가 있습니까? (나는 Spring도 .NET에서도 사용할 수 있다고 믿습니다).

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

이것이 제가 일반적으로 취하는 접근 방식입니다!


4

Spring Framework 를 사용 하는 경우 일반 빈을 생성 할 수 있습니다. 기본적으로 (또는 명시 적으로 설정 scope="singleton"한 경우) Bean의 인스턴스는 하나만 생성되고 해당 인스턴스는 Bean이 종속성에서 사용되거나를 통해 검색 될 때마다 반환됩니다 getBean().

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


3
아이러니 아 - 사용 (싱글) 스프링 빈을 ... 당신의 싱글 톤을 대체하는
잭 컴버

4

대안은 물건에 물건을 요청하는 대신 필요한 것을 전달하는 것입니다.


4

이해하기 어렵고 깨지기 쉬운 매우 큰 개체로 끝날 것이기 때문에 단일 구성 개체에 대한 책임을 축적하지 마십시오 .

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

일반적이고 전역 적이며 큰 Configuration객체 를 피하기 위해 코드를 리팩토링하십시오 . 필수 매개 변수 만 클라이언트 클래스에 전달하십시오.

class Server {

    int port;

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

}

다음과 같이 리팩토링되어야합니다.

 class Server {

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

의존성 주입 프레임 워크는 여기에 많은 도움이 될 것입니다,하지만 stricly 필요하지 않습니다.


네, 정말 좋은 지적입니다. 나는 전에 이것을했다. 내 큰 구성 개체는 종속성 주입 프레임 워크가 구성을 클래스에 전달하는 것보다 MailServiceConf, ServerConf ..와 같은 인터페이스를 구현하여 내 클래스가 큰 구성 개체에 종속되지 않았습니다.
caltuntas 2010 년

1

정적 메서드를 사용하여 싱글 톤의 동일한 동작을 수행 할 수 있습니다. Steve yegge는 게시물 에서이를 매우 잘 설명합니다 .


실제로이 기사는 꽤 훌륭하며 대신 정적 메서드를 사용해야한다고 말하지 않습니다. 대신 그는 정적 메서드도 싱글 톤일 뿐이며 마지막에는 팩토리 메서드 패턴을 사용하는 것이 좋습니다. "여전히 Singleton 객체를 사용할 필요가 있다고 느끼면 대신 팩토리 메서드 패턴을 사용하는 것이 좋습니다. ... "
FrankS

0

정적 메서드와 필드 만 포함하는 클래스가 가능합니까? 귀하의 상황이 정확히 무엇인지는 모르겠지만 살펴볼 가치가있을 수 있습니다.


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

1
C ++에 있습니다-패턴은 Monostate로 알려져 있습니다.

0

어떤 툴링 / 프레임 워크 등이 사용되는지에 따라 다릅니다. 종속성 주입 / ioc 도구를 사용하면 di / ioc 컨테이너가 클래스의 인스턴스를 하나만 생성하여 필요한 클래스 (예 : IConfigSettings 인터페이스)에 대해 싱글 톤 동작을 사용함으로써 싱글 톤 성능 / 최적화를 얻을 수 있습니다. 이것은 여전히 ​​테스트를 위해 대체 될 수 있습니다.

또는 팩토리를 사용하여 클래스를 만들고 요청할 때마다 동일한 인스턴스를 반환 할 수 있지만 테스트를 위해 스텁 / 모의 버전을 반환 할 수 있습니다.


0

콜백 인터페이스로 구성 할 가능성을 검토하십시오. 따라서 구성에 민감한 코드는 다음과 같습니다.

MyReuseCode.Configure(IConfiguration)

시스템 초기화 코드는 다음과 같습니다.

Library.init(MyIConfigurationImpl)

0

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


0

그다지 깨끗하지 않을 수도 있지만 변경하려는 정보 비트를 사용하는 대신 싱글 톤을 생성하는 메서드로 전달할 수 있습니다.

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

createSingleton(Information info)응용 프로그램 시작시 (및 단위 테스트의 setUp-Methods에서) 직접 호출 할 수 있습니다.


-1

싱글 톤은 나쁘지 않지만 디자인 패턴에 결함이 있습니다. 런타임 중에 단일 인스턴스 만 만들고 싶지만 결정 론적 결과를 보장하기 위해 단위 테스트 중에 여러 격리 된 인스턴스를 만들고 싶은 클래스가 있습니다.

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

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