@wollk

Как правильно спроектировать приложение?

Здравствуйте, пришел в тупик, перепробовал разные варианты, но как-то чувствую что они не правильные.
Возьмем например простой сайт, с публикацией новостей, созданием страниц, регистрацией.
Пусть будут классы Engine, Page, News, User, DB.

Сначала я эти классы создавал поочередно все
$db = new DB(/*какие-то параметры*/);
....
$page = new  Page(/*какие-то параметры*/);

При этом, взаимодействие с классом DB в других классах происходило путем global $db, но я наслышан, что использовать global - не есть хорошо. По этому в конструктор класса стал передавать $db.
Классы типа Page, News, User сделаны по такому принципу: методы для выбора, удаления, добавления, получение каких-то констант. В общем все что касается конкретно новостей, должно быть в News, страниц - в Page. Потом чтоб сгруппировать как-то это все, засунул эти $page = new Page(...) в Engine (сделал агрегацию): $this->page=new Page(...); (кроме User, он наравне с Engine). Добавление статьи пользователем происходит по такой цепочке $user->add_news(...), в add_news проверяются права пользователя и вызывается $engine->news->add(...)
Но в Engine есть, например, метод добавления ошибки в лог, соответственно из класса Page я уже не смогу вызвать этот метод, разве что сделать его статическим и вызывать так Engine::log()

В общем я очень запутался, верните меня на путь истины ). Уж очень сильно отличаются некоторые моменты ООП в построении сайтов и разработке программ на том же C++. Как же все таки правильно организовать структуру, чтоб потом было легко добавлять функционал/удалять? Пытался покопаться в WordPress но там много всего, не разобрался.
  • Вопрос задан
  • 3487 просмотров
Пригласить эксперта
Ответы на вопрос 3
Почитайте про паттерны. Мне очень помогла книга "Чистый код" (www.ozon.ru/context/detail/id/21916535/).

Не усложняйте свою программу, если это можно сделать проще - сделайте.
Не пишите лишнего. Если это сейчас не требуется, то и не стоит писать.
В Вашем случае я вижу такую структуру:
Есть класс пула соединений (напр. ConnectionPool). На входе принимает строку - название хранилища, на выходе отдает содединение с базой.

Разбиваем программу на сущности: User, News, Page.
У каждой сущности есть свое хранилище: UserStorage, NewsStorage, PageStorage. Хранилище занимается только тем, что управляет сущностью в БД: save, load, delete, etc.
При создании, хранилище прнимает соединение с БД и сохраняет его "в себе".
Код при этом получается примерно такой:
$Connection = ConnectionPool::getConnection('users');
$UsersStorage = new UserStorage($Connection);

$User = $UsersStorage->loadById(1);
$User->set('name', 'Yakob');
$User->get('name');
$UserStorage->save($User);
$UserStorage->delete($User);


Аналогично другими сущностями.
Сразу же прослеживается связь между сущностями и хранилящами между собой. Выделяем абстракцию, например AbstractStorage. Выносим в нее общие части хранилищ.
Приведенный код создания хранилища можно скрыть, например за фасадом примерно так:
class UserFacade {
    protected static $UserStorage = null;

    public static function getById($id) {
        return self::getUserStorage()->getById($id);
    }

    public static function save(User $User) {
        return self::getUserStorage()->save($User);
    }

    protected static function getUserStorage() {
        if (is_null(self::$UserStorage)) {
            $Connection =  ConnectionPool::getConnection('users');
            self::$UserStorage = new UserStorage($Connection);
        }

        return self::$UserStorage;
    }
}


Все остальное - разные укровни бизнес логики. Нужно получить новости юзера? Создаем класс например UsersNewsStorage, который наследуется от NewsStorage. Есть метод getFeed
Код примерно такой получается:
....
$User = $UserStorage->getById(1);
$UsersNewsStorage = new UsersNewsStorage($Connection);
$Feeds = $UsersNewsStorage->getFeed($User);


Нужна валидация новостей? Хранилище (NewsStorage) мы не трогаем, оно занимается только тем, чем занимается. Остальное бизнес логика.
Добавляем валидацию в UsersNewsStorage.
$User = $UsersStorage->loadById(1);
$News = new News(['title'=>'AAA', 'body'=>'bbbbbb']);
$UsersNewsStorage = new UsersNewsStorage($Connection);
try {
  $UsersNewsStorage->saveNews($User, $News); // Внутри валидация
} catch (ValidationNewsErrorException $Ex) {
  // Валидация не прошла
}


Таким образом мы выносим ответственность и бизнес-логику из основных классов, определяем зависимости в коде. В любой момент мы сможем заменить один кусочек не нарушив работу всего остального кода.
Если что-то не понятно, задавайте вопросы. Тема очень большая и требует вопросов.
Ответ написан
DmitriyEntelis
@DmitriyEntelis
Думаю за деньги
1) https://ru.wikipedia.org/wiki/Model-View-Controller
2) Мне кажется Вам будет полезней посмотреть какой нибудь нормальный фреймворк типа Yii2.
WordPress это просто классический образчик говнокода.
Ответ написан
Комментировать
mzcoding
@mzcoding
Web-Разработка
Как уже раньше порекомендовали, вам необходимо понять и применять шаблоны проектирования. Пару книг для ознакомления, которые точно помогут www.ozon.ru/context/detail/id/5648968 и www.ozon.ru/context/detail/id/2457392/.

Также установите и поюзайте какой-нибудь фреймворк Yii или Laravel например.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы