Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Какой подход использовать? 
:(
    Опции темы
BuShaRt
Дата 20.9.2013, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1391
Регистрация: 29.6.2006

Репутация: 4
Всего: 6



На работе пробуем начать программировать на правильном ООП (использовать SOLID и т.п.). Возникают вопросы. Вот один из них.

У нас есть класс User (мы называем такие классы Entity - он описывает все элементарные свойства объекта + имеет набор сеттеров и геттеров + какие-то методы, производяшие подсчеты, на которые влияют только данные уже имеющиеся в объекте). Вообще мы используем Doctrine 2, если кто работал с ней, тем будет сразу ясно о чем речь.

Примерно так
User
- id
- name
+ getId
+ setName
+ getName
+ getStamp { retuen name + id }

А теперь у нас есть задача, получить набор статусов этого пользователя, но для подсчетов используется сложная логика, затрагивающая несолько таблиц в БД и соотвественно несолько объектов (для нагялдности представим, что эта логика состоит из лапши из циклов и SQL-запросов).  Если мы поместим эту логику в наш класс User, то мы автоматически нарушим принцип SOLID, как минимум тем, что этот объект сам по себе не может обращаться к базе, что говорить о том, что он станет в курсе того какие еще объекты есть в системе.

Конечно в голову приходят варианты решения задачи, на пример следующие:
- Сделать отдельные объекты - процессоры, которые будет на входе получать объект user,  а на выходе отдавать значение одного из статусов.
- Сделать объект SuperUser, который принимает на входе объект User и при инициализации производит все необходимые подсчеты (хотя, мне кажется тут тоже нарушается принцип SOLID)
- Еще такая идея пришла, пока писал пост. Каким нибудь образом добавить необходимые статусы в класс User, но поместить в них не значения, а объекты типа процессоров описанных в первом пункте (наверно в данном контексте это будет похоже на паттерн прокси).

Вот... Расскажите, как вы поступаете в таких ситуациях?
PM MAIL   Вверх
baldina
Дата 20.9.2013, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



Цитата(BuShaRt @  20.9.2013,  11:35 Найти цитируемый пост)
логика, затрагивающая несолько таблиц

на это можно взглянуть иначе: мы имеем не запрос, а функцию, возвращающую значение. не вникая в подробности реализации можно её просто использовать.

Нужно ответить на вопрос: чем является информация (в БД), на основе которой считаются статусы, по отношению к пользователю. Тогда станет понятно
а) это свойство пользователя или операция над ним
б) как лучше абстрагировать слой БД, что бы User или функция расчета оперировали терминами задачи, а не таблицами

ЗЫ. Отвлеченный вопрос. Предполагается, что юзер может быть переименован (я про setName)?

Добавлено через 1 минуту и 36 секунд
Цитата(BuShaRt @  20.9.2013,  11:35 Найти цитируемый пост)
в голову приходят варианты решения задачи

Прежде поиска технических решений надо с концепцией определиться
PM MAIL   Вверх
BuShaRt
Дата 20.9.2013, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1391
Регистрация: 29.6.2006

Репутация: 4
Всего: 6



Цитата

Нужно ответить на вопрос: чем является информация (в БД), на основе которой считаются статусы, по отношению к пользователю. Тогда станет понятно
а) это свойство пользователя или операция над ним
б) как лучше абстрагировать слой БД, что бы User или функция расчета оперировали терминами задачи, а не таблицами


А можно я приведу более подробное описание, а вы ответите сами на эти вопросы? Просто я не уверен, что точно их понял, а на вашем примере мне будет проще сооринтироваться.
Имеем следующие статусы
1. Стутус частоты заказов. 
1.1 = 2, если пользователь за последние 14 дней заказывал не менее двух товаров в день как минимум 10 раз (дней)
1.2 = 1, если пользователь за последние 14 дней заказывал не менее одного товара в день как минимум 5 раз (дней)
1.3 = 0 во всех други случаях
2. Статус прогресса заказов
1.1 = 2, если пользователь за последние 5 дней заказал больше, чем за предыдушие 5 дней
1.2 = 1, если пользователь за последние 5 дней заказал товара меньше, чем за предыдушие 5 дней, но не более чем на 20% (меньше)
1.3 = 0  во всех других случаях

Цитата

ЗЫ. Отвлеченный вопрос. Предполагается, что юзер может быть переименован (я про setName)? 

Это просто пример. Реально у нас есть поле identity, которое нельзя менять, а name менять можно т.к. он информационное.

Это сообщение отредактировал(а) BuShaRt - 20.9.2013, 12:19
PM MAIL   Вверх
georgiy11
Дата 20.9.2013, 12:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 29.9.2008

Репутация: нет
Всего: нет



Здесь не проблема в чистом или не чистом ООП. Проблема в том как модель User будет себя позиционировать в системе: включать бизнес логику (AR) и это как раз определение выше сказанных условий или будет обычным шлюзом к таблице в БД.
Обычно, если бизнес логика не велика (то есть при добавлении модель не будет раздута до небес), это вмещается и в AR, например я бы сделал так (это очень удобно)
1. Стутус частоты заказов. 
1.1 = 2, если пользователь за последние 14 дней заказывал не менее двух товаров в день как минимум 10 раз (дней) $user->isOrderedLeastTwoItems($period = 14, $countOrders = 10);
1.2 = 1, если пользователь за последние 14 дней заказывал не менее одного товара в день как минимум 5 раз (дней) $user->isOrderedLeastOneItems($period = 14, $countOrders = 5);
1.3 = 0 во всех други случаях

Что дают такие методы: избавляемся от статусов и инкапсулируем бизнес логику в методах (бизнес логика имеет структуру но настраиваема, хотя лучше конечно полностью инкапсулировать)
Тфжёлое в этом подобрать имена методам smile
PM MAIL   Вверх
BuShaRt
Дата 20.9.2013, 14:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1391
Регистрация: 29.6.2006

Репутация: 4
Всего: 6



georgiy11, Я Вас чуть-чуть обманул. Я только сейчас узнал, что в Doctrine 1 использовался AR-паттерн, а в Doctrine 2 используется Data Mapper. Я написал, что мы работаем с Doctrine, но не уточнил с какой именно, видимо этим введя вас в заблуждение. Так вот мы работаем с Doctrine 2 и наши объекты не являються не AR, не шлюзами - они являются просто объектами, без бизнес логики, манипалирование которыми берет на себя Data Mapper. Но Data Mapper умеет манипулировать только элементарными данными этих объектов + явно выраженными связями. Т.е. он может заполнить объекты проксями к другим объектам или самими данным, но вот производить вычисление на базе данных он не умеет, да и не должен уметь судя по тому, как я понял его концепцию. 

Это сообщение отредактировал(а) BuShaRt - 20.9.2013, 14:05
PM MAIL   Вверх
georgiy11
Дата 20.9.2013, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 29.9.2008

Репутация: нет
Всего: нет



Тогда это прослойка из стратегий, хорошо вписывается в архитектуру. Стратегии могут и должны содержать бизнес логику, и могут оперировать множеством сущностей.
То есть, фактически, стратегия будет инкапсулировать какой то объём бизнес логики с различными мапперами и их связями. 
Ещё более чистый ООП, подразумеваем инкапсулирование мапперов в сущностях Entites и соответственно связи производится будут между entity<->entity, в которых инкапсулированы данные от мапперов. Но мне кажется это слишком не нужный подход. Решение стратегий довольно гибкое для средних проектов (имею ввиду с более менее сложной бизнес логикой). Где отлично работает архитектура с сущностями и в них маппер, так это высоконагруженная бизнес-логика например игра браузерная. 
Это лично моё мнение smile

PM MAIL   Вверх
baldina
Дата 20.9.2013, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



BuShaRt, значит имеем три связанные сущности - пользователь (User), его заказы (Orders) и его статусы (Status).
Класс Orders умеет получать информацию о заказах конкретного пользователя (посредством обращения к хранилищу - БД)
Класс Status умеет рассчитывать значение статуса на основании определенной статистики (заказов)
Класс User пользуется и тем и другим, связывая их и предоставляя интерфейс доступа к значению статусов.

Итого примерно такая схемка (вместо классов с одной функцией для краткости использую функции):

Код

// вернуть число заказов пользователя $user_id за последние $ndays дней, содержащих не менее $nproducts продуктов
// (или без учета продуктов, если $nproducts=null
function get_num_orders ($user_id, $ndays, $nproducts=null); 
function get_freq_status  (array $norders_by_nproducts); 
function get_prgr_status  ($ratio); 

class User {
  ...
  function getFreqStatus () {
    $no1 = get_num_orders ($this->id, 14, 2);
    $no2 = get_num_orders ($this->id, 14, 1);
    return get_freq_status (['2'=>$no1, '1'=>$no2]);
  }

  function getPrgrStatus () {
    $no1 = get_num_orders ($this->id, 5);
    $no2 = get_num_orders ($this->id, 10);
    return get_prgr_status ($no1 / ($no2-$no1));
  }
}



где функции статуса могут быть например такие

Код

function get_freq_status (array $odata) {
  $rules = ['2' => [2=>10], '1'=>[1=>5]];
  foreach ($odata as $nprods=>$norders)
    foreach ($rules as $status => list ($np,$no))
       if ($nprods >= $np && $norders >= $no)
          return $status;
  return 0;
}

function get_prgr_status ($ratio) {
  $rules = ["2" => 1, "1"=> 0.8];
  foreach ($rules as $status => $r)
     if ($ratio >= $r)
        return $status;
  return 0;
}


Добавлено через 7 минут и 35 секунд
Цитата(georgiy11 @  20.9.2013,  14:29 Найти цитируемый пост)
Ещё более чистый ООП, подразумеваем инкапсулирование мапперов в сущностях Entites и соответственно связи производится будут между entity<->entity, в которых инкапсулированы данные от мапперов.

ужос))))


Это сообщение отредактировал(а) baldina - 20.9.2013, 17:13
PM MAIL   Вверх
georgiy11
Дата 21.9.2013, 10:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 29.9.2008

Репутация: нет
Всего: нет



Цитата

Цитата(georgiy11 @  20.9.2013,  14:29 Найти цитируемый пост)
Ещё более чистый ООП, подразумеваем инкапсулирование мапперов в сущностях Entites и соответственно связи производится будут между entity<->entity, в которых инкапсулированы данные от мапперов.

ужос))))


http://design-pattern.ru/patterns/data-mapper.html
В чём то есть правильность подхода.

Кстати, а можно ли наследовать маппер и делать дочерний класс AR.
PM MAIL   Вверх
baldina
Дата 21.9.2013, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



Цитата(georgiy11 @  21.9.2013,  10:28 Найти цитируемый пост)
В чём то есть правильность подхода.

как техническое решение - да, есть такое. есть и множество других. только ООП тут непричем
ООП это подход, его то и не хватает, а вы углубляетесь в частности не определив общее решение.

Добавлено через 10 минут и 39 секунд
BuShaRt, у вас уже были хорошие решения - 1 и 3 из первого поста. Какое выбрать зависит от вкусовых пристрастий и необходимости дальнейшего расширения проекта. 1й простой и расширяемый, но требует часть концепции в голове держать. 3й это модный DI (при злоупотреблении вносящий больше путаницы чем пользы). Идите по пути ослабления связей между классами, это всегда оставляет возможность для изменений без переписывания всего.
PM MAIL   Вверх
georgiy11
Дата 22.9.2013, 01:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 29.9.2008

Репутация: нет
Всего: нет



[B]baldina[/B
Цитата

как техническое решение - да, есть такое. есть и множество других. только ООП тут непричем, 


 smile  по секрету, тихо, ООП и есть техническое решение
Есть решение принять функциональный подход к задаче
Есть решение ООП подход,
Есть решение совмешённый ООАП, ООП, функциональный, процедурный ....

Цитата

только ООП тут непричем

Сори, датамапер ни к какой парадигме не подойдёт как к ООП, если ВЫ конечно не оспорите smile

Цитата

Какое выбрать зависит от вкусовых пристрастий


Вкусовые пристрастия .... ну ну .... smile если будем ориентироваться на вкусы что же будем получать в результате?

Это сообщение отредактировал(а) georgiy11 - 22.9.2013, 01:23
PM MAIL   Вверх
baldina
Дата 22.9.2013, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



Цитата(georgiy11 @  22.9.2013,  01:10 Найти цитируемый пост)
по секрету, тихо, ООП и есть техническое решение

вы заблуждаетесь. точнее, если вы так смотрите на ООП, то многое теряете, практически ничего не приобретая. ООП - парадигма, подход, методология.

Цитата(georgiy11 @  22.9.2013,  01:10 Найти цитируемый пост)
если будем ориентироваться на вкусы что же будем получать в результате?

писать так
Код

if (cond) {
}
или так
Код

if (cond)
{
}
дело вкуса
или вам известен Единственно Верный Путь?
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0565 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.