mercredi 25 février 2015

Looking for a loader design pattern

Let's say I have the following classes whose instances store their property somewhere for e.x. in a JSON file or a database:


Class Foo



abstract class Foo
{
protected $ID;
protected $title;

// getters and setters
}


Class Bar (extends Foo)



class Bar extends Foo
{
protected $text;

// getters and setters
}


Class Baz (extends also Foo)



class Baz extends Foo
{
protected $tabs = array();

// getters and setters
}


What's the best way to load them from the data source?


How I do it now (not satisfying)


My abstract class Foo has a method load($ID, PDO $pdo). This method is overwritten by Bar and Baz which extends the general loading of the title property in Foo class with their own properties which have to be loaded.


So in code this would look something like this:


Class Foo



abstract class Foo
{
protected $ID;
protected $title;

public static function load($ID, PDO $pdo)
{
$result = null;

// SQL query for getting $title property into $result

return $result;
}

// getters and setters
}


In the class Bar I do this:



class Bar extends Foo
{
protected $text;

public function __construct(stdClass $data)
{
$this->ID = $data->ID;
$this->text = $data->text;
}

public static function load($ID, $pdo)
{
$generalInfo = parent::load($ID, $pdo);

$result = null;

// PDO query for getting $text property into $result

$generalInfo->text = $result;

return $generalInfo;
}

// getters and setters
}


So this let me call $dataToCreateInstance = Bar::load(4, $pdoInstance) and returns the needed information to instanciate the specific Bar object with ID 4.


The probleme here is (as you can see) my classes are bound to PDO also it's really ugly to implement a load method for each data source so it's not generic at all.


What I want to achieve


I'm looking now for a pattern which let me load those classes from any source. I thought about a Loader class which looks like this:



class LoaderManager
{
/**
* @var Loader[]
*/
protected $loaders = array();

public function registerLoader($className, $loaderClass)
{
$this->loaders[$className] = $loaderClass;
}

public function loadClass($class, $ID)
{
return $this->loaders[$class]->load($ID);
}
}


and with an abstract Loader class



abstract class Loader
{
public abstract function load($ID);
}


So now I have decoupled the thing. The problem with this attempt is that I have always to provide an additional Loader for the class itselfs. So for the class Bar I have to provide at least one of BarLoaderPDO or BarLoaderJSON. Which is somehow not that elegant and feels a bit "wrong".


Also there is the problem that I have to store somewhere the mapping which class in the current application has to use which loader.


But it is the only attempt I can think of which leads me to that what I want to achieve.


I like now to discuss and hear if there are other (better) attempts and how to realize them.


Aucun commentaire:

Enregistrer un commentaire