Фабричный класс с инициализацией объекта - пытается избежать статического - PullRequest
7 голосов
/ 30 марта 2011

Я пытаюсь создать набор фабричных классов для нашей системы, где некоторые объекты, созданные фабрикой, также должны быть инициализированы, прежде чем они могут быть использованы должным образом.

Пример:

$foobar = new Foobar();
$foobar->init( $qux, ... );
// $foobar ready for usage

Для того же примера, допустим, что объект $qux является единственной зависимостью, в которой нуждается Foobar.Я хотел бы получить следующее:

$foobar = Foo_Factory( 'bar' );

Чтобы избежать необходимости передавать объект $qux по всей системе и передавать его классу фабрики в качестве другого параметра, яЯ хотел бы выполнить инициализацию Foobar непосредственно в фабричном классе:

class Foo_Factory {

    public static function getFoo( $type ) {

        // some processing here
        $foo_name = 'Foo' . $type;
        $foo = new $foo_name();
        $foo->init( $qux );

        return $foo;
    }

}

Есть несколько решений, которые приходят на ум, но ни одно из них не является идеальным:

  1. Добавитьметод статического установщика для $qux фабричного класса, и пусть он хранит ссылку на $qux в закрытой статической переменной.Система может установить $qux в начале, а фабричный класс может предотвратить любые будущие изменения (по соображениям безопасности).Хотя этот подход работает, использование статического параметра для хранения ссылки на $qux проблематично во время модульного тестирования (например, он успешно выживает между отдельными тестами благодаря своему статическому состоянию).
  2. Создание нового класса контекста с помощью Singletonшаблон и пусть фабричный класс использует его, чтобы получить ссылку на $qux.Это может быть немного более чистым способом сделать это, чем вариант № 1 (хотя мы переносим статическую проблему из класса фабрики в класс контекста).
  3. Полное использование внедрения зависимостей, то есть передача $qux влюбой объект, который использует класс фабрики, и пусть этот объект передает его классу фабрики в качестве другого параметра: Foo_Factory::getFoo($type, $qux);.
  4. То же, что и выше (# 3), но вместо передачи $qux вдольсистема, вместо этого передайте экземпляр класса фабрики (т. е. в этом случае он будет не статичным, а инстанцируемым).

Что бы вы порекомендовали, пожалуйста?Любая из четырех альтернатив, упомянутых выше, или есть лучший способ сделать это, пожалуйста?

Примечание: я не хочу входить в static is evil флейм здесь, просто пытаюсь придумать лучшеерешение.

Ответы [ 2 ]

5 голосов
/ 30 марта 2011

Я бы пошел с инъекцией зависимости полностью. Но вместо того, чтобы передавать $ qux везде, просто зарегистрируйте его в контейнере инжектора зависимостей и дайте контейнеру разобраться. В Symfony Component говорят:

// Create DI container
$container = new sfServiceContainerBuilder();

// Register Qux
$container->setService('qux', $qux);
// Or, to have the DI instanciate it
// $container->register('qux', 'QuxClass');

// Register Foobar
$container->register('foobar', 'Foobar')
          ->addArgument(new sfServiceReference('qux'));

// Alternative method, using the current init($qux) method
// Look! No factory required!
$container->register('altFoobar', 'Foobar')
          ->addMethodCall('init', array(new sfServiceReference('qux')));
4 голосов
/ 30 марта 2011

Я бы просто сделал методы фабрики нестатичными и передавал их каждому объекту, которому нужна эта фабрика.

Чтобы настроить фабрику, вам нужно указать в параметре $qux в конструкторе.

class Foo_Factory {

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

    public function getFoo( $type ) {
        // some processing here
        $foo_name = 'Foo' . $type;
        $foo = new $foo_name();
        $foo->init( $this->qux );

        return $foo;
    }
}

При таком подходе вы должны получить простоту использования в классах, где вам нужно работать с фабрикой, без "проблем" передачи сервисного контейнера или реестра.

В этом примере я бы использовал прямой подход, просто передавая объекты, которые вам действительно нужны, а не абстрагируя их в классы-контейнеры.

Решение о том, использовать ли DIC или Registry или обычный старый DI, должно быть сделано для всего вашего проекта. Я настоятельно предпочитаю DIC, а не реестр, но лучше обычного DI. Для данного контекста трудно спорить за или против определенного подхода.

Подводя итог: если статическая фабрика - проблема, просто сделайте ее не статичной.

Надеюсь, я правильно понял ваш пост;)

...