2012-02-10 2 views
2

현재 추상 팩토리를 사용하여 요청 객체를 생성하기위한 사용자 정의 클래스 이름을 지정할 수 있습니다. 이렇게하는 이유는 코드를 변경하지 않고 핵심 기능을 쉽게 확장 할 수있게하려는 것입니다. 하지만 최근에이 접근법의 효용성에 관해서 몇 가지 의문점이있었습니다. PHP의 추상 팩토리 패턴으로 사용자 정의 클래스 인스턴스화 허용

는 공장 가 예상되는 인터페이스는 공장 개념의 bastardization 일치하는지 어떤 제출 된 클래스 이름을 인스턴스화 할 수 있습니다 : 그래서 제 질문은 이것이다? 나는 이것을 피하는 것이 더 나은가?

UPDATE 여기 논리가

이 : 한편으로, (예를 들어)는 실제 자동차 공장은 자동차를 만들 수 없습니다 그것은 기계가 장착되어 있지 않은 경우는 만들려면 그 종류의 차. 다른 한편으로는, 아래의 코드는 같은 자동차 공장에 청사진을 제공하여 원래 의도하지 않은 맞춤형 자동차를 만드는 것과 같습니다.

대안으로는 공장에서 사용할 수있는 사용자 정의 클래스 이름을 지정하는 구성 객체를 전달하고 구성 지정 사용자 정의 클래스 이름과 일치하는 경우 사용자 지정 클래스 만 생성하도록 팩토리를 제한 할 수 있습니다. 이견있는 사람?


그리고 관련 코드

...

<?php 

interface AbstractRequestFactory 
{ 
    public function buildRequest($type); 
} 

class RequestFactory implements AbstractRequestFactory 
{ 
    public function buildRequest($type='http') 
    { 
    if ($type == 'http') { 
     return new HttpRequest(); 
    } elseif ($type == 'cli') { 
     return new CliRequest(); 
    } elseif ($custom = $this->makeCustom($type)){ 
     return $custom; 
    } else { 
     throw new Exception("Invalid request type: $type"); 
    } 
    } 

    protected function makeCustom($type) 
    { 
    if (class_exists($type, FALSE)) { 
     $custom = new $type; 
     return $custom instanceof RequestInterface ? $custom : FALSE; 
    } else { 
     return FALSE; 
    } 
    } 
} 

// so using the factory to create a custom request would look like this: 

class SpecialRequest implements RequestInterface {} 

$factory = new RequestFactory(); 
$request = $factory->buildRequest('\SpecialRequest'); 
+0

$ 유형 코드 스 니펫을 게시 할 수 있습니까? –

+0

@MikePurcell 귀하의 요청에 따라 코드의 하단을 업데이트했습니다. – rdlowrey

+0

"CLI", "Http"공장이 인터페이스 팩토리를 구현하기 위해 인터페이스 팩토리와 다양한 유형을 모두 줄이려고했습니다. –

답변

1

넌 꽤 잘하는 군. 팩토리가있는 시점은 몇 가지 기준을 전달하고 메서드가 호출 된 코드에서 사용할 수있는 동일한 호출 가능 메서드를 갖을 것으로 가정하는 개체를 반환하는 것입니다. RequestInterface를 구현하여이 가정을 시행하고 있으므로 모든 사용자 정의 요청 클래스가 동일한 인터페이스를 구현하는 한 '비 오브젝트에서 함수를 호출 할 수 없음'시나리오가 종료되지 않습니다.

권고의 커플 (단지 개인적인 취향) :

  • 내가 당신에게, 그렇지 않으면 내가 널 또는 makeCustom()에서 객체 반환 buildRequest

    에 $ 유형에
  • 을 스위치/케이스를 사용합니다

  • 사용자 정의 유형의 수에 따라 실제로 혼란을 줄이기 위해 스위치 케이스에 하드 코딩합니다. 나에게 틀리게하지 마라, 많은 수업을 가지고 있으면 당신이 가지고있는 것은 훌륭하지만 기회는 없다.

  • "코드를 변경하지 않고 핵심 기능을 쉽게 확장 할 수있는"조각을 사용자 지정 형식 클래스로 확장 할 수있는 추상 부모 클래스에 넣는 것을 고려한 적이 있습니까?

  • 또한 팩토리는 객체를 만들기 때문에 정적으로 설정하는 것이 일반적입니다.

예제 코드 :

public static function getRequest($type='http') 
{ 
    switch ($type) { 

     case 'http': 
      return new HttpRequest(); 

     case 'cli': 
      return new CliRequest(); 

     case 'myCustom1': 
      return new MyCustom1(); 

     case 'myCustom2': 
      return new MyCustom2(); 

     default: 
      throw new Exception("Invalid request type: $type"); 
    } 
} 

$request = RequestFactory::getRequest($type); 

// As long as all objects in factory have access to same methods 
$request->doSomething(); 
$request->andDoSomethingElse(); 

// Otherwise you end up with that feared 'unable to call function on non-object' 
$request->iAmASneakyMethodNotEnforcedByAnInterfaceOrAvailableByExtension();  
+0

hehe, +1 * "iAmASneakyMethodNotEnforcedByAnInterfaceOrAvailableByExtension (*") * 및 유용한 글 머리표 – rdlowrey

+0

No prob. 내가 언급했듯이 그들은 단지 개인적 취향 일 뿐이며 이미 가지고있는 것에 대해서는 아무것도 아닙니다. –

1

이 매우 주관적이기 때문에 다음과 같은 단 하나 개의 의견입니다 :

나는 이런 식으로 뭔가를 사용하는 것이 빨리하지 않을 것입니다. 공장이 관심을 갖게 될 소수의 수업 만 있다면, 나는 그 수업을 열심히 코딩 할 것입니다. 그러나 당신이 이것들의 큰 세트를 가지고 있다면, 그것이 적절할 수 있다고 생각합니다.

클래스가 적절한 인터페이스를 확장하는지 확인하면 감히 안전하지 않으므로 수행중인 작업에 아무런 문제가 없다고 말할 수 있습니다. 해당 팩토리 메소드를 사용하는 코드는 깨끗하게 보입니다. 나는 이것이 가장 중요한 것이라고 생각한다.

당신이 그런 곳에서 그런 기술을 사용했다면 나는 그것에 반대 할 것입니다. 그러나 이것은 구현에서 숨겨져 있기 때문에 약간 부적절한 작업을 할 때 더 많은 여유를 가질 수 있다고 생각합니다.

+0

좋은 조언. 그리고 네, 그것은 약간의 주관적인 질문입니다. 그리고 저는 그 이유 때문에 여기에 거의 게시하지 않았습니다. 이것은 내가 생각했던 것과 같은 일이지만, 나는 다른 의견을 원했다. 당신이 말하는 것처럼 "구현에서 숨겨져있는"* 것에 도움이 될 수 있다고 생각합니다. 사방에 사용하면 방어하기가 어려울 것입니다. – rdlowrey

1

왜 디스패치 배열을 사용하지? 즉

class RequestFactory 
{ 
    private static $requests = array(
     'http' => 'HttpRequest', 
     'cli' => 'CliRequest', 
     'summatelse' => 'Summat' 
    ); 
    public static GetRequest($type) 
    { 
     if (array_key_exists($type, $requests)) return new $requests[$type]; 
     else throw new Exception("Invalid request type: $type"); 
    } 
} 
+0

니스. 이것은 잘 작동 할 것이다. –

관련 문제