Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Perl: Общие вопросы > Классы |
Автор: Bulat 1.10.2007, 13:28 |
Вообщем-то раньше писал на яве, сейчас пишу на перле, но очень хочется порой писать по ООП'ному, просто так красивее и проще ![]() Просмотрел ряд топиков, но все же... Хочется решить такую задачу: Есть класс, в нем инкапсулированные переменные класса, и методы getVariable1, getVariable2 и т.д., а также методы setVariable1, setVariable2 и т.д. Все переменные должны поступать через конструктор класса, т.е. методы setVariable1 и т.д. только для правки. ![]() Т.е. по сути дела класс - лишь контейнер для хранения данных. Далее каждый экземпляр класса должен хранится в массиве, и при необходимости получать ту или иную переменную через метод getVariableX, соотв. для этого он и задумывается ![]() Вообще видел один не плохой топик, однако то, что меня в нем не устроило, то, что там массив был внутри самого экземпляра класса. Мне же нужно чтоб класс был лишь "контейнером". Т.е. каждый экземпляр класса хранить по одному набору переменных объявленных в классе. А все экземпляры класса хранятся в массиве, скажем так основного скрипта. При прохождении данного массива обращаемся каждый раз к очередному экземпляру класса и работаем с переменными из данного экземпляра... Надеюсь понятно выразился... ![]() |
Автор: korob2001 1.10.2007, 18:24 | ||||||||||
Ну насколько я понял, нужно что-то типа этого: Есть класс Person, поля которого хранят имя, фамилию и возраст человека. Опишем его: Файл Person.pm
Теперь сохраним в тот же каталог, файл который будет использовать наш класс Person. Файл people.pl
Я для краткости, не стал использовать все методы, но ты если хочешь можешь опробовать и их, но тогда последний цикл тебе придётся заменить, так как в нём массив очищается, так как используется как стёк, т.е. вместо строки:
Вставь наример такую:
После этого цикла все объекты так и будут храниться в нашем массиве @people и будет возможность поэксперементировать с ним ещё. Например можно попробовать добавить каждому человеку не по одному году, а по 5 лет используя всё тот же метод addAge() но уже с одним параметром типа int.
Здесь параметры получаемые конструктором получились именованные, если же хочешь сделать так, как в Java, то в конструкторе используй анонимный массив вместо анонимного хеша. Но это так, простейший пример, если хочешь более подробно, то поищи в разделах по Perl, по ключевому слову "ООП" или "Объектно Ориентированное Программирование", а так же советую почитать книгу "Программирование на Perl", в ней автор языка более подробно описывает данную тему. Если знаком с Java, то думаю всё будет понятно. |
Автор: Bulat 2.10.2007, 09:00 | ||||
korob2001, супер.... Это даже больше чем я ожидал... Есть только пара вопросов, чтоб добить это
Я так понял, объявление переменных внутри класса, инкапсулирует их ??? И как бы так грамотнее выразится... $self и будет являтся экземпляром класса ??? И послдений пока вопрос:
немного напоминает объявление массива хэшэй, но суть вопроса не в этом.... Как правило в яве, вроде бы и в С++, в конструкторе мы пишем все входные параметры, а при создании очередного экземпляра класса, лишь пишем, допустим $name = "Вася" $family = "Пупкин" $age = 16 new Person($name, $family, $age) и тут главное соблюдат правильную последовательность переменных... При таком объявлении, возможно не соблюдение последовательности ??? Добавлено через 13 минут и 32 секунды Млин, прям все это так глаз радует, все эти старые геттеры и сеттеры, методы и классы, и все на перле..... Море восторга, и соотв... |
Автор: Bulat 2.10.2007, 09:17 |
М-дя, и в догонку очень важный вопрос о деструкторах... В яве-то их ручками писать не надо, а как насчет перла ?? |
Автор: nitr 2.10.2007, 10:59 |
Bulat, тоже самое "не надо", но это исходя из задачи. В данном примере - не нужен. А korob2001 как всегда ![]() |
Автор: Bulat 2.10.2007, 11:40 |
nitr, А хорошего ;) , ресурса про ООП в перле случаем нет... А то в рамках данного примера все гуд, вот только хотелось более полно догнать такие вещи как наследование, инкапсуляция и т.п. P.S. Ссылки на топики форума прошу не кидать, в целом почти все промсотрел, но хотелось бы более полного материала ![]() |
Автор: cerf_machine 2.10.2007, 14:34 | ||||||
Инкапсуляции в перле нет. Т.е. в представленном выше примере можно обращаться к "свойствам" "объекта" напрямую:
Наследование в перле не использовал, но знаю, что оно тоже, к сожалению, псевдо, как и перегрузка операторов:( Реализуется через подключение базового класса в @ISA дочернего.
Ага. Но на самом деле $self - ссылка на хэш, связанная (blessed) с текущим пакетом (Person). Свойства же - на самом деле - ключи хэша.
Да, возможно. |
Автор: korob2001 2.10.2007, 23:12 |
Кстати, ты говорил, что знаком с Java. Вот я тут как-то приводил пример того, как можно создавать классы Java на лету, прямо из Perl программы, а после этого создавать объекты в Perl программе и работать с ними, как с родными Perl объектами. Это работает примерно так же, как встроенный код Assembler'a в программу C++. Вот http://forum.vingrad.ru/index.php?showtopic=124314&view=findpost&p=952337 можешь посмотреть этот пример. Кстати, таким же макаром, можно встраивать в Perl программу и код на C++, Assembler, Basic, да и многих других языков и не только языков. Вобщем если будет интересно, то поищи модули на cpan.org, по ключевому слову "Inline". Если ты под виндой, то можешь просто набрать в командной строке, такую команду: C:\>ppm s Inline Получишь список модулей, для встраивания кода других языков в Perl программу. Что бы установить модуль дай команду: C:\>ppm i Inline-Java Или другое имя модуля, вместо Inline-Java. |
Автор: Bulat 3.10.2007, 09:36 |
korob2001, ну инкапсуляция перемнных в классе-контейнере, вообще очень важна, так как если в ходе работы программы у нас создается не один экземпляр класса, то потом при попытке получить доступ, может вообще такая путаница произойти.... Вообщем как-то было у меня один раз в яве, после чего даже не стал разбиратся, тут это для меня как бы аксиома В целом огромное пасиба, за очень содержательные ответы... А ссылки на досуге обязательно почитаю, хотя в моей текущей конторе мы пишем исключительно на перле.. Да и раньше кода я комбинировал яву с перлом, то это были отдельные программы одной системы, как правило перл использовал за их регулярки... Если же внутри кода создавать, то я так понимаю, нужно будет устанавливать и виртуальную ява-машину, сейчас, я думаю мне этого никто не позволит сделать, в новой конторе я еще не набрал такого "веса" ![]() cerf_machine, тоже большой сенкс ![]() |
Автор: cerf_machine 4.10.2007, 10:49 | ||
Ух, ты ![]() Даже не думал, что можно связать с пакетом ссылку на функцию. Хотя это логично - перл крайне гибкий язык. korob2001, спасибо. Bulat, не за что;) |
Автор: Bulat 5.10.2007, 11:22 |
К сожалению пока углубится особенно в ООП на перле нет времени... Появился такой вопрос... При стандартном сеттере, если передаешь в качестве параметра не саму переменную, допустим $name = "Александр", а setName((shortName($name))); т.е., процедура shortName делает какие-то модификации с самой переменной... ?? |
Автор: cerf_machine 5.10.2007, 13:42 | ||
Не понял вопрос.
setName получит $_[0] => return-значение shortName. |
Автор: Bulat 5.10.2007, 13:51 |
cerf_machine, вопрос ты как раз понял и ответил на него ![]() Я лишь хотел убедится, что реально метод получит значение возвращаемое процедурой ![]() |
Автор: korob2001 5.10.2007, 16:57 | ||||||||
Ответ уже дали, но всё же решил привести ещё один пример, так на всякий случай ![]()
Теперь осталось запустить программу из командной строки и передать ей своёимя в качестве параметра. Причём, что бы налядно увидеть работу программы, имя должно быть в беспорядочном регистре, например так: dEnNiS. Если программа была запушена правильно, то регистр будет исправлен. Нас интересует строка:
Сначала передаём параметр функции lc(), она преобразует строку в нежний регистр, т.е. она возвращает строку "dennis" и тут же передаёт её дальше, функции ucfirst(), которая поднимает первый символ строки в верхний регистр и возращает результат "Dennis" и наконец предаёт отредактированное имя методу $person->setName(). Т.е. сначала выполняется самая внутренняя функция, это аналогично применению скобок для изменения приоритета арифметических операций. Тоже самое можно делать и с методами, добавим в код ещё две строки, теперь он выглядит так:
В строке:
сначала выполняется метод $person->getName(), он возвращает текущее имя "Dennis", это имя передаётся функции uc(), которая переводит верхний регистр всю строку "DENNIS" и в конце устанавливаем уже проеобразованное имя методом $person->setName(). |
Автор: Bulat 14.11.2007, 11:01 |
В целом, тема очень широкая, и появились еще дополнительные вопросы... Вообще конечно, кое-что уже было разъяснено ;) однако я сам не с того конца сформулировал вопрос, поэтому и не получил все ответы на него... В целом получится может даже убить два зайца... Изначально был очень хороший, но все же тривиальный пример... А меня сейчас интересует нечто более глубже... В данном примере, все поля класса - хеши, у класса есть свои методы и т.п. Все это хорошо, но если нам нужно что-то более сложноструктурированное, чтоб допустим этот класс, являлся лишь полем какого-то другого класса... И при этом из нового класса, доступ ко всем методам класса текущего, получается что-то типа наследования... Если не представится сложным, хотелось также затронуть момент переопределения метода, и для разнообразия побольше функциональных действий в самом конструкторе... P.S. В дополнение, также пока не совсем понял как лучше работать с директориями(пакетами), куда можно объеденить несколько классов, попытаюсь изобразить более визуально ./myScript.pl - <корневой скрипт> ./myClasses/... - пакет, где находятся классы, допустим ./myClasses/classesForDB/... ./myClasses/classesForFiles/... ./myInterfaces/.... ./myUtils/... - также содержатся какие-то классы ./myModules/... - просто модули ./files/... - пакет просто для каких-то конфигов, xml-файлов, или еще чего-нить ... Для знатока явы, я думаю понятно, что я хотел спросить про пакеты и подпакеты ![]() |
Автор: vadiml 18.11.2007, 18:18 |
> чтоб допустим этот класс, являлся лишь полем какого-то другого класса создаешь переменную в классе и этой переменной присваиваешь класс, т.к. класс в перле это всего лишь blessed ссылка (или array, ...) > хотелось также затронуть момент переопределения метода, для переопределения метода базового класса вообще ни чего не надо делать -- поиск метода всегда начинается с пространства имен текущего класса и только если ни чего не нашлось, то потом поочереди перебирается дерево базовых классов. другое дело если надо в классе переопределить встроенный в перл метод -- в начале класса надо объявить эту функцию, например переопределение split: use subs qw(split); а уже ниже её описать. экспортировать такую функцию не советую, путь живёт в пространстве имен только этого класса > побольше функциональных действий в самом конструкторе... в конструкторе можно делать что угодно, это самая обычная функция, которую и обозвать можно как угодно, например в Tk принято конструктору давать имя класса, хотя наиболее частый вариант -- это new > как лучше работать с директориями(пакетами), куда можно объеденить несколько классов создать для них каталог, например QQQ, и потом подключать их как use QQQ::модуль1; use QQQ::модуль2; но и названия пакетов внутри тоже должны быть приведены к этому виду: package QQQ::пакет1; use 5.008; use strict; use QQQ::модуль2; ... ЗЫ посмотри любой каталог, где лежат модули перла |
Автор: Bulat 20.11.2007, 15:53 | ||
Все же не совсем понял, а именно use QQQ::модуль1; package QQQ::пакет1; use QQQ::модуль2; тривиальный пример есть два модуля: util.pm и work.pm, что и где должно прописатся чтобы можно было работать при структуре ./mainScript.pl ./modules/util.pm ./modules/work.pm Но меня, интересует как бы не только раскидал по директориям и работаешь из основного скрипта... Но и такие ситуации, что модули из одного подкаталога должны использовать процедуры или модули из другого подкаталога... Конечно можно все это писать ручками в самих скриптах, указывая пути, но хотелось бы что-то более оптимальное, чтоб при работе, при подключении модулей, он просматривал корневой каталог текущего проекта, а там дальше по подкаталогам и к нужнему конфигу или модулю... Пример конечно не плохой, но уж слишком "на пальцах" ![]() |
Автор: Bulat 20.11.2007, 16:35 | ||
Хм... Что касается пакетов, то частично решил свои задачи, правда не могу пока знать все плюсы и минусы подобного подхода, надеюсь подскажете модуль
соотв в самом скрипте достаточно подключить его use modules::printDatas, а для вызова процедуры достаточно PrintHeader допустим, но здесь у меня возник еще один вопрос. В модуле я ручками прописываю push @EXPORT , '&PrintHeader';, но если уже есть хотелось бы, чтоб это выполнялось для всех процедур, которые есть в модуле... Конечно можно и ручками придумать нечто подобное, но если велосипед изобрели до меня ![]() |
Автор: vadiml 23.11.2007, 23:50 |
Для экспорта должен быть резон Иногда гораздо читабельне вызывать функции по полному имени: modules::printDatas::PrintHeader(); или для чего-то с зависимым содержанием создали класс, а потом вызывали через его указатель функции: my $pd = printDatas::new(); $pd->PrintHeader(); А если Вам хочется заняться экспортом, то надо заметить, что экспортироваться могут не только функции, но и любые переменные, массивы, хеши. а our @EXPORT; push @EXPORT , '&PrintHeader'; ... # куча push проще описать как our @EXPORT = qw(PrintHeader PrintFooter PrintMainLinks); не забывайте про списковый контекст, это часто очень удобный способ передачи данных PS вообще плохой пример с названием modules, желательно что-то осмысленное. В лучше бы Вы подключили каталог modules в переменную просмотра путей для поиска модулей: use lib qw(ваш_путь/modules ещё_один_путь_к_другой_группе_модулей); use printDatas; ... printDatas::PrintHeader(); PPS пустой блок END { } не имеет смысла, как и BEGIN стоящий в самом начале файла -- код в нем и так выполнится первым. Главное чтоб Вы модули подключали через use, а не require, при первом способе компиляция выполняется при старте программы, при втором -- при обращении к ней. |
Автор: Bulat 25.11.2007, 22:08 | ||||||
Резон-то есть... Методы(процедуры) вызываются в основном скрипте, это все ж не просто классы экземпляры данных ![]()
совсем не проще, какая разница, мне и так и так нужно перечислять весь список своих методов... хм, я имел ввиду другое, что-то, что позволило бы сразу все методы, без перечисления...
скока пишу, столько встречаюсь, что не поставленные где-то скобки(потому как сейчас они не имеют смысла) и т.п. частенько плачевно заканчиваются, лучше все же сначала закончить написание всего кода, а уже потом решать что нужно, а что нет ;) |
Автор: Bulat 15.9.2009, 11:41 |
некромантирую свою старую тему. ![]() Хотелось бы узнать делал кто-нить, если - да, то мож пример какой по переопределению методов, то бишь функций.. Полная аналогия с тем, что в ООП называется переопределение. ![]() И даже для большего страха ![]() Ес-но, сама суть в том, чтобы организовать хак, при котором определенная функция переопределяется и начинает работать по иному алгоритму нежели стандартная ![]() P.S. Интересует именно переопределение, а не альтернативные реализации хака )) |
Автор: gcc 15.9.2009, 11:52 | ||
SUPER псевдо-класс?
|
Автор: sir_nuf_nuf 15.9.2009, 12:51 | ||||||
делали.. для какого то мелкого модуля протокола STOMP.. Но если не используется OOP - это довольно шаткое решени. Заменить процедуру в любом модуле легко
Однако, если эта процедуру кто ли-бо импортировал до момента подмены - у них останется старая. В этом весь трабл.
Поэтому если вы хотите такое провернуть, то нужно подменять процедуру в самом начале
|
Автор: Bulat 15.9.2009, 16:37 | ||||
Вот на этом моменте я тоже призадумался
В том-то и вся проблема, что при такой реализации - все будет выглядеть еще некрасивее. ![]() gcc, не натыкается-ли твой способ на эти же грабли?? ![]() |
Автор: gcc 15.9.2009, 18:25 | ||||
для множественного наследования есть давно: use NEXT; http://search.cpan.org/~flora/NEXT-0.64/lib/NEXT.pm и много разных дополнений написанных на Си use Class::C3; http://search.cpan.org/~blblack/Catalyst-Plugin-C3-0.03/lib/Catalyst/Plugin/C3.pm http://search.cpan.org/search?query=mro&mode=all в каталисте в новой версии используется: Class::C3::Adopt::NEXT http://search.cpan.org/~flora/Class-C3-Adopt-NEXT-0.12/lib/Class/C3/Adopt/NEXT.pm в отладке выводиться сообщение что нужно перейти на этот модуль (проблем с переопределение в данном случае по-моиму не будет)
в какой-то старой книге (Кристенсен 2 или 3 издание, я книгу сейчас не смог открыть компе) было написано что можно как-то обойти это если использовать множественное наследование с SUPER... |
Автор: sir_nuf_nuf 15.9.2009, 23:19 | ||
Подменять чужие функции - вообще некрасиво. Другое дело как это сделать менее убого.. Ну создайте отдельный модуль типа .. Startup, в котором весь этот кошмар и изложите. А далее - либо первой строчкой своего скрипта его подгружайте, либо как startup.pl при старте mod_perl |
Автор: gcc 15.9.2009, 23:43 |
sir_nuf_nuf, а NEXT тут разве не подходит? его автор сделал как раз для множественного наследования... |
Автор: sir_nuf_nuf 16.9.2009, 08:47 |
gcc, нет. он подходит только если наследование (т.е. ООП) вообще имеет место. Мы же говорим про импорт обычных процедур. не методов объектов |
Автор: Bulat 16.9.2009, 11:32 | ||||
Действительно, это важный момент, сохранять целостность семантики кода... Тот кто после меня посмотрит мой код должен понимать не только как, но и что в нем происходит, а когда налеплено где-то процедурное, где-то ООП - это тоже не красиво... ![]()
Вариант.. ![]() |
Автор: gcc 16.9.2009, 14:07 |
Bulat, а в Java множественного наследования вроде бы нету и не будет... |
Автор: Bulat 16.9.2009, 16:40 | ||
Java - это уже сам по себе объекто-ориентированный и ссылочный язык. Там много устроено по иному нежели в перл... И переопределение происходит на уровне дочернего класса... Кроме того и перегрузка методов еще есть... Пафос перла-то в том, что нет необходимости писать огромное количество кода, когда можно обойтись десятью строчками. ![]() А в Java как такого множественного наследования нет, но есть интерфейсы ;) Хотя по мне это одно и то же... Ну мож за всю жизнь пару раз все же придется залезть так "глубоко", чтоб почувствовать и в этом разницу ![]() |