Статика это плохо, но как насчет фабричной модели?

13

Я работаю над проектом TDD, поэтому стараюсь как можно больше придерживаться хороших правил, связанных с таким развитием. Один из них - избегать как можно более статичных и глобальных.

Я сталкиваюсь с этой проблемой: у меня есть объект "article", с которым могут быть связаны "options" (дополнительная "micro-article").

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

С моей реальной точки зрения, я вижу 3 варианта:

1) Построить внутри статьи:

class Article
{
    //[...]
    public function getArrOption(){
        //Build an array of Options instance.
        //return an array of Options.
    }
}

Pro: прямо вперед

Const: Maintenability: объект article теперь содержит логику построения для объекта Option. Это, вероятно, приведет к дублированию кода.

2) Использование опции Factory

class Article
{
    //[...]
    public function getArrOption(){
        return OptionFactory::buildFromArticleId($this->getId());
    }
}

Pro: Построение логики не из класса Article

Const: Я нарушаю правило "статика трудно подделать", делая мой класс Article трудным для тестирования.

3) Разделить все логики.

//Build the array of Option instance in a controller somewhere, using a Factory:
$arrOption = OptionFactory::buildFromArticleId($article->getId());

Pro: Статья обрабатывает только его собственную ответственность и не заботится о его «отцовской» ссылке на опции. Вещи действительно отделены

Const: Потребуется больше кода внутри контроллера каждый раз, когда мне понадобится доступ к опциям. Это означает, что я никогда не должен использовать Фабрику внутри объекта, и это звучит для меня утопично ...

Какой лучший путь? (Я что-то пропустил?) Спасибо.

Редактировать:

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

FMaz008
источник
Я не уверен, что это уместно, но я пишу код на PHP, поэтому «приложение» - это состояние меньше. Мы должны перезагрузить все данные между каждой страницей, если они не сохранены в файле cookie сеанса. Это означает, что мы не можем предварительно загрузить все как на языке приложения.
FMaz008
@job: Ну, это потому, что статический вызов внутри метода в большинстве случаев невозможно заменить при модульном тестировании. Цель состоит в том, чтобы использовать внедрение зависимости. Но фабрика, как правило, статична, поэтому ее нельзя вводить.
FMaz008

Ответы:

12
  1. Статика не "плохая", она не поддающаяся контролю. Вы все еще можете использовать его там, где насмешка не имеет смысла.

  2. Это не шаблон фабрики, он выглядит как шаблон репозитория, хотя может и не быть. Фабрика - это то, где у вас есть несколько классов с одним и тем же интерфейсом / базовым классом, и вы хотите выделить логику, которая решает, какой класс вернуть. Репозиторий получает данные из своего репозитория, абстрагируя от реализации этого репозитория (статья не должна знать, хранятся ли его параметры в той же БД, другой, XML-файле, CSV-файле и т. Д.).

  3. Вы проигнорировали возможность дать классу Article объект ObjectFactory (или Repository, или любой другой) в конструкторе, для которого он может вызывать метод buildFromArticle.

Мой PHP ржавый, но я думаю, что это выглядит так:

class Article
{
    private $_option_repository;

    public function __construct($option_repository) {
        $_option_repository = $option_repository;
    }

    //[...]

    public function getArrOption(){
        return $_option_repository->buildFromArticleId($this->getId());
    }
}

Я думаю, что это выполняет все ваши плюсы выше.

прецизионный самописец
источник
Так что нормально иметь экземпляры Factory / Repository / Mapper? Мне понадобится контейнер зависимостей или что-то в этом роде, потому что если нам нужно внедрить всю фабрику / репозиторий / маппер для всех возможных объектов, которые могут быть возвращены объектом, это быстро принесло пользу. (Статья -> OptionGroup -> Option -> Статья и т. Д.)
FMaz008
1
Это более чем хорошо, это предпочтительнее. Я обычно резервирую статическое использование для удаления повторяющегося кода, если он достаточно мал для тестирования в нескольких классах. И да, Контейнер IOC / DI сделает вашу жизнь намного проще. Используйте один.
фунтовые
1

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

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

(1) Заменить каждое вхождение глобала доступом к переменной экземпляра;

(2) Пусть эта переменная экземпляра будет автоматически введена в объект при его создании.

«Сьюз: разделение ответственности от статических методов для детальной настройки»

Wayback Machine Link

nes1983
источник
3
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится.
Комнат