views:

43

answers:

2

Well,

I have a problem (ok, no real problem, but I wanna try out something new) with creating objects. Actually I have some orders, which contains a list of orderitems.

These orderitems are used and so spreaded in the whole application, and I need a way to create them. The main problem is, I want to be able to create these objects in many different ways.

Actually I do this in the class constructor and check if the argument which is given. (I'm using php, so there is no overloading support from the language as you surely know :))

A simple and quick Example

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

Anyway, if I want to create my object by giving another type of parameter, lets say a xml-document encapsulated in a string I need to put all this stuff in my constructor. If the process for creating an object is more complicated, I eventually need to create a seperate method for each type, I want to initiate. But this method is only called when this special type is created. (I think you got the problem :))

Another problem comes to mind, if I need more parameters in the constructor to create a concrete object, I have modify all my code, cause the contructor changed. (Ok, I can give him more and more parameters and work with default values, but that is not what I really want).

So my Question is, which pattern fits this problem to solve my creation of a concrete object. I thought about creating a factory for each way I want to create the concrete object. But I'm not sure if this is a common solution to solve such a problem.

+2  A: 

IF its only the signature of the constructor changing i would do it like so (a la the Zend Framework universal constructor):

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;
  }
}

And this essntially means all your constructor parameters are array elements with named keys, and anything you want used in this array during initialization you create a setter for and then its automatically called. The down side is the lack of effective hinting in IDEs.

On the otherhand if you want to have specific constructors then i might go with a factory but still use much the same approach:

class foo {

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

Of course you could alternatively use PHP's reflection to determine how to call the constructor instead of just injecting an arbitrary array argument.

prodigitalson
Wow, the code in example one is very nice. Took me a while to understand it, but I will definatly using it, if it matches any problem i got.But in the concrete scenario I think your second example is the way I want to do it.So I create an abstract base-class of my current one and do the specific things in seperated classes for each way I want to create my object.Thank you, your examples really enlightenend me.
evildead
Glad it helped... please not i changed the constructor a bit... i was in a hurry earlier :-)
prodigitalson
Am I blind, what changed?
evildead
$options = null by default
prodigitalson
+1  A: 

you could simply make it a factory with optional params :)

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...
    }
}
zolex
thank you too for that quick answer. It's a nice solution too, but I think I cannot adept that for my concrete problem, cause I don't have mandatory and optional things. The values I give to the my concrete constructors cannot be splitted in these two categories.
evildead
well it's not limitted to mandatory/optional, it's just an exmaple, you can also have only 1 param or 5. the pattern is to call methods on the new instance depending on the input data :)
zolex