2016-10-28 7 views
0

어떻게 제거합니까? 이 문제를 해결하는 패턴이나 무언가가 있는지 궁금합니다. 기본적으로 다른 클래스의 type 속성을 기반으로 구체적인 자식 클래스를 인스턴스화해야합니다. 즉 type = 1이면 new A이고, else type = 2이면 new B 등입니다. type 속성을 가진 클래스 :공장에서 중복 된 조건문

/** 
* Get a ticket decorator based on the ticket type 
* @return ReferralService\TicketDecorator 
* @throws Exception 
*/ 
public function getTicketDecorator(): ReferralService\TicketDecorator 
{ 
    if (!$this->code) { 
     throw new Exception("Couldn't create a ticket wrapper based on the type without a code"); 
    } 

    /** 
    * The debug service 
    * @var Debug\Service $debugService 
    */ 
    $debugService = app(Debug\Service::class); 
    $debugService->setDebug(config('referral.debug')); 

    switch ($this->code) { 
     case self::TYPE_FEEDBACK: 
      return new ReferralService\TicketDecorator\FeedbackTicketDecorator($debugService); 
      break; 
     case self::TYPE_BIRTHDAY: 
      return new ReferralService\TicketDecorator\BirthdayTicketDecorator($debugService); 
      break; 
     case self::TYPE_NEW_PARTNER: 
      return new ReferralService\TicketDecorator\PartnerTicketDecorator($debugService); 
      break; 
     default: 
      throw new Exception(sprintf("Couldn't instantiate a ticket decorator based on the %s type", $this->code)); 

    } 
} 

/** 
* Instantiate a private page based on the ticket type 
* @param ReferralService\Service $service 
* @param Referrer $referrer 
* @param Ticket $ticket 
* @return ReferralService\Page\PrivatePage 
* @throws Exception 
*/ 
public function getPrivatePage(ReferralService\Service $service, Referrer $referrer, Ticket $ticket): ReferralService\Page\PrivatePage 
{ 
    if (!$this->code) { 
     throw new Exception("Couldn't create a private page based on the type without a code"); 
    } 

    switch ($this->code) { 
     case self::TYPE_FEEDBACK: 
      return new ReferralService\Page\PrivatePage\EmailReference($this->service, $referrer, $ticket); 
      break; 
     case self::TYPE_BIRTHDAY: 
      return new ReferralService\Page\PrivatePage\Birthday($this->service, $referrer, $ticket); 
      break; 
     case self::TYPE_NEW_PARTNER: 
      return new ReferralService\Page\PrivatePage\Partner($this->service, $referrer, $ticket); 
      break; 
     default: 
      throw new Exception(sprintf("Could't find a page for the type", $this->code)); 
    } 
} 

공장의 모든 메소드는 유형 필드를 테스트합니다.이 필드는 나를 위해 서투르게 보입니다. 모든 유형에 대해 별도의 하위 클래스가 있고 조건문없이 팩터 리 메서드를 사용한다고 생각했지만 Laravel 모델에서는 사용할 수 없습니다.

+1

예쁜 것은 아니지만 문제는 없습니다. 공장을 가지고있는 것은 꽤 읽기 쉽고 합법적 인 방법입니다. 나는 너무 많이 걱정하지 않을 것이다. – Andrew

+0

당신은 이미 쓸모없는'break;'('return's 다음에)를 모두 제거 할 수있다. –

+0

@Casimir 맞아요, 전 항상 break 문을 항상 사용하는 데 익숙해 져 있습니다. – Sergey

답변

1

매우 일반적인 리팩토링 패턴은 replace conditionals by polymorphism입니다.

TicketType을 생성하고 티켓 유형에 팩토리 메소드를 구현하여 TicketDecoratorPrivatePage 콘크리트를 생성하는 팩토리를 구현하기 만하면됩니다.

그러나 이것은 단지 TicketType과 그것이 생성하는 구체적인 클래스 사이의 결합을 도입한다는 것을 명심하십시오. 그런 커플 링을 피하는 것이 바람직하다면 초기 디자인을 고수하십시오.

+0

왜 그런 커플 링을 피하고 싶습니까? – Sergey

+0

@Sergey 주로 추상화 수준과 모듈 간의 결합 수준에 따라 다릅니다. 예 :'Product' 모듈에있는'ProductType'을 가지고 있지만'Shipping' 모듈에서 배송 전략을 선택하기 위해 타입이 사용된다면'Shipping'에'Product'를'Shipping'에 연결하는 것을 피할 수 있습니다 '제품'과 연결되어야한다. 가장 좋은 예는 아니지만 잘하면 당신에게 의미가있을 것입니다. – plalx

+0

네, 감사합니다. 아마도 다형성을 사용하여 구체적인 페이지와 데코레이터를 생성하는 추상 팩토리를 오버라이드하는 구체적인 클래스 중 하나를 선택하는 TicketType 클래스 내부의 팩토리 메소드를 수행 할 것입니다. 당신의 답변과 조금 다르긴하지만 여전히 똑같습니다. – Sergey

1

음, 여기 내 해결책이 있습니다. 나는 페이지/데코레이터를 인식하지 못하도록 모든 것의 TicketType (조건문이있는 원래 게시물의 클래스)과 모든 것을 분리했다.

동시에 구체적인 티켓 클래스를 만들었습니다 : BirthdayTicket, PartnerTicket.

나는 티켓의 종류에 따라 티켓 클래스의 구체적인 인스턴스를 생성하는 Ticket 클래스로 팩토리 메소드를 배치 한

- BirthdayTicket, PartnerTicket 등 구체적인 티켓 클래스 내가 (페이지 장식)을 필요로하는 물건을 생산하고 사용을 @plalx에 의해 제안 된 다형성.