Taras_Serevann
@Taras_Serevann
веб-разработчик, автор

Как правильно реализовать инверсию зависимостей в PHP?

Допустим, есть проект -- обертка над API соц. сети. В нем есть класс Wall (для работы со стеной пользователя) и класс Post (содержит данные поста, их геттеры/сеттеры и другие методы).

Класс Wall:
class Wall
{
    public function addPost($text) 
    {
        ... // какие-то действия
        return new Post($id, $text);
    }

    public function getLastPost()
    {
        ... // какие-то действия в результате которых мы можем:
        return new Post($last['id'], $last['text']);
    }

    // предположим, метод, который делает репост или другие действия, не суть
    public function repost(Post $post) 
    {
        ... $post->getId() ...
        ... $post->toString() ...
        .... // ещё какие-то действия с объектом 
    }


Класс Post:
class Post
{
    ... // переменные/поля
    ... // геттеры/сеттеры
    ... // toString и другие связанные методы
}


При этом видно, что класс Wall очень тесно связан с классом Post (особенно там, где создаются новые экземпляры в классе Wall) и это не соответствует SOLID и в частности принципу инверсии зависимостей.

Как ослабить связь между классами и сделать их более переносимыми и SOLIDными? И нужно ли это делать в такой ситуации? У меня в принципе есть идеи, но, уверен, есть какой-то изящный паттерн, который решит все мои проблемы и о котором я пока не знаю.
  • Вопрос задан
  • 986 просмотров
Решения вопроса 2
SerafimArts
@SerafimArts
Senior Notepad Reader
Указывать не объект, а его интерфейс. В данном случае там три метода - getId, toString и __construct. Этого будет достаточно для начала.

P.S.
По-хорошему ещё надо избавляться от id, т.к. это поле относится к реализации, а не к логике. Все полученные посты из какого-либо стораджа будут его иметь, а новосозданным постам знать о его существовании не обязательно. Т.е. примерно так должно получиться:
interface Post
{
    public function __construct(string $content, User $user);
    public function getContent() : string;
    public function getUser() : User;
    public function changeAuthor(User $user);
}

class WallPost implements Post
{
    ... implement methods
}


В таком случае у любых постов будет лишь автор и содержание, а остальное уже тонкости реализации, т.к. id нужен лишь для БД, что бы связать юзера с постом.

Но это всё уже немного другая история (см. предметно-ориентированное программирование).

P.P.S. На счёт сеттеров я бы поспорил. Предлагаю посмотреть вот эту https://habrahabr.ru/post/279919/#comment_8816651 ветку комментариев, где Сергей мне доступно объяснил по поводу их нужности и я вынужден с этим согласиться, ибо иммутабельность данных - это хорошо.
Ответ написан
riky
@riky
Laravel
помоему вы не туда ушли.
идеал - не то что два класса никак не связаны. классы всегда будут связаны.
то что вы сущности post создаете в сервисе это норма. все равно при расширении вы будете просто добавлять туда новые свойства и геттеры/сеттеры. вы же не будете расширять post наследованием?

либо создайте отдельный сервис фабрику для постов и создавайте в ней. PostFactory::createPost()
а в Wall классе считайте что работаете с обьектом наследующим PostInterface.
только в таком случае вы по нормальному используете только те геттеры/сеттеры которые указаны в PostInterface.

в общем вопрос только зачем вам хочется абстрагироваться от Post ?
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽