Является ли DI через Builder эквивалентным шаблону Service Locator? - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть объект класса Foo, созданный строителем. Конструктор передает себя в конструктор А, который затем устанавливает из него все свойства А.

  • Foo требует другого объекта (Bar) в качестве зависимости.

  • Строитель получает этот объект в качестве аргумента конструктора на своем конкретизации.

  • BuildDirector получает Builder в качестве аргумента конструктора на своем конкретизации.

  • Клиент получает BuildDirector в качестве аргумента конструктора на своем конкретизации.

Эта цепочка внедрения зависимостей обрабатывается контейнером Pimple DI при запуске приложения:

$dependencies = new \Pimple\Container();

$dependencies['FooDependency'] = functiom($c) {
    return new \App\Bar();
};
$dependencies['FooBuilder'] = function($c) {
    return new \App\FooBuilder($c['FooDependency']);
};
$dependencies['FooBuildDirector'] = function($c) {
    return new \App\FooBuildDirector($c['FooBuilder']);
};

$dependencies['Client'] = function($c) {
    return new \App\Client($c['FooBuildDirector']);
};

$client = $dependencies['Client'];
  • Когда требуется Foo, клиент вызывает FooBuildDirector, который был передан ему для создания объекта.
  • FooBuildDirector затем устанавливает все атрибуты объектов в FooBuilder и вызывает его метод "build ()".
  • FooBuilder затем создает новый Foo и передает себя в его конструктор.
  • Foo устанавливает все свои свойства, а также зависимости из FooBuilder.

FooBuildDirector:

class FooBuildDirector
{

    protected $fooBuilder;

    public function __construct(FooBuilderInterface $fooBuilder)
    {
        $this->fooBuilder = $fooBuilder;
    }

    public function build(): FooInterface
    {
        return $this->fooBuilder->reset()
                                ->setFooProperty1('something')
                                // set some more properties...
                                ->build();
    }

}

FooBuilder:

class FooBuilder implements FooBuilderInterface
{

    protected $fooProperty1;
    // some more Foo properties
    protected $fooDependency;

    public function __construct(FooDependencyInterface $fooDependency)
    {
        $this->fooDependency = $fooDependency;
    }

    public function reset(): FooBuilderInterface
    {
        // set all Foo properties to null
    }

    public function build(): FooInterface
    {
        return new Foo($this);
    }


    // some setters and getters for Foo properties

 }

Foo

class Foo implements FooInterface
{

    protected $property1;
    // some other properties
    protected $dependency;

    public function __construct(FooBuilderInterface $builder)
    {
        $this->setDependency($builder->getFooDependency())
             ->setProperty1($builder->getFooProperty1())
             // set some other properties;
    }

    // some other methods

}

Я сомневаюсь, что передача зависимости объекту Foo внутри Builder не совпадает с использованием антишаблона «Локатор служб», поскольку он скрывает зависимость и делает его не очевидным при рассмотрении типов аргументов конструктора Foo.

Есть ли лучший способ сделать это, учитывая, что использование Builder необходимо (так как есть много других свойств, которые должны быть установлены при создании экземпляра Foo)? Возможно, требуются и конструктор, и зависимость в качестве аргументов конструктора Foo?

...