工厂模式合适吗?

时间:2010-08-05 21:34:04

标签: php design-patterns

那么,

我有一个问题(好吧,没有真正的问题,但我想尝试新的东西)和创建对象。实际上我有一些订单,其中包含一个订购项目列表。

这些订单项在整个应用程序中使用并传播,我需要一种方法来创建它们。主要问题是,我希望能够以多种不同的方式创建这些对象。

实际上我在类构造函数中执行此操作并检查是否给出了参数。 (我正在使用php,所以你肯定不会知道该语言的重载支持:))

一个简单快捷的例子

class foo {
    protected $_data=null;
    public function __contruct($bar){
        if (is_array($bar)){
            $this->_data=$bar;
        }
        else {
            $dataFromDb=getDataFromDatabase
            $this->_data=$dataFromDb;
        }
    }
}

无论如何,如果我想通过提供另一种类型的参数来创建我的对象,让我们说一个封装在字符串中的xml文档我需要将所有这些东西放在我的构造函数中。 如果创建对象的过程更复杂,我最终需要为每种类型创建一个单独的方法,我想启动。但只有在创建此特殊类型时才会调用此方法。 (我认为你遇到了问题:))

另一个问题浮现在脑海中,如果我在构造函数中需要更多参数来创建具体对象,我已经修改了所有代码,导致构造函数发生了变化。 (好吧,我可以给他越来越多的参数并使用默认值,但这不是我真正想要的。)

所以我的问题是,哪种模式适合这个问题来解决我创建的具体对象。我想为我想要创建具体对象的每种方式创建一个工厂。但我不确定这是否是解决此类问题的常用解决方案。

2 个答案:

答案 0 :(得分:2)

如果只改变构造函数的签名,我会这样做(Zend Framework的通用构造函数):

class foo {
  // params

  public function __construct($options = null)
  {

    if(null !== $options)
    {
       $this->setOptions($options);
    }
  }

  public function setOptions(array $options){

    foreach ($options as $name => $value){
      $method = 'set' . $name;
      if(method_exists($this, $method)
      {
         $this->$method($value);
      }
   }

   return $this;
  }
}

这个ess理论上所有的构造函数参数都是带有命名键的数组元素,以及在初始化过程中你想要在这个数组中使用的任何东西,你为它创建一个setter然后自动调用它。缺点是IDE中缺乏有效的暗示。

另一方面,如果你想拥有特定的构造函数,那么我可能会选择工厂,但仍然使用相同的方法:

class foo {

  public static function create($class, $options)
  {
     if(class_exists($class))
     {
        $obj = new $class($options);
     }
  }
}

当然,您也可以使用PHP的反射来确定如何调用构造函数而不是仅注入任意数组参数。

答案 1 :(得分:1)

你可以简单地把它变成一个带有可选参数的工厂:)

class Example_Factory
{
    public static function factory($mandatoryParam, $optionalParam = null)
    {
        $instance = new self;
        $instance->setMandatory($mandatoryParam);

        if ($optionalParam !== null) {

            $instance->setOptional($optionalParam);
        }

        return $instance;
    }

    public function setMandatory($in)
    {
        // do something....
    }

    public function setOptional($in)
    {
        // do some more...
    }
}