2012-12-12 2 views
3

Guice를 보험 데이터 변환 플랫폼에서 사용할 준비를하고 있으며 Guice 문서 또는 내가 찾은 모든 게시에서 직접 해결되지 않는 흥미로운 시나리오가 있습니다.Guice puzzler : Batch scoped 캡슐화 된 컨텍스트

Google 플랫폼은 몇 가지 중요한 영역에서 캡슐화 된 컨텍스트 (EC) 패턴을 사용합니다. 예를 들어, 우리가 10 개의 정책 집합을 처리하고 있다고 가정합니다. 새 정책을 처리하기 시작할 때마다 PolicyContext 개체를 만들고 정책 번호, 주 및 회사와 같은 속성을 초기화해야합니다. 이 PolicyContext은 변환 프로세스에 관련된 많은 클래스에 대한 종속성입니다.

PolicyContext (및 기타 *Context 개체는 특정 도메인 영역에 집중되어있는 가치 객체입니다 (유비쿼터스 적으로 필요한 정책 정보를 나타냄). 비록 이들이 순전히 가치있는 물건이고 확실히 "부엌 싱크대"를 나타내지는 않지만 당신 사이의 패턴 전문가가 여전히 이것을 안티 패턴 (미시시 Hevery가 말한 바와 같이 http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/)으로 생각하는지에 관심이 있습니다.

현재 우리는 최악의 방법으로 PolicyContext을 관리하고 있습니다. 새로운 정책을 처리하기 시작할 때마다 정적 전역 변수 policyContextpolicyContext.initialize(String company, String state, String policyNum)이 호출됩니다.

  1. Guice 이전 PolicyContext을 삭제합니다 : 즉, 개념적으로, 우리는 새로운 정책을 처리하기 시작 때마다 있도록 Guice는 구조적으로 최적의 방식으로이 상황에 맞는 객체를 관리 할 수 ​​

    내 목표이다.

  2. Guice는 company/state/policyNum 매개 변수를 사용하여 새롭고 불변 인 PolicyContext (냄새 나는 초기화 방법이 없음)을 구성합니다.
  3. Guice는 이미 구성된 PolicyContext을 필요로하는 모든 클래스에 삽입합니다.

    1. 는 배치의 경계 외부에서 결정된다 --where http://code.google.com/p/google-guice/wiki/CustomScopes에서 Guice 배치 범위 시료와 유사한 사용자 지정 범위-뭔가를 만들기 :

    여기 내 임시 접근 방법이다. 이 범위에서 새 정책을 처리하기 시작하면 1) 이전 "배치"를 끝내고 새 배치를 시작할 수 있습니다. Q : Guice 배치 스코프 샘플을 앞에서 언급 한 URL과 똑같이 사용할 수없는 이유는 무엇입니까?

  4. PolicyContext은 종속성이 없으므로, 의 모든 생성자 매개 변수 (다소 이상하게 보임)에 AssistedInject를 사용합니다.

    … 
    scope.exit(); 
    scope.enter(); 
    @Inject private PolicyContextFactory policyContextFactory; 
    policyContextFactory.create(company, state, policyNum); // the parameters come from a database record. 
    // Note that we don’t need to actually store the created instance; it will be injected elsewhere into various class constructors. 
    … 
    

이 최적의 보이는가 : 우리가 접근을하고 PolicyContextFactory을 생성 가정, 우리가 새 정책을 처리하기 시작 어디에 우리가 같은 코드를 것이라고 다음? 새 정책을 처리 할 때마다 PolicyContext 특정 인젝터를 새로 만드는 등 더 간단한 방법이있을 수 있습니다. 실제로는 새로운 PolicyContext을 만듭니다. 그러나 이것은 아키텍처의 핵심 요소이므로 절충하고 싶지는 않습니다.

또 다른 옵션은, 나도 알아,이 시나리오에서 DI를 사용하여 절제하고 단지 전자의 방법은 현재 PolicyContext을 버리고 생성 공장은 별도의 createget 방법/저장과 정적 PolicyContextManager 클래스를 사용하는 것 새로운 방법인데, 후자의 방법은 간단히 "활성"PolicyContext을 반환합니다. 하지만 methodThatNeedsPolicyContext(PolicyContextManager.get(), …)과 같은 코드를 많이 작성하게 될 것이므로 직접 작성하는 것이 좋습니다. 어쨌든 우리는 Guice를 사용하기 시작할 것이므로이 접근법은 최적의 것으로 보이지 않습니다.

나는 DI에 대한 깊은 이해를 기르는 사람들에게 단 가리 프라 사나의 "의존성 주입"을 강력히 추천한다. Guice와 Spring에 초점을 맞춘이 책은 필자가 만난 다른 어떤 것보다 훨씬 깊어서 절대적으로 필요했습니다.

도움 주셔서 감사합니다.

답변

3

것 같습니다 당신의 당신의 욕망이 주위에 당신의 컨텍스트를 통과하지 않도록하고, 사용자 정의 범위를 보장하기 때문에 SimpleScope, 그것은 정확히으로 사용자의 요구에 거의 완벽 연결된 그 어떤 @PolicyScoped 바인딩 (아마도 만 컨텍스트 및 그 내용) 이미 준비 ("뿌린"). 정적 인 참조를 정적 ThreadLocal로 바꾸는 것만으로도 좋은 멀티 스레딩 기능을 얻을 수 있습니다.

enterexit 호출 사이에 정책 범위의 개체 그래프를 삽입하거나 이름을 지정하도록 선택해야합니다. PolicyContext를 생성자 나 필드에 삽입하면 (객체의 상태에 저장), 객체 인스턴스는 이제 해당 정책에만 적용된다는 것을 알아 두십시오. 이것은 분명해 보일지 모르지만 팀원이 무의식적으로 주사하거나 dueDateCalculator을 캐싱하면 암시 적으로 정책 # 8675-309에 대한 만기일 계산기로 구성되었으며 정책 # 5550-187에 대한 나쁜 대답을 제공한다는 것을 알지 못할 수 있습니다. 특히 정책 범위 종속성이 필요한 모든 @Singleton 객체는 공급자를 사용해야합니다. 그렇지 않으면 범위를 벗어 났을 때도 정책이 "기억"됩니다. 이것은 "범위 확대 주사"의 예이고 Prasanna discusses it at length입니다.

당신은 그것을 간단 팀 동료가 직접 PolicyContext를 주입하지 주장 찾을 대신 항상Provider<PolicyContext>를 주입 할 수있다 (이 당신 get for free if PolicyContext is injectable). 이것에 의해, 오브젝트의 구축시에 어느 정책이 액티브 한 것인가에 대해 생각하지 않게되어, 그 오브젝트의 메소드가 실행될 때의 PolicyContext가 신뢰됩니다.

개체에 종속성이없는 경우 Guice를 만들 필요가 없습니다. 이는 과장입니다. 너무 많은 의존성이 생기면 객체의 생성을 Guice로 옮기는 것이 쉽습니다. 수동으로 생성하는 것은 고통입니다. 당신이해야 할 때까지 그것을하지 마십시오.

마지막으로, 캡슐화 된 컨텍스트에 대한, 나는 EC 패턴만큼 상황이 더 논리가없고 상황이 표시되는 위치를 객체의 전체 번들 적용으로 유효한 리팩토링이라고 생각하는 일이. 컨텍스트의 모든 항목이 컨텍스트를 주입하는 시간의 80 %를 사용한다고 나에게 방어 할 수 있다면 코드는 더 짧고 따라하기 쉽고이기는 것입니다. 의존성 주입의 이점 중 하나는 의존성을 추가하거나 제거하는 것이 매우 쉽다는 점이므로 하나의 개별적으로 바인딩 된 Context 속성을 주입하는 것으로부터 두 개의 개별 Context 속성을 주입하여 전체 Context를 직접 주입하는 것 (그리고 당신이 가진 많은 컨텍스트에 대해 반복하십시오.)

그건 내 생각입니다. 희망이 도움이됩니다!

+0

감사합니다. Jeff. 명확하게 언급하고 몇 가지 중요한 뉘앙스를 다룹니다. 몇 가지 관련 질문이 있지만 별도로 게시하겠습니다. –

+0

+1 공급자를 주입하고 사용자 지정 범위를 만드는 데 사용됩니다. 당신은 공급자 BTW를 삽입 바인딩을 필요로 생각하지 마십시오. – RobbieV

+0

@RobbieV Guess가'Foo'를 주입 할 수 있다면,'get for free '주석으로 언급했듯이 추가 코드없이'Provider '를 주입 할 수 있습니다. 'Foo'는 그것이 구체적인 클래스이고'Foo' 또는'Provider '에 대한 바인딩이 필요없는 경우 암시 적으로 바인딩 될 수 있습니다. 그러나'Foo'가 인터페이스 인 경우에도 여전히 어딘가에 바인딩해야합니다. 필자는 "Provider "를 삽입 할 때 위의 "Provider "를 바인드했습니다.하지만 이제는 수정되었습니다. –