Внедрение зависимостей, когда вы не контролируете создание и использование - PullRequest
3 голосов
/ 13 февраля 2010

Как это сделать?

У меня есть класс Model, который является родительским для многих подклассов, и эта Модель зависит от соединения с базой данных и механизма кэширования.

Теперь вот тут-то и начинаются проблемы: я не контролирую, как создается и используется каждый объект, но у меня есть контроль над методами, которые используются подклассами.

В настоящее время я прибегаю к использованию статических методов и свойств для внедрения зависимостей, например:

class Model
{
    private static $database_adapter;
    private static $cache_adapter;
    public static function setDatabaseAdapter(IDatabaseAdapter $databaseAdapter)
    {
        self::$databaseAdapter = $databaseAdapter;
    }
    public static function setCacheAdapter(ICacheAdapter $cacheAdapter)
    {
        self::$cacheAdapter = $cacheAdapter;
    }
}

Что сработало хорошо, но кажется грязным (оно создает глобальное состояние для всех моделей).

Я рассмотрел шаблон фабрики, но он снимает контроль создания экземпляров с подклассов (как создать экземпляр объекта с переменным числом параметров в его конструкторе?).

Теперь я в растерянности. Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 13 февраля 2010

Насколько я знаю, это вполне приемлемая альтернатива. Другая возможность, предложенная Себастьяном Бергманном, создателем PHPUnit, заключается в наличии статического свойства $ testing. Вы можете прочитать его недавнюю статью о Тестировании синглетонов . Похоже, у вас есть похожие проблемы.

0 голосов
/ 13 февраля 2010

Ваше решение подойдет для установки адаптеров по умолчанию, но я бы добавил способ для отдельных моделей иметь другой адаптер. Учтите это:

abstract class Model {
    protected $_database_adapter;
    protected $_default_database_adapter;

    public function getDatabaseAdapter() {
        if(!$this->_database_adapter) {
            if(self::$_default_database_adapter) {
                $this->_database_adapter = self::$_default_database_adapter;
            } else {
                throw new Exception("No adapter set yet");
            }
        }
        return $this->_database_adapter;
    }

    public function setDatabaseAdapter(IDatabaseAdapter $databaseAdapter) {
        $this->_database_adapter = $databaseAdapter;
    }

    public static function setDefaultDatabaseAdapter(IDatabaseAdapter $databaseAdapter) {
        self::$_default_database_adapter = $databaseAdapter;
    }
}

Конечно, вы можете извлечь все статические методы / свойства в Registry, Container или что-нибудь еще в качестве центрального.

Например, возможно, вы не хотите собирать данные с одного хоста базы данных по всему вашему приложению. Тогда ваш оригинальный сценарий будет выглядеть следующим образом:

Model::setDatabaseAdapter($default);
$my_model->query('....');
Model::setDatabaseAdapter($another_adapter);
$my_other_model->query('....');
Model::setDatabaseAdapter($default);

что очень похоже:

mysql_select_db('default_db');
mysql_query('...');
mysql_select_db('other_db');
mysql_query('...');
mysql_select_db('default_db');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...