ООП - правила хорошего тона

Kirill

Новичок
ООП - правила хорошего тона

Я пока не понимаю правил хорошо тона в ооп, поэтому такой вопрос:
Есть класс, который является обработчиком (не важно чего). Вся логика рабты в нем.
Дочерние классы наследуются от него и устанавливают значение свойства ($this->page_prop - таблица в БД, поля и т.д.), по которому и происходит формирование данных.
Внимание вопрос, как должно происходить это присвоение по правилам хорошего тона?
Я делаю так:
В конструкторе обрабоотчика
function ClassName($param1, &$prod2, $etc){
parent::ClassInc($param1);

$this->page_prop = $this->SetVariables();
}

Соответственно в дочернем классе есть метода SetVariables, которы возвращает массив.
Правильно ли это? Или для установки $this->page_prop надо писать отдельную функцию, передавать ей данные, а она уже их присвоит $this->page_prop?

По мне так лучше бы SetVariables установить значения $this->page_prop.
 

denver

?>Скриптер
function ClassName($param1, &$prod2, $etc){
parent::ClassInc($param1);

$this->page_prop = $this->SetVariables();
}
Что за parent класс непонятно, функция SetVariables очевидно должна называться getVariables (это по поводу хорошего тона), и вообще, к чему такая конспирация? ClassName, ClassInc, param1, prod2, etc, page_prop? Что за класс и зачем нужен?
 

aXis

Новичок
Kirill
Твой вопрос очень даже понятен. На подобные заморочки есть такое решение. Код должен быть реюзабельным, то есть использоваться повторно.
Можно поступить и так и так. Смотри что будет юзаться повторно. Если коду нужно установить page_prop, то конечно через конструктор она сможет только один раз. Тут имеет смысл перенести установку в данный метод. А если нужно повторно запрашивать массив ( а оно нужно, иначе нафиг создавать этот метод) то правильный вариант в примере.
Ну а если и то и другое нужно делать много раз то выноси в 2 метода
function ClassName($param1, &$prod2, $etc){
parent::ClassInc($param1);

$this->SetProp();
}
function SetProp(){
$this->page_prop = $this->GetVariables();
}
function GetVariables(){
return array();
}

-~{}~ 23.01.07 03:33:

В свою очередь у меня тоже вопрос. У меня есть класс конфига. Он абстрагирует файлы конфига. Так вот что лучше? Передавать обьект класса по всем слоям приложения (и код сам достанет то что ему нужно) или передавать параметры полученные из этого конфига на верхнем уровне?

1 вариант чувствителен к изменению конфига. приложение только пишется и хрен знает что будет нужно
2 вариант какой то не ооп :(
 

denver

?>Скриптер
aXis
У меня есть класс конфига. Он абстрагирует файлы конфига. Так вот что лучше? Передавать обьект класса по всем слоям приложения (и код сам достанет то что ему нужно) или передавать параметры полученные из этого конфига на верхнем уровне?
...
2 вариант какой то не ооп
И кто из этих "какой-то не ООП"?
Вариант1:
PHP:
function __construct($config) {
  $lowLevel = $config->get('low_level');
  $maxLevel = $config->get('max_level');
  $hidden = isnull($config->get('is_hidden')) ? true : $config->get('is_hidden');
...
}
или Вариант 2:
PHP:
function __construct($lowLevel, $maxLevel, $hidden = true) {
...
}
Если всё еще не очевидно, подумайте про interface для этого класса
 

aXis

Новичок
denver

Упс. не так выразился. Тут вопрос касаемо опыта. Конечно можно передавать и так и так. НО... например обьявляю я у класса свой интерфейс конфига - все вроде хорошо, класс живет своей жизнью. Просто при вызове класса тот конфиг что мы имеем нужно перевести в удобоваримый формат понимаемый данным классом. Лишняя работа (конечно в библиотечных классах только этот способ, но у нас бизнес-обьекты). Можно ведь напрямую передать конфиг. Но тогда непродуманный конфиг при его изменении вызовет как минимум избыточный код при его модификации.

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

denver

?>Скриптер
aXis
Ну а другой вариант, когда целый конфиг вообще не передавать, а передавать только нужные параметры? Будет какая-то проблема?
 

aXis

Новичок
А вот щас как раз делаю передачу параметров. так уже несколько раз менял количество параметров. В конце концов запихал их в массив(обьект). При этом перед созданием обьекта класса приходится преобразовывать данные
 

aXis

Новичок
HraKK
Ага полный абзац. :)
Любой класс не обязан знать что ему подсовывают. Он обьявляет интерфейс и его не колышет кто его реализовывает и как.

То что количество параметров варьируется по мере разработки это обычное явление. То что в пхп можно задавать параметры нулл имхо плохая задумка. Лучше бы перегрузку методов сделали.

Есть такой хороший паттерн Messenger. Его функцию и выполняет передаваемый массив.

Писать конфиг дело неблагодарное. Не знаешь что нужно а что лишнее. И постоянно переделываешь. не менять же из-за этого все классы зависимые. Классы то знают чего им надо. А я не видя конечной системы не знаю какие параметры запихать в ини файл а какие бы лучше зашить в код. Конечно я обьявил интерфес конфиг-класса. Хоть он то стабилен. Но ведь проект не стоит на месте. И он может изменится. Не знаю почему, а я терпеть не могу методов оставленных из-за совместимости.

Есть лучший вариант? Всегда готов поучится.
 

denver

?>Скриптер
aXis
Когда у тебя слишком много параметров и интерфейс его часто склонен к изменениям, то дизайн класса скорее всего неправильный (например бывает правильным разбить его на несколько классов)

Приведи пример кода, когда тебя что-то не устраивает в передаче параметров обычным перечислением (т.е. не через конфиг).
 

aXis

Новичок
да нет. все правильно.
вот есть у нас конфиг допустим массив (что тоже класс в принципе)
$param=array(
\'par1\'=>\'value1\'
\'par2\'=>\'value2\'
)

и на самом деле нет никаких отличий в двух классах

__construct($param1, $param2) Вызов new Class($param[\'par1\'], $param[\'par2])
и
__construct(array $classparam)
Вызов new Class($param)
однако потому что класс $param изменяется то приходится
$newparam=array(
\'1\'=>$param[\'par1\'],
\'2\'=>$param[\'par2]
)
Вызов new Class($newparam)
То есть фактически производится преобразование интерфейса

Class это стабильный класс. он обьявил что он делает и что ему для этого надо.
Количество параметров слишком большое - в массив его.

однако сам конфиг постоянно меняется ибо он работает с файлами конфига. А у меня нет опыта угадывать что лучше
дать возможность настраивать а что нет. слишком подробный конфиг требует много правок при перездах. слишком скупой
дает мало гибкости.

Я пока использую такой выход. Класс конфига задает жесткий интерфейс и может отдать любой параметр. неважно откуда.
из файла или собрав его динамически. файл меняется а класс по возможности нет
Затрудений не предвидится если я не захочу дать море параметров и разнести их в разные классы со своими интерфейсами
дабы не запрашивать все через один класс. Очевидно в этом случае копи-вставить плюс код сразу скажет где что не так.
пробежаться по коду поменять.
А вот что неочевидно и хочу понять.
 

denver

?>Скриптер
Количество параметров слишком большое - в массив его
Никак не можешь понять, что здесь ошибаешься.
Из F(a,b,c,d,e,f), ты делаешь F(g) где g=array(a,b,c,d,e,f)
Это называется обман зрения :) Вроде меньше параметров, но на самом деле на один больше стало.

Количество параметров слишком большое -> к редизайну класса. И лучше рассматривать не сферические классы в вакууме, а реальные примеры.
 

aXis

Новичок
denver
Увы не ошибаюсь и никакой это не обман. Этот паттерн называется Messenger. Когда куча данных инкапсулируются в контейнер и его передают.

Зачем? на агиледев целая статься есть про инверсию зависимостей. Цель чтобы класс вообще не знал про реальный мир, а только про то что ему дали.

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

Количество параметров слишком большое -> к редизайну класса
Как же это так? А если класс имеет кучу свойств, которую надо инициализоровать через конструктор? тут никакой редизайн не поможет.

Пример правда наверно не жизненный. за жизненными надо идти в MFC. У них там длинючие конструкторы обычное дело.
Но все таки.
обьект музыкальный файл.
нужно
-имя
-исполнитель
-год
- битрейт
- альбом
и много ID3 тэгов
И допустим при создании усе это богатсво нужно задать.

Или даже вот. PEAR::pager там юзается фабрика. И юзается точно такой же подход. Ибо количество параметров характеризующих класс огромно. А он как и положено, ничего не знает о том где его используют.
Если я не прав, (хотя не пойму в чем собственно спор) давайте редизайним PEAR::pager
 

denver

?>Скриптер
Гугл молчит про Messenger, кто его озаглавил, есть ссылки?

Ну примеры убедительные. В случае с id3 тэгом, все эти аттрибуты действительно можно передавать в экземпляре реализующем интерфейс id3Attributes (можно и в массиве). Только по тому что это набор однотиных (с точки зрения реализации класса) аттрибутов.

на агиледев целая статься есть про инверсию зависимостей. Цель чтобы класс вообще не знал про реальный мир, а только про то что ему дали.
Ты думаешь только исходя из своих проблем. Статью я читал, но смысл ее имеет отношение только к *твоей* проблеме, когда ты думаешь адаптировать ли конфиг или так передать. В случае передачи параметров отдельными параметрами такой проблемы не - бу - дет:
Да и еще к тому же это даст возможность типизировать параметры (типизировать твой Messenger можно только с напрягом):
PHP:
function __construct(DataBase $dbInstance, integer $lowLevel, integer $maxLevel, boolean $hidden = true) { 
... 
}
 

aXis

Новичок
Этот паттерн озвучил Bruce Eckel (President, MindView, Inc.) как написано у меня в Thinking in Patterns (Технология решения проблем с использованием Java). даже у него сайт есть. www.BruceEckel.com. Правда я там никогда не был.

В случае передачи параметров отдельными параметрами такой проблемы не - бу - дет:
Да и еще к тому же это даст возможность типизировать параметры (типизировать твой Messenger можно только с напрягом):
Ну вообще то конечно мессенджер родился для типизированного языка.
Вот пхп без типизации. Но ведь зачем создавать нетипизированный язык, чтобы потом везде юзать типы?
Да и сама типизация в пхп это проблема. Уточнение типа в пхп5 это бред какой то.
простой пример. увы я сильно не тестил но мне и этого хватает.
function __construct(DataBase $dbInstance, integer $lowLevel, integer $maxLevel, boolean $hidden = true) {
...
}
При вызове этого коснтруктора мне явно приходится транслировать в (int) ибо чуть не уследил и оно mixed.
Взять же тот конфиг-класс с паблик свойствами. Пусть кто то где то установил свойство в 5 (забыв при этом указать (int)) и трындец - при вызове такого конструктора с использованием свойства вышеописанного конфиг класса будет ошибка.

Я в своих скриптах юзаю только проверку классов, а простые типы проверять - все равно вылетает ошибка несовпадения типов.

Взять тот же Зенд фреймворк. Кое где они проверяют на массив. Ибо передать класс реализующий итератор просто невозможно. Пришлось удалить проверку и все работает как часы.

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

Конечно в пхп 5 таки можно это чудо совершить с классами. Но мессенджер тоже класс и тоже может отслеживать. Причем не только проверить простой тип а и насильно (невозможно ж забыть )транслировать его в нужный, дабы далее не было проблем.

Плюс еще одна польза от передачи массива. Я офигеваю писать оффигенно длинные строки вызова. Ибо приходит ко мне обьект класса и мне нужно достать каждое свойство и в итоге получается
$object=new Class($config->DataBase, $config->LowLEvel, $config->MaxLevel, $config->Hidden);
Причем бывает несколько таких надо вызывать и не в цикле. Проще один раз подготовить общую часть массива параметров и немного модифицировать перед вызовом. Экономит время на получения значений свойств.

-~{}~ 25.01.07 17:32:

может сложится впечатление что я защищаю использования массива. но это не так. Я всегда использую явные вызовы пока параметров меньше 5.

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

Что, впрочем я и делаю. Класс требует интерфейс и он совпадает с интерфейсом конфига. Однако мне не помешает при нужде поменять интерфейс конфига (правда придется тогда адаптировать его для бизнес -обьекта перед вызовом)

denver
После долгих писаний на си шарп я пришел к выводу, что любой контроллер (любой класс кто реагирует на действия юзера) должен быть посредником - то есть ничего толком не делать, но знать кто знает и перенаправлять вызов ему. Так же пришел к выводу, что только он должен знать что такое конфиг, как достать его и как передать вызываемому модулю нужные данные. Но модуль не должен знать о конфиге ничего кроме заявленного интерфейса.

Если у кого то другие наработки, прошу сообщить. Ибо вечно учусь.

Так вот была типичная задача. Контроллер получив нажатие кнопки просто доставал конфиг и инициализировал какой то модуль. Этот модуль знал что нужно создать поток (ну не контроллеру же это знать) и создавал его и опять же надо туда передать все параметры. То есть уже 2ная передача. Поток может создать че то свое мудренное (например форму) и туда передать. То есть конфиг идет по уровням. И когда я не оборачивал его в контейнер и приходилось добавлять параметр я лазил по всем этим уровням и добавлял нужный параметр.
Ведь только одному классу положено знать обо всех - посреднику. Остальные пусть знают только о себе.
то есть выполнятся:
Закон Деметера (Demeter): \"Не говорите со странниками\". Объект должен ссылаться только на себя, свои атрибуты и аргументы своих методов.
 
Сверху