问题
Take the following code as an example of what i want:
class SomethingController extends Factory
{
private $somethingRepository;
public function __Construct( ISomethingRepository $repo )
{
$this->somethingRepository = $repo;
}
}
class Factory
{
public function __Construct()
{
// The following call to AddBinding would push into SomethingController the new instance of the class denoted in my AddBinding second parameter.
$this->AddBinding( ISomethingRepository, MySQLSomethingRepository);
// So in this case, if the controller i'm extending has a construct parameter of ISomethingRepository, then make the parameter equal a new MySQLSomethingRepository()
// Then if I want to use JSONSomethingRepository in the future, I only have to change the one AddBinding call and the controller will still work.
}
public function AddBinding( $interface, $concrete )
{
// Somehow assign the constructor properties of the extending class as new instances of the bindings i have called upon in the construct of my factory class (see this class's construct)
// Pseudo code:
// ----------------------
$calledClass = get_called_class();
$class = new \ReflectionClass( $calledClass );
$method = $class->getMethod( "__construct" );
$params = $method->getParameters();
foreach( $params as $param )
{
if ( $param == $interface )
{
return new $concrete;
}
}
// /Pseudo code:
// ----------------------
}
}
I want to implement a factory kind of class.
- This factory class will be extended by a controller class.
- the factory class will look at the construct parameters of the controller class and make new instances of the object based off of my AddBindings method in the factory.
Let's say I wanted to have a MySQLSomethingRepository which has data coming from MySQL... injected into my SomethingController... Somewhere I need to declare that
SomethingController( new MySQLSomethingRepository() )...
which hopefully will be dealt with by my factory class...
The current way i'm doing it is that is forcing a direct coupling with the data source... which is making it very hard to do test cases with:
private $somethingRepository = new MySQLSomethingRepository();
so imagine if i have used this same repository in loads of other controllers and i want to change my database source to some json data and i implement the following repository "JsonSomethingRepository", I have to go and change all of the controllers to:
private $somethingRepository = new JsonSomethingRepository();
How might i implement my Factory class so that it can deal with creating the instances my controller class is demanding inside the AddBindings function?
回答1:
Design an abstract class in Adapter model and provide some common methods for child class. You can design both repos with adapters to injected in you controllers.
My recommendtation is to use Abstract class and do it in way below:
class SomethingController extends AbstractController {
}
abstract class AbstractController {
protected $somethingRepository;
public function __Construct(ISomethingRepository $repo) {
$this->somethingRepository = $repo;
$this->AddBinding ( ISomethingRepository, MySQLSomethingRepository );
}
public function AddBinding($interface, $concrete) {
// Somehow assign the constructor properties of the extending class as new instances of the bindings i have called upon in the construct of my factory class (see this class's construct)
}
}
Hope it would be help.
来源:https://stackoverflow.com/questions/20471675/how-to-implement-a-factory-class-using-php-dependancy-injection