Avillions
@Avillions
PHP Developer at Genesis

Как правильно подобрать архетикуру (ООП) для задачи?

Не могу правильно подобрать архитектуру для задачи, пишу что-то наподобии агрегатора сайтов.

Есть модель Account c такими полями: login, password, provider_name

Есть класс Manager, в конструктор которого передается модель Account. В классе Manager есть метод getProvider(). Который инициализирует и возвращает объект класса Provider в соответствии со значением свойства provider_name в модели Account.

На каждый агрегируемый сайт есть свой класс Provider который может имплетировать интерфейсы например: ProfileInterface, MessageInterface, NewsInterface и т.д.

Интерфейсы описывают основные методы для работы с сайтом. Что бы можно было работать в цикле (при помощи конструкции instanceof) с разными сайтами не думая о том что происходит внутри класса Provider.

Так вот получается что когда класс Provider имплементирует несколько интерфейсов - то все хорошо, но когда количество имплементируеммых интерфейсов становится больше 5-10, то файл становится не читаемым, слишком много методов в классе Provider.

Допустим есть такие провайдеры:
Social/VK/Provider
Social/OK/Provider
Social/Facebook/Provider

Класс Manager получая в конструкторе объект Account по полю provider_name находит нужный Provider, например Social/VK/Provider и инициализирует его и возвращает объект Provider. То есть проводится авторизация на сайте Вконтакте в конструкторе класса Provider.

Дальше есть задача получить новости со всех аккаунтов:

foreach($accounts as $account) {
    $provider = Manager::getProvider($account);
    if ($provider instanceof NewsInterface) {
        $news = $provider->getNews();
        //...
    } else continue;
}


Я первым делом вспомнил про трейты, но дело в том что методы из разных интерфейсов могут использовать друг друга (например трейт описывающий реализацию интерфейса MessageInterface использует трейт описывающий реализацию интерфейса ProfileInterface). Да и почти в каждом трейте идет работа с БД коннект которого находится в свойстве объекта Provider.

В общем трейты работают, но не эстетически красиво. Я уверен что есть более красивая реализация, только не могу ее найти.

Заранее спасибо за любое замечание и предложение =)
  • Вопрос задан
  • 389 просмотров
Пригласить эксперта
Ответы на вопрос 1
alexey-m-ukolov
@alexey-m-ukolov Куратор тега PHP
Что бы можно было работать в цикле (при помощи конструкции instanceof) с разными сайтами не думая о том что происходит внутри класса Provider.
Для этого существует полиморфизм. Instanceof - это антипаттерн.

По большому счету, замена трейтов - агрегация. Инжектите в конструкторе провайдера нужные обработчики и вызывайте уже их:
class FooProfileThing implements ProfileThingInterface {}

class FooMessageThing implements MessageThingInterface {}

class FooProvider extends Provider
{
  public function __constructor($bar)
  {
    $this->bar = $bar;
    $this->profileThing = new FooProfileThing;
    $this->messageThing = new FooMessageThing;
  }
}

Таким образом вы соблюдете принцип единственной ответственности и сможете более разумно построить иерархию этих объектов.

Да и вообще, что это за объекты Profile, Message, News, для которых вы создали интерфейс? Почему Provider одновременно ведет себя как профиль, сообщение и новость? Это сущности действительно однотипны?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы