2011-03-30 3 views
7

팩토리에서 생성 된 일부 객체를 제대로 초기화하기 전에 초기화해야하는 우리 시스템 용 팩토리 클래스 세트를 설계하려고합니다.객체 초기화가있는 팩토리 클래스 - 정적을 피하려고 시도합니다.

예 : 예를 들어 동일한

$foobar = new Foobar(); 
$foobar->init($qux, ...); 
// $foobar ready for usage 

$qux 오브젝트 만 종속 그 Foobar 필요가 있음을 말하고 있습니다. 내가 도착하고 싶은 것은 :

가 전체 시스템에 걸쳐 $qux 개체를 따라 전달하고 다른 매개 변수로 팩토리 클래스에 전달해야 할 필요성을 방지하기 위해
$foobar = Foo_Factory('bar'); 

, 내가 수행하고 싶습니다 직접 공장 클래스의 Foobar의 초기화 :

class Foo_Factory { 

    public static function getFoo($type) { 

     // some processing here 
     $foo_name = 'Foo' . $type; 
     $foo = new $foo_name(); 
     $foo->init($qux); 

     return $foo; 
    } 

} 

이 마음에 와서 몇 가지 솔루션을하지만, 그들 중 누구도 이상적입니다 :

  1. 는 정적 세터 메타 추가 팩토리 클래스에 $qux에 대한 od를 입력하고 $qux에 대한 참조를 개인 정적 변수에 저장하십시오. 시스템은 처음에 $qux을 설정할 수 있으며 팩토리 클래스는 보안상의 이유로 향후 변경을 막을 수 있습니다.
    이 방법이 효과가 있지만 $qux에 대한 참조를 저장하기 위해 정적 매개 변수를 사용하는 것은 단위 테스트 중에 문제가됩니다 (예 : 정적 상태로 인해 개별 테스트간에 행복하게 살아남음).
  2. 싱글 톤 패턴을 사용하여 새 컨텍스트 클래스를 만들고 팩토리 클래스에서이를 사용하여 $qux에 대한 참조를 가져 오도록합니다. 이것은 옵션 # 1보다 (팩토리 클래스에서 컨텍스트 클래스로 정적 문제를 이동 시키더라도) 이것을 수행하는 좀 더 깔끔한 방법 일 수 있습니다.
  3. 종속성 주입을 항상 사용합니다. 즉, 팩토리 클래스를 사용하는 모든 객체에 $qux을 전달하고 다른 객체로 공장 클래스에 전달합니다 (Foo_Factory::getFoo($type, $qux);).
  4. 위와 같지만 (# 3) 시스템을 따라 $qux을 전달하는 대신 factory 클래스의 인스턴스를 전달합니다 (이 경우 static이지만 인스턴스화 할 수 없음).

무엇을 권하고 싶니? 위에서 언급 한 네 가지 대안 중 하나를 선택하거나 더 나은 방법으로이 작업을 수행 할 수 있습니까?

참고 : 여기에 flamewar로 static is evil에 들어가기를 원하지 않고 최상의 솔루션을 찾으려고합니다.

답변

5

나는 의존성 삽입과 함께 할 것입니다. 그러나 $ QUX를 어디에서나 전달하는 대신 Dependency Injector Container에 등록하고 컨테이너가이를 정렬하도록합니다. Symfony Component으로 말하면 :

// Create DI container 
$container = new sfServiceContainerBuilder(); 

// Register Qux 
$container->setService('qux', $qux); 
// Or, to have the DI instanciate it 
// $container->register('qux', 'QuxClass'); 

// Register Foobar 
$container->register('foobar', 'Foobar') 
      ->addArgument(new sfServiceReference('qux')); 

// Alternative method, using the current init($qux) method 
// Look! No factory required! 
$container->register('altFoobar', 'Foobar') 
      ->addMethodCall('init', array(new sfServiceReference('qux'))); 
+0

아, 사실은 매우 멋진 - 내가 더 상세하게 (실질적으로) 내가 기회를 얻을 때의 심포니에보고해야합니다 것을 알 수 있습니다. 간단한 컨테이너 솔루션을 만들었고, 여전히 내부적으로 공장을 사용하고 있지만, 매력처럼 작동합니다 .-- 피드백과 예제에 감사드립니다! – MicE

4

난 그냥 공장 방법이 아닌 정적 만들어 주겠다고하고 공장을 필요로 모든 객체에 전달합니다.

공장을 설정하려면 생성자에 $qux 매개 변수를 사용하여 피드를 제공해야합니다.당신이 서비스의 용기 또는 레지스트리 주위에 전달하는 "문제"없이 공장 작업에 필요한 클래스에 사용하기 쉬운을 받아야하는 방식으로

class Foo_Factory { 

    public function __construct($qux) { 
     $this->qux = $qux; 
    } 

    public function getFoo($type) { 
     // some processing here 
     $foo_name = 'Foo' . $type; 
     $foo = new $foo_name(); 
     $foo->init($this->qux); 

     return $foo; 
    } 
} 

.

이 예제에서는 Container 클래스에 실제로 필요한 객체를 전달하고 추상화하지 않는 직접 접근 방식을 사용합니다.

DIC 또는 레지스트리 또는 평범한 구형 DI를 사용할 것인지 결정하는 것은 전체 프로젝트에 대해 수행해야한다고 생각합니다. 나는 강하게 DIC를 선호하지만 정상적인 DI를 더 좋아한다. 주어진 맥락에서 특정 접근법에 대해 논쟁하기가 어렵습니다.

내 요점을 요약하려면 다음과 같이하십시오. 정적 팩터 리가 문제가되는 경우 정적이 아닌 경우.

희망 나는 당신의 포스트를 잘 이해)

+0

감사합니다. 결국 나는 DIC를 사용했다. 왜냐하면 실제로'$ qux'보다 더 많은 의존성을 가지고 있기 때문에. 단위 테스트 가능성의 향상은 말할 것도 없습니다 :-) – MicE

관련 문제