ОО подход к тривиальной проблеме

fisher

накатила суть
тут есть 2 но: это php-опп, и это рсубд-ооп.

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

связка ооп и рсубд вообще вещь занятная, но копий тут сломано уже столько, что мама не горюй. я пользуюсь некоторыми классами, инкапсулирующими понятия cущность, связь 1:M, связь M:M, в этом случае реальные объекты типа продукт, документ, чтоугодно и связи между ними "собираются" из экземпляров базовых классов. НО всё это упрощает жизнь только в ряде несложных случаев, когда в проекте нет сугубо рсубд-фич, связанных с оптимизацией запросов, переноса всей бизнес-логики на пакеты и процедуры, всевозможных денормализующих извращений. как только доходит до этого дело - часто оказывается проще писать готовые решения для данного конкретного случая.
 

camka

не самка
я пользуюсь некоторыми классами, инкапсулирующими понятия cущность, связь 1:M, связь M:M,
Можно поподробнее пожалуйста если не трудно будте так добры маааааааааленький примерчик для конкретного случая. Как можно представить сущность классом и что у него внутри буит?

Очень кстати говоря актуальненько

Сэнкъю вэри мач
 

csa

Guest
Автор оригинала: fisher
связка ооп и рсубд вообще вещь занятная, но копий тут сломано уже столько, что мама не горюй.
на вскидку не скажешь, где на эти копья поглядеть можно?
 

fisher

накатила суть
Автор оригинала: csa
на вскидку не скажешь, где на эти копья поглядеть можно?
вообще яркий пример брожения мозгов - само наличие на рынке рсубд,ор(объектнро-реляц)субд и оо(объектно-ориент)субд.
на вскидку я не могу вспомнить какого-либо нормального обзора - над этим бьются скорее теоретики от computer science. из русскоязычных людей, кто этой темой занимается достаточно глубоко - Вендров, Кузнецов (имхо, по крайней мере, они активно публикуются и их статьи легко найти в интернете). почитайте их статьи на citforum'e.
ну вот кратенько тут, например http://www.citforum.ru/seminars/cbd99/inteltec_2.shtml

2camka:
код не дам, сыроват и заточен под оракл к тому же. единомышленников, которые хотели бы подход развить до нормального проекта - пока не нашлось. у кого есть понимание проблемы - вкалывают и у них катастрофически нет времени ;)
для отдельной сущности всё просто, какие-то поделки я даже видел в phpclasses (мне не понравились)
имя таблицы, имя первичного ключа, хэш имен-типов полей, хэш имен-значений полей (для конкретного primary key).
ну и методы типа, select, unsert, update, delete.
а для конкретного объекта структура таблицы - как параметр коструктора класса. ничего принципиального, в-общем.
 

camka

не самка
Автор оригинала: fisher
2camka:
код не дам, сыроват и заточен под оракл к тому же.

имя таблицы, имя первичного ключа, хэш имен-типов полей, хэш имен-значений полей (для конкретного primary key).
ну и методы типа, select, unsert, update, delete.
а для конкретного объекта структура таблицы - как параметр коструктора класса. ничего принципиального, в-общем.
Я имел ввиду как можно было бы реализовать данный подход в нашем примере. То есть включить класс 1:М для продукт-вендор связи. Интересно на что он будет похож.
 

fisher

накатила суть
2camka
entity всё равно понадобится. а базовая связь будет что-то вроде relation_1M:
master(entity, например VENDOR), slave(entity,например PRODUCT) - физически копии или ссылки на ранее созданные объекты entity, здесь важны лишь структура таблиц, имена ключей, и значение первичного ключа у master.
и ещё имя поля у slave которое foreign key на master (vendor_id). методы - ну какие потребуются, минимальный набор - count_slaves, get_slaves.
можно извращаться типа move_slaves_to_another_master(another_master_id) ну и так далее.
твой продукт-вендор extends relation_1M
 

vitus

мимо проходил
мне кажется ребята, что вы несколько преувеличиваете существо проблемы :) если у вендора всего два аттрибута, то его вполне можно достать всего в процессе доставания продукта, и держать внутри продукта как объект.

кроме того странно выглядит предложение делать вендора и продукт (классы) наследниками класса БД, чтобы у каждого был свой Connect() ...

и зачем подменять вполне нормальный способ обращения к базе данных (SQL) своими методами и классами - никчему это.

ООП придумали чтоб облегчить жизнь программиста, а не для того чтобы она (жизнь) превратилась в сущий кошмар, используйте его для описания словаря предметной области и не парьтесь :)
 

camka

не самка
Автор оригинала: vitus
ООП придумали чтоб облегчить жизнь программиста, а не для того чтобы она (жизнь) превратилась в сущий кошмар, используйте его для описания словаря предметной области и не парьтесь :)
вот потому то и спрашиваю. Есть ли какое стандартное решение проблемы. Видимо нету. А насчет вендоров дак там атрибутов и десяток может быть.
 

vitus

мимо проходил
Автор оригинала: camka
вот потому то и спрашиваю. Есть ли какое стандартное решение проблемы. Видимо нету. А насчет вендоров дак там атрибутов и десяток может быть.
стандартных решений у проблемы не бывает, - тогда она сразу не проблема :)
пусть у вендоров будет мильён аттрибутов, тебе ведь нужен только Name (или я не так понял?).

а в принципе для вывода списка продуктов с именами вендоров наверное лучше либо класс - ProductList сделать , либо функцию, либо прямо в list.php - цикл с проходом по рекордсету (курсору) и инклюдить его где надо, - вариантов много, ответ зависит от того насколько это кусок кода будет востребован потом (на других страницах, в других объёктах)
и насколько часто могут меняться требования к этому куску кода ...

да и приведённый в начале код - тоже не плохое решение, если не тормозит :)
 

csa

Guest
2camka:
а чем тебе мой подход не нравится? делаешь всего один sql-запрос и его результатами инициализируешь объекты
думаю, для твоего исходного примера этого будет достаточно
 

camka

не самка
Автор оригинала: csa
2camka:
а чем тебе мой подход не нравится? делаешь всего один sql-запрос и его результатами инициализируешь объекты
думаю, для твоего исходного примера этого будет достаточно
Да. Честно говоря я для себя как раз этот вариант и выделил. Довольно интересная реализация с кэшем. Спасиба.

Вот еще такой вопрос:

Я обычно создаю классы для основных таблиц БД. И у всех у них есть методы
Init - вылавливаем все атрибуты по АйДи
Add- Добавляем в БД предварительно проверив передаваемые атрибуты на правильность методами Checkxxx где ххх это передаваемые в Add параметры. То есть для каждого параметра своя процедура проверки.
Update - Изменить по тому же АйДи. Перед апдейтом также выполняется проверка. В случае если какое то поле не прошло проверку добавляется ошибка в класс ошибок, который так же является атрибутом каждого из мною создаваемых классов. В случае обнаружения ошибки добавление либо изменение данных не производится.

Ну вот в общем то вопрос в том что как то не особо здорово писать эти методы для каждого класса причем все они похожи но наследование как то не удается так как есть некоторые различия и специфические особенности. Хочется наследовать их откуда то свыше. Но почему то неудается.

Мож кто пользует некую автоматизацию процесса? Ну типа визарда который сам пишет класс для тебя. Или мож кто какое заклинание знает?
 

kvn

programmer
ИМХО: удобнее использовать класс, который тебе будет создавать(factory?) все эти обьекты Product & Vendor, причем в Product будет _ссылка_ на class Vendor, и наоборот, в Vendor ->prop = class Product.
Вполне себе нормальная структура. Метод, который это для тебя будет делать вполне может быть статическим.
+использовать какой-нить итератор для обхода этой структуры.

тогда сделав что-то типа:
PHP:
while ($product = $iterator->nextProduct()){
  echo $product->getName();
  $vendor = $product->getVendor();
  echo $vendor->getName();
}
типа того.
имхо.
 

kvn

programmer
Мож кто пользует некую автоматизацию процесса? Ну типа визарда который сам пишет класс для тебя. Или мож кто какое заклинание знает?
я юзаю 'dia' - для рисования UML-диаграмм,
к ней есть приблуда dia2code - умеет создавать заготовки классов из UML диаграмм.

Это конечно не RationalRose, но - на любителя.
 

csa

Guest
Автор оригинала: camka
Да. Честно говоря я для себя как раз этот вариант и выделил. Довольно интересная реализация с кэшем. Спасиба.
да я не про кэш :)
мне интересна критика первых 2-х постов

Вот еще такой вопрос:

Я обычно создаю классы для основных таблиц БД. И у всех у них есть методы
Init - вылавливаем все атрибуты по АйДи
Add- Добавляем в БД предварительно проверив передаваемые атрибуты на правильность методами Checkxxx где ххх это передаваемые в Add параметры. То есть для каждого параметра своя процедура проверки.
ну как check-методы ввести в такую иерархию, наверное, и так понятно
[...]
Ну вот в общем то вопрос в том что как то не особо здорово писать эти методы для каждого класса причем все они похожи но наследование как то не удается так как есть некоторые различия и специфические особенности. Хочется наследовать их откуда то свыше. Но почему то неудается.
я использую такую идею (не свою):
- вводим в объект массив valid_fields с полями, которые можно использовать в запросе
- вводим 3 метода:
get_keys(array) - вернет строку с ключами массива через запятую (используем в INSERT)
get_values(array) - вернет строку со значениями в кавычках через запятую (там же)
get_key_value_pairs(array) - вернет сроку вида "key1='value1', key2='value2' " (используем в апдейт)
каждый из этих методов формирует строку из полей массива, переданного аргументом, но только для тех полей, ключи которых есть в valid_fields

реализуем в соответствии с этой схемой методы для вставки и обновления и наследуем

можно пойти дальше и ввести метод get_work_vars (все из той же идеи :)) и в нем проверять переданные аргументы и на корректность значений, и на допустимость, собственно, каждой переменной (см про valid_fields)
 

csa

Guest
перечитал еще раз начало треда - у меня та же (наверное) идея про инициализацию объектов, что и у тони :)
 

zhuk

Guest
По поводу инициализации классов: я тоже использую 2 вышеперечисленных метода. И тот или иной метод используется в зависимости от производительности. То есть если операция некритична по времени - либо 1 объект либо небольшое кол-во, свойства вытаскиваются внутри объекта.

Если же вытаскивается список товаров - то использую внешнюю инициализацию. Потому что как правило запрос сложный - с INNER JOIN'ами и прочим. То есть выигрыш в производительности по сравнению если все данные будут добываться непосредственно объектами неслабый - не один раз проверено на практике.

Вот пример как это у меня реализовано

(http://www.fotoclub.ru/labs/)

class lab extends basic {

var
$id,
$name,
$city,
$address,
$phone,
$email,
$web,
$comments,
$downtime,
$addservice;

function lab($arr) {

basic :: basic();

$this -> id = $arr["lab_id"];
$this -> name = $arr["lab_name"];

...

$this -> link = new link("labs_showlab_page", array("lab_id" => $this -> id), $this -> name);
$this -> add_comment_link = new link("labs_add_lab_opinion", array("lab_id" => $this -> id), "дПВБЧЙФШ ПФЪЩЧ »");

}
}


class lab_from_id extends lab {

function lab_from_id($lab_id) {

basic :: basic();

$this -> sql -> set_query("select ....");

$this -> sql -> query();
list($labarr) = $this -> sql -> to_array();

lab :: lab($labarr);

}

}
 

vitus

мимо проходил
Автор оригинала: zhuk
Вот пример как это у меня реализовано
class basic extends ??? {
}

class lab extends basic {
...}

class lab_from_id extends lab {
...}
либо мне ничего непонятно по причине общей моей ограниченности, либо что-то тут мне не нравится :) - приведи интерфейсы упомянутых классов пожалуйста.
 

vitus

мимо проходил
в общем если НЕОБХОДИМО использование ооп для решения данной задачи то можно предложить следующий вариант:

PHP:
class ProductList extends DataFace{

var $connect; //экземпляр класса, обеспечивающего связь с бд
var $cursor; //курсор со списком

//не инициализировать в конструкторах
var $product = new Product(); 
var $vendor  = new Vendor(); 

function ProductList($connect, $where_clause)// конструктор
{
   $this->connect = $connect;
   $this->cursor = $this->connect->OpenQuery(
      "select * from product, vendor where $where_clause") ;
// ну или чтонибудь более красивое, 
// в зависимости от требований к отборам и от самой бд ...
}

function Next()
{
   if($row=$this->cursor->Fetch())
//  cursor->Fetch() возврашает ассоциативный 
//массив полей запроса
     {
// можно расписать по полям, 
// но наверное лучше не здесь а в самих вендорах и продуктах
      $this->vendor->set($row);
      $this->product->set($row);
      return 1;
     }
   return 0;
}

function ShowAll()
{
    while($this->Next())
      {
         $result .= "<всякий хтмл или вызов определённых методов для формирования вывода>";
      }
   return $result;
}

}
теперь интерфейсы упомянутых классов :) :
PHP:
// приведены только используемые в примере методы и поля
// для пущего понимания методы и поля типизированы как в 
// Java
class Cursor{
   public String[] Fetch(); // не совсем как в жабе, но это ведь для пхп : )
}
class Connect{
   public void Connect(String $connstring, Object[] $otherParametersNeeded);
   public Cursor OpenQuery(String $sqlString);
}
class Vendor extends DataFace{
public void set(String[] $fields);
// реализовать можно как у zhuk 
}
class Product extends DataFace{
public void set(String[] $fields);
// реализовать можно как у zhuk 
}

class DataFace{
 // этот класс реализует всевозможную функциональность . необходимую всем классам, являющимся интерфейсами к объектам в бд
}
как видите - вовсе не обязательно быть наследником класса. чтобы воспользоваться его методами :)
 

camka

не самка
Автор оригинала: vitus

PHP:
//не инициализировать в конструкторах
var $product = new Product(); 
var $vendor  = new Vendor();
Почему то мне казалось что так поступать нельзя. Инициализация атрибутов являющихся объектами классов должно выполнятся в конструкторе.
Опровергни.
 
Сверху