2010-08-13 3 views
9

싱글 톤이 "불량"인지, 대신 어떤 패턴을 사용해야하는지에 관해 많은 질문이 있습니다. 일반적으로 클래스의 정적 메서드에서 싱글 톤 인스턴스를 검색하는 싱글 톤 디자인 패턴에 중점을 둡니다. 이 질문 중 하나가 아닙니다.의존성 삽입을 사용하고 있습니다. 어떤 유형을 싱글 톤으로 바인딩해야합니까?

몇 달 전에 의존성 주입을 실제로 "발견 했으므로"나는 우리 팀에서 채택을 추진하고 있으며 시간이 지남에 따라 코드에서 정적 및 싱글 톤 패턴을 제거하고 가능하면 생성자 기반 주입을 사용했습니다. 우리는 DI 모듈에 명시적인 바인딩을 계속 추가 할 필요가 없도록 규칙을 채택했습니다. DI 프레임 워크를 사용하여 로거 인스턴스를 제공하므로 추가 코드없이 각 로거에 자동으로 알릴 수 있습니다. 이제는 여러 유형이 묶이는 방법을 제어 할 수있는 단일 장소가 있으므로 클래스의 특정 카테고리 (유틸리티 클래스, 리포지토리 등)의 라이프 사이클을 결정하는 것은 정말 쉽습니다.

초기 생각은 클래스를 상당히 자주 사용하기를 기대한다면 클래스를 싱글 톤으로 바인딩하는 것이 도움이된다는 것입니다. 그것은 단지 생성하는 객체가 큰 의존성 트리를 가지고 끝날 때 훨씬 더 적은 숫자가 발생한다는 것을 의미합니다. 거의 모든 클래스의 비 정적 필드는 생성자에 주입되는 값이므로 사용되지 않을 때 인스턴스를 유지하는 데 비교적 적은 메모리 오버 헤드가 발생합니다.

그렇다면 나는 "싱글턴을 사랑하지만, 당신은 www.codingwithoutcomments.com"에서 나를 데려왔다. 그리고 그것은 나에게 내가 올바른 생각을 가지고 있는지 궁금하게 만들었다. 결국, Ninject는 기본적으로 객체 생성 함수를 컴파일하므로 이러한 객체의 추가 인스턴스를 생성 할 때 반영되는 오버 헤드가 거의 없습니다. 우리는 비즈니스 로직을 생성자 밖으로 유지하기 때문에 새로운 인스턴스를 만드는 것은 실제로 매우 가벼운 작업입니다. 그리고 객체에는 정적 필드가 많지 않으므로 새 인스턴스를 만드는 데 많은 메모리 오버 헤드가 발생하지 않습니다.

그래서이 시점에서 나는 어느 쪽이든별로 중요하지 않다고 생각하기 시작했습니다. 내가 고려하지 않은 추가 고려 사항이 있습니까? 특정 유형의 객체의 수명주기를 변경하여 성능을 크게 향상시킨 경험이 있습니까? DI 패턴을 따르는 것이 진짜 중요한 것입니까, 아니면 객체의 단일 인스턴스를 사용하는 것이 본질적으로 "나쁘다"는 다른 이유가 있습니까?

답변

5

싱글 톤 인스턴스를 사용하여 객체를 생성하는 데 비용이 많이 든다. (nhibernate 세션 팩토리와 같이) 또는 응용 프로그램에서 공유하려는 객체에 대해 비싸다.

불확실성이있는 경우 객체가 사용될 때마다 객체를 다시 만들고 싱글 톤 또는 "요청 당"/ "요청 당"/ "필요한만큼만"으로 표시해야합니다.

새소식을 잠재적으로 저장하기 위해 장소 전체에 걸쳐 스 캐터링을하는 것은 조기 최적화이며, 오브젝트가 새 오브젝트인지 또는 여러 오브젝트/인스턴스에서 공유되는지 확실하지 않기 때문에 정말 불쾌한 버그가 될 수 있습니다.

개체가 현재 상태가없고 공유하기 위해 저장되어있는 것처럼 보이더라도 나중에 다른 사람/개체간에 의도하지 않게 공유 될 수있는 상태를 추가하고 상태를 추가 할 수 있습니다.

+0

+1 질문에 대한 답변. – StriplingWarrior

0

메모리 사용량은 중요하지 않지만 모듈성이 증가하고 모의 객체로 테스트하기 쉬워지고 의존성을 명시 적으로 작성해야하는 심미한 추악함은 프로그래머가 각 클래스를 더 직교적이고 독립적으로 만들도록 권장합니다. . 클래스가 전역을 호출 할 때 의존 관계를 더 쉽게 이해할 수 있습니다. 기본적으로 단일 클래스가 있으며, 나중에 더 힘들게 만들 수 있습니다.

+0

나는 내 질문을 이해하지 못했다고 생각합니다. 나는 의존성 삽입을 사용하기 때문에 코드는 정확히 같은 방식으로 보일 것이다. 문제는 주입 된 객체가 매번 동일한 인스턴스인지 여부 또는 각 클래스에 새로운 인스턴스가 전달되는 이점이 있는지 여부입니다. – StriplingWarrior

+1

오, 그럴 경우 귀하의 질문에 올바르게 답할 수있는 더 많은 정보가 필요합니다. 전달 된 객체에 상태가 없으면 새 인스턴스를 만드는 데 필요한 추가 객체 참조를 제외하고는 아무런 차이가 없습니다. 그들이한다면, 그것은 당신의 요구 사항과 당신이 기대하는 것에 달려 있습니다. – gtrak

+0

오브젝트에는 삽입 된 다른 서비스와 별개로 상태가 없으며 비공개 필드로 저장됩니다. 따라서 잠재적으로 한 서비스가 생성 될 때마다 새로운 '큰 일'이 일어날 수 있습니다. – StriplingWarrior

1

많은 수의 개체를 만들지 않는 한 메모리 관리가 큰 문제인지 잘 모르겠습니다. IoC 컨테이너에서 싱글 톤을 사용하여 캐싱과 같은 작업을 할 때 도움이되는 것으로 나타났습니다. 캐싱 개체를 생성하고 캐싱 서버에 연결하는 작업은 비용이 많이 들기 때문에 캐싱 개체를 한 번 생성하고 다시 사용합니다.

단일 인스턴스는 위험 할 수 있지만 서비스 인스턴스의 경우 여러 인스턴스를 처리 할 때 성능에 병목 현상을 일으킬 수 있습니다.

+0

두 번째 단락을 자세히 설명해 주시겠습니까? 각 클래스가 캡슐화되도록 클래스를 작성한다고 가정하면 스레드 안전성은 문제가되지 않습니다 (잠금 또는 기타를 수행 할 필요가 없습니다). 하나의 인스턴스가 여러 요청을 처리하도록하려면 어떻게 느려질 수 있습니까? – StriplingWarrior

+1

당신이 쓰레드에 안전하다면, 내가 아는 한 멀리 걱정할 것이 없다. IoC에 대한 첫 번째 시도가이 문제로 나를 때리게했습니다. 그 이후로 나는 많은 서비스를 위해 싱글 톤을 사용하고 쓰레드를 안전하게 만든다. – Wix

0

Gary's answer에서 언급했듯이 DI의 전체적인 점은 테스트 가능성입니다 (클래스에 대한 모든 참조는 생성자에 나열되어 있기 때문에 쉽게 참조 할 수 있습니다). 런타임 성능이 아닙니다.

당신은 을 원합니다.은 TDD (시운전 개발)를하고 싶습니다. 맞습니까?

+0

Gary의 대답 (답하기 전에 쓰여졌습니다.)과 제목, 다시 질문의 본문에 언급 된 것처럼 * 종속성 주입 *을 사용하고 있습니다. 싱글 톤 "패턴"에 대해서는 묻지 않고 DI 구성 모듈에서 싱글 톤 (singleton)과 과도 (transient)로 서비스를 바인딩하는 이점이 있는지 여부를 묻습니다. – StriplingWarrior

+0

알겠습니다. 나는 여전히 성능이 여기에 주요 관심사가되어서는 안된다고 생각한다. 코드를 가장 쉽게 읽을 수있는 솔루션을 사용하는 것이 좋습니다. 로거 용 DI 프레임 워크를 사용한다고 가정 해보십시오. 그것은 가독성 (class)의 혼란을 덜어 준다. 다른 경우에는 그 반대가 될 수 있습니다. 서비스가 클래스 의도/라이프 사이클/카테고리를 암시하는 경우 명시 적으로 원할 수 있습니다. – louisgab

+0

나는 DI를 사용하고 관례에 따라 바인딩하기 때문에 한 줄의 코드에'.InSingletonScope()'를 추가 할 수 있으며, 의존성 주입을 계속 사용하더라도 모든 저장소 클래스가 마술처럼 싱글 톤이 될 것이다 그들을 필요로하는 수업. DI 프레임 워크 덕분에 코드의 가독성은 어느 쪽의 방법에도 영향을받지 않습니다. 나는 공연이 큰 관심사가 아니라는 것에 동의한다. 그래서 나의 결정은이 결정을 내릴 때 염두에 두어야 할 다른 염려가 있는지의 여부이다. – StriplingWarrior

관련 문제