Как правильно реализовать архитектуру для связанных объектов с сервисом, коллекцией и репозиторием?

Добрый день.
Есть таблица в бд, в ней хранится сущность: Post.
Сама по себе эта сущность не используется, в зависимости от некоторых строк в таблице, создается дочерняя сущность News, Article и.т.д, у которых есть одинаковые методы, но могут быть дополнительные разные методы.
Хотелось бы реализовать все это с репозиториями и интерфейсами, чтобы можно было менять при необходимости

Набросал пример, чтобы было хоть немного понятно, чего я хочу:
interface PostContract
{
    public function getId();
    public function getTitle();
}

interface NewsContract extends PostContract
{
    public function getCountry();
}

interface ArticleContract extends PostContract
{
    public function getTags();
}

abstract class Post implements PostContract
{
    public function getId()
    {
    }

    public function getTitle()
    {
    }
}

class News extends Post implements NewsContract
{
    public function getCountry()
    {
    }
}

class Article extends Post implements ArticleContract
{
    public function getTags()
    {
    }
}

interface NewsCollectionContract
{
    public function push(NewsContract $item);
}

interface ArticleCollectionContract
{
    public function push(ArticleContract $item);
}

class NewsCollection implements NewsCollectionContract
{
    public function push(PostContract $item)
    {
    }
}

class ArticleCollection implements ArticleCollectionContract
{
    public function push(ArticleContract $item)
    {
    }
}


interface PostRepositryContract
{
    public function getList();
}

interface NewsRepositryContract extends  PostRepositryContract
{
    public function getList() : NewsCollectionContract;
    public function get($id) : NewsContract;
}

interface ArticleRepositryContract extends  PostRepositryContract
{
    public function getList() : ArticleCollectionContract;
    public function get($id) : ArticleContract;
}

abstract class PostRepositry
{
    // Общие методы
}

class NewsRepository extends PostRepository implements NewsRepositryContract
{
    public function getList() : NewsCollectionContract
    {
        return new NewsCollection;
    }
    public function get($id) : NewsContract
    {
        return new News;
    }
}

class ArticleRepositry extends PostRepository implements PostRepositryContract
{
    public function getList() : ArticleCollectionContract
    {
        new ArticleCollection;
    }

    public function get($id) : ArticleContract
    {
        new Article;
    }
}

interface NewsServiceContract
{
    public function getList(array $params) : NewsCollectionContract;
}

interface ArticleServiceContract
{
    public function getList(array $params) : ArticleCollectionContract;
}

class NewsService implements NewsServiceContract
{
    private $repo;

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

    public function getList(array $params) : NewsCollectionContract
    {
        return $this->repo->getList();
    }
}

class ArticleService implements ArticleServiceContract
{
    private $repo;

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

    public function getList(array $params) : ArticleCollectionContract
    {
        return $this->repo->getList();
    }
}


Как все это реализовать правильно?
  • Вопрос задан
  • 274 просмотра
Решения вопроса 1
DeFacto
@DeFacto
глубоко ушел в абстракции.

1. Кто и для чего будет использовать методы getTags(), getCountry() ?

по логике допустим, у тебя интерфейс ArticleContract добавляет функции getTags()
лучше тогда создать интерфейс TagsContract
так как потом требования могут изменится, и тэги нужны будут для News

2. Зачем на каждый чих делать интерфейсы? Для Service я вообще не вижу смысла. Или ты собираешься подменять где-то ArticleService другим ArticelService который должен так же возвращать ArticleCollectionContract?

3. самый простой вариант для начала
оставляем interface PostContract
по-необходимости для функционала делаем interface TagContract
оставляем PostRepostory, PostService
PostRepostory расширяем чтобы он мог возвращать объекты по типу (например
$postRepostory->getNews(), $postRepostory->getArticles() )
В тех местах где тебе реально нужен доп функционал типа getCountry - создаешь отдельный интерфейс interface CountryContact
и далее в тех местах где будет зависимость встраиваешь CountryContact
в итоге class News extends Post implements CountryContact, TagContract
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

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