This registers collaborators (dependencies) in the constructors in order to decouple the object creation in methods.
inversion control, dependency injection, builder
Testable, reusable and maintainable code by avoiding hard-coded references in methods.
- Creating collaborators (a.k.a. dependencies) only in constructors.
- Avoiding a global dependency injection container.
- Switching default implementations with alternatives and test's objects.
- Referencing of classes and interfaces with its namespace.
- Usage of mapping.
- Anonymous classes.
- Passing empty objects that create those which are fully identifiable.
- Defining and implementing an interface for each collaboration.
// It reconstitutes a person from a data store: PersonID is a kind
// of Identity as much as an AboutMe is a kind of About and both
// of them are collaborators. Take note that the creation is
// delayed until need it, but it is not a Singleton.
// Testing purposes.
$person = new PersonFromStore(
new FetchedPerson($id), TestPersonID::class, AboutMe::class
);
// Application.
$person = new PersonFromStore(
new FetchedPerson($id), PersonID::class, AboutMe::class
);
// Description
final class PersonFromStore implements Party
{
private $record;
private $identity;
private $about;
public function __construct(IdentityRecord $record, string $identity, string $about)
{
$this->record = $record;
$this->identity = new Assignment(Identity::class, $identity);
$this->about = new Assignment(About::class, $about);
}
// Please, your ID?
public function identity() : Identity
{
// It calls the main constructor or the operator "new" in the ID class.
// Same as: new PersonID(...)
return $this->identity->new($this->record->key());
}
// Tell me something about you.
public function about() : About
{
// It calls a convenience constructor in the AboutMe class.
// Same as: AboutMe::withID(...)
return $this->about->withID($this->identity());
}
}
// Definition
final class PersonFromStore implements Party
{
// It can use another word, such as join, to avoid conflicts with traits.
use (Identity, About);
public function identity() : Identity
{
return new Identity($record->key());
}
...
}
// Client
$person = new PersonFromStore($fetchedPerson) use (PersonID, AboutMe);
// Test
$person = new PersonFromStore($fetchedPerson) use (TestPersonID, AboutMe);
Now, we can create objects from their interfaces and thus, we have no more hard-coded dependencies in the methods.