@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
DmitriyEntelis
@DmitriyEntelis
Думаю за деньги
1) https://ru.wikipedia.org/wiki/Model-View-Controller
2) Мне кажется Вам будет полезней посмотреть какой нибудь нормальный фреймворк типа Yii2.
WordPress это просто классический образчик говнокода.
Ответ написан
Комментировать
Почитайте про паттерны. Мне очень помогла книга "Чистый код" (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) {
  // Валидация не прошла
}


Таким образом мы выносим ответственность и бизнес-логику из основных классов, определяем зависимости в коде. В любой момент мы сможем заменить один кусочек не нарушив работу всего остального кода.
Если что-то не понятно, задавайте вопросы. Тема очень большая и требует вопросов.
Ответ написан
mzcoding
@mzcoding
Web-Разработка
Как уже раньше порекомендовали, вам необходимо понять и применять шаблоны проектирования. Пару книг для ознакомления, которые точно помогут www.ozon.ru/context/detail/id/5648968 и www.ozon.ru/context/detail/id/2457392/.

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

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

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