Разработка сервисного контейнера: SRP, выбор правильного креационного шаблона и избежание тесной связи

Я пишу свою собственную реализацию Laravel Service Container, чтобы попрактиковаться в некоторых шаблонах проектирования, а затем создать частную микросхему.

Класс выглядит сейчас так:

class Container implements ContainerInterface
{
/**
* Concrete bindings of contracts.
*
* @var array
*/
protected $bindings = [];

/**
* Lists of arguments used for a class instantiation.
*
* @var array
*/
protected $arguments = [];

/**
* Container's storage used to store already built or customly setted objects.
*
* @var array
*/
protected $storage = [];/**
* Returns an instance of a service
*
* @param $name
* @return object
* @throws \ReflectionException
*/
public function get($name) {
$className = (isset($this->bindings[$name])) ? $this->bindings[$name] : $name;

if (isset($this->storage[$className])) {
return $this->storage[$className];
}

return $this->make($className);
}

/**
* Creates an instance of a class
*
* @param $className
* @return object
* @throws \ReflectionException
*/
public function make($className) {
$refObject = new \ReflectionClass($className);
if (!$refObject->isInstantiable()) {
throw new \ReflectionException("$className is not instantiable");
}

$refConstructor = $refObject->getConstructor();
$refParameters = ($refConstructor) ? $refConstructor->getParameters() : [];

$args = [];
// Iterates over constructor arguments, checks for custom defined parameters
// and builds $args array
foreach ($refParameters as $refParameter) {
$refClass = $refParameter->getClass();
$parameterName = $refParameter->name;
$parameterValue =
isset($this->arguments[$className][$parameterName]) ? $this->arguments[$className][$parameterName]
: (null !== $refClass ? $refClass->name
: ($refParameter->isOptional() ? $refParameter->getDefaultValue()
: null));

// Recursively gets needed objects for a class instantiation
$args[] = ($refClass) ? $this->get($parameterValue)
: $parameterValue;
}

$instance = $refObject->newInstanceArgs($args);

$this->storage[$className] = $instance;

return $instance;
}

/**
* Sets a concrete implementation of a contract
*
* @param $abstract
* @param $concrete
*/
public function bind($abstract, $concrete) {
$this->bindings[$abstract] = $concrete;
}

/**
* Sets arguments used for a class instantiation
*
* @param $className
* @param array $arguments
*/
public function setArguments($className, array $arguments) {
$this->arguments[$className] = $arguments;
}
}

Это работает нормально, но я ясно вижу нарушение SRP в make() метод. Поэтому я решил делегировать логику создания объекта отдельному классу.

Проблема, с которой я столкнулся, состоит в том, что этот класс будет тесно связан с Container учебный класс. Потому что ему нужен доступ к $bindings а также $arguments массивы, и get() метод. И даже если мы передадим эти параметры классу, хранилище все равно останется в контейнере. В общем, вся архитектура неверна, и нам нужно еще 2 класса: StorageManager а также ClassFactory, Или, может быть ClassBuilder? И должен ClassFactory быть в состоянии построить аргументы конструктора или ему нужен другой класс — ArgumentFactory?

Что вы думаете, ребята?

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …