| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Общие вопросы > Динамическая генерация процедур |
| Автор: Rohoss 19.8.2008, 20:09 | ||||
Есть класс с множеством методов
Мне нужно вызывать разные методы этого класса, типа как здесь
только здесь у процедуры один параметр, а мне нужно чтобы количество параметров менялось. Для того чтобы этим процедурным типом можно было вызвать любой метод класса TCommands Надеюсь у меня получилось правильно выразить мысль |
| Автор: Rohoss 20.8.2008, 02:19 |
| Возможно ли такое вообще? |
| Автор: Rennigth 20.8.2008, 10:56 |
хм, ну в принципе как Tnte объявишь, так и вызывай... в чем проблемма то? |
| Автор: Rohoss 20.8.2008, 21:08 |
| Так функции имеют разное количество параметров, причём не известно, сколько их будет (параметров). Добавлено через 1 минуту и 45 секунд Нужно как-то Tnte объявить как функцию с динамическим количеством параметров. Добавлено через 7 минут и 14 секунд Можно было параметром использовать динамический массив, но класс TCommands уже определён |
| Автор: Zmiy 20.8.2008, 22:05 | ||||
| Rohoss, все параметры - строки? Добавлено через 10 минут и 58 секунд Не знаю, попробуй
или
|
| Автор: Rohoss 20.8.2008, 22:52 | ||
Да
Сделал типо теста, сообщения выходят бредовые… |
| Автор: Rohoss 20.8.2008, 23:16 |
| ama_kid немного не то… Тип должен использоватся для функции с разным количеством параметрами, а у тебя параметр массив… |
| Автор: ama_kid 21.8.2008, 07:08 | ||||
|
| Автор: Felan 21.8.2008, 08:39 | ||||
| Тебе придется делать метод с переменным числом аргументов, потом проверять типы и приводить типы аргументов. Без этого не как. Есть другой вариант, если есть возможность переделать архитектуру классов, то смотри в сторону паттерна проектирования Command. И, если неизвестно изначально, какие команды могут быть, смотри виртуальные конструкторы. Общая суть такая:
Тест кода:
|
| Автор: Rohoss 21.8.2008, 21:39 | ||
| ama_kid либо я не понял твоего примера, либо ты не понял что я хочу… Есть, к примеру, текстовый файл fun.txt
приложения должно читать каждую строчку этого файла, вызывать метод класса TCommands и передавать этому методу параметрами то что идёт после пробела. «&» - разделитель между параметрами. Команды класса TCommands будут добавляться, а некоторые будут экспортироваться с dll, поэтому заранее определить не получится. Добавлено через 10 минут и 56 секунд Felan в твоём примере запутался, разберусь и отпишусь чуть позже… |
| Автор: THandle 21.8.2008, 21:54 | ||
| Rohoss, может и глупость сейчас говорю... Но что если сделать тип TNte с максимальным для методов класса TCommands параметров? То есть например:
|
| Автор: Rohoss 21.8.2008, 22:00 |
| Felan для каждой команды создавать свой класс? Добавлено через 4 минуты и 38 секунд THandle там точно есть команда с больше чем десятью параметрами… это не весь код класса TCommands. Пока единственный способ вижу изменять класс TCommands (сделать параметром динамический массив), но этого очень не хотелось. |
| Автор: Felan 22.8.2008, 07:25 | ||||
Почитай про паттерны проектирования. Это паттерн "Команда" и все станет понятно. Ну и что? В чем проблема-то? Зато каждая команда будет полностью самостоятельной единицей, которую ты сможешь править независимо ни от чего, и все изменения будут локализованы. Лучше что-ли когда у тебя класс с мильоном методов, да еще не дай бог, перегруженных? Да с переменными аргументами? Да тип у этих аргументов общий, который нужно приводить на месте к нужному типу? Да за порядком этих аргументов нужно тщательно следить, за безопасностью типов тоже... за их правильным приведением... Чуть что, все надо перелопачивать... опухнуть можно
И вот это как раз реализуется отлично. В моем примере добавляешь абстрактный метод Parse, в каждой команде реализуешь специфичный для нее парсинг строки. Динамически, создаешь нужную команду и выполняешь ее.... Все работает. В принципе, я тебе даже показал способ как можно команды без перекомпиляции добавлять... Только нужно будет их хранить в длл, и использовать паккаджи для общих классов. ЗЫЖ Логика такая. Есть базвый класс команды. Он используется для полиморфного выполнения и передачи объекта !ЛЮБОЙ! команды, которая унаследована от него (тут правда можно еще интерфейс использовать, но тогда не получит использовать виртуальные конструкторы напрямую). Каждая команда предаставляет собой класс-наследник базовой команды, которые реализует специфичный для себя функционал и инкапсулирует в себе все вспомогательные действия типа парсинга строки команды.... Все команды выполняются единообразно, после того как создается и настраивается класс команды. Их даже хранить не надо, создал команду, когда понадобилась, выполнил ее, уничтожил... |
| Автор: Rohoss 22.8.2008, 18:10 |
| Felan, вопрос в том, чтобы не переопределять класс TCommands Добавлено через 12 минут и 8 секунд А если уже без переопределения класса никак, то чем твой метод лучше от использования динамического массива? 1. Не нужно процедуру парсинга писать для каждой команды. 2. Получится более компактно. 3. Можно использовать общие поля класса для всех команд |
| Автор: Felan 23.8.2008, 11:48 | ||||
Ну тогда конечно такой способ не подойдет. Ибо я сразу сказал, "если есть возможность переделать архитектуру".
Тем, что это классика ООП. Следовательно проверена не раз на практике. Тем что он понятный, прозрачный, типо-безопасный, расширяемый. Ессно программист использующий его должен иметь определенный уровень, что бы четко понимать ООП, виртуальные конструкторы делфи. (не принимай на свой счет, просто это факт. Что бы с чем-то разобраться и понять нужны определенные знания и опыт). Плохо. Т.к. будет одна процедура для всех команд. Команд много - процедура становится огромной, трудной для восприятия и понимания за счет объема. Для расширения списка команд обязательно требуется перекомпиляция и очень внимательное и осторожное добавление команды. Пройдет время и ты не сможешь изменить ее так, что бы не потратить кучу времени на отладку. В моем случае у каждой команды своя маленькая процедурка, ошибки в которой влияют только на эту команду. Проще поддерживать, отлаживать, ошибки локализуются. Цель разработчика сделать код понятным, простым, устойчивым, что бы можно было его легко поддерживать исправлять. А компактность это не показатель. Можно все в одну строку написать без пробелов, будет еще компактнее. Как будешь читать модуль в 1000 символов? С такой компактностью потеряешь все преимущества, про которые я говорил в предидущем пункте + к ним добавишь проблемы с ручным контролем типов. Вот это просто ОШИБКА проектирования! Пройдет пару месяцев и для того, что бы исправить одну команду будешь неделю проверять не затронуло ли это другую. Зачем смешивать данные? Ты что для контроллера пишешь? Тебе принципиально сэкономить несколько байт? Это конечно все не критично, если пишешь проект с тремя командами, который один раз отдашь кому-то и забудешь, а если у тебя будет много команд, тебе придется его поддерживать и расширять, исправлять ошибки, все это хлебнешь по полной Ну а если тебе принципиально нельзя менять архитектуру, то выбирай из того, что тебе уже сказали. Или можешь все-таки сделать метод, который выбирает команду например таким:
Где TArgument базой класс типа TCommand в моем варианте, а от него наследника для каждой команды. Тогда по типу класса сможешь определить точно, какую команду нужно вызвать а в полях объекта передать нужные данные. |
| Автор: Rohoss 23.8.2008, 14:36 | ||||||
Ну вот функция:
Раз написал и забыл о парсинге… Добавлено @ 14:44 А так выглядят функции класса TCommands
|
| Автор: Rohoss 23.8.2008, 15:00 | ||||||
А почему они должны смешиваться? К примеру полем является класс для ведения логов
у него функции типа
Почему они будут смешиваться? В принципе они независимы, разница в том, что этот класс создаётся один раз, а не для каждой команды. Каждый байт конечно не важен, но ИМХО это не оправдано… |
| Автор: Rohoss 23.8.2008, 15:18 | ||
ну, здесь я так понимаю опять же нужно переопределять класс… Дело в том, что TCommands писал не я, и в нём 186 команд, общей длиной 11700 строк |
| Автор: Felan 23.8.2008, 16:45 | ||||||
Ну если так то хорошо. А если придется добавлять еще одну команду, которую надо будет парсить по другому?
Ну возможно я не совсем понял, что ты имеешь ввиду под "общими полями для всех команд". Создашь один раз и он будет у тебя висеть все время, пока работает программа... В моем случае команда существует пока выполняется.
Нет. Здесь как раз его не надо переопределять. Здесь ты делаешь обвязку для этого класса, которая изолирует его.
Не важно кто писал. Важно то, можешь ты его изменить или нет. Вот видишь, количество команд уже большое. ЗЫЖ Количество классов одно, количество объектов - другое. Я не настаиваю на своем способе и не говорю, что твой не правильный. Я просто привел другой вариант, который на мой взгляд более правильный. Но это только на мой взгляд |
| Автор: Rohoss 23.8.2008, 17:34 | ||
а можешь привести маленький пример? |
| Автор: Felan 25.8.2008, 08:00 | ||
| Ну я даже не знаю, Как тут его привести... Ну например так:
ЗЫЖ Но учти, что это обертка |
| Автор: CodeMonkey 25.8.2008, 11:19 | ||
| Пробежал тему по-диагонали. Вопрос: есть имя метода, скажем, 'XXX'. Есть ли возможность узнать, сколько у него параметров в классе? Т.е. по имени определить число параметров? Если да, то я не вижу проблемы. Можно сделать, например, как-то так:
Не нравится объявление 20-ти типов? Можно вызвать процедуру и без них, если код вызова записать на ассемблере. Первые три аргумента пойдут по регистрам, остальные - циклом до числа параметров пихаются в стек, после чего делаем call. P.S. Что будет, если число параметров у метода и число строк, которое мы напарсили, отличается? |
| Автор: Rohoss 25.8.2008, 21:20 | ||||||
Ты имел ввиду в функции? Хз, думаю как-то можно…
В ассемблере я полный ноль…
Не понял вопроса… Если мы передадим в метод не то количество параметров которые у него есть Добавлено через 7 минут и 13 секунд Felan твоего примера я пока не понял, попробую разобраться чуть позже, что-то он мне кажется сильно раздутым… Ты предлагаешь писать наследника TArguments для каждой команды??? |
| Автор: ama_kid 25.8.2008, 22:09 | ||||
Добавлено а, ну после этого - я тебя понял |
| Автор: CodeMonkey 26.8.2008, 12:58 | ||
Значит ваше кунг-фу ещё недостаточно хорошо ;)
|
| Автор: Rohoss 26.8.2008, 20:27 |
| CodeMonkey было бы очень не плохо если бы ты прокомментировал то, что написал… Так как гугл не заваливает инфой по запросу «delphi ObjAuto» Добавлено через 47 секунд да и drbk тоже… |
| Автор: CodeMonkey 27.8.2008, 00:21 |
| Всё это подробно разжёвывается, например, здесь: http://hallvards.blogspot.com/2006/09/extended-class-rtti.html и далее по ссылкам. На русском: http://www.transl-gunsmoker.ru/2011/07/digging-into-soap-and-websnap.html (начало серии тут: http://www.transl-gunsmoker.ru/2011/07/polymorphism-ad-nauseum.html ) P.S. Респект за попытку разобраться вместо бездумного копирования! |
| Автор: Rohoss 29.8.2008, 04:31 | ||
Вроде в общих чертах понял! Спасибо! |
| Автор: CodeMonkey 13.9.2010, 20:49 | ||
| Начиная с Delphi 2010 появилась новая RTTI, где можно делать много новых вещей. Немного ссылок: http://robstechcorner.blogspot.com/2009/09/delphi-2010-rtti-basics.html http://habrahabr.ru/blogs/delphi/86840/ http://delphi.about.com/od/oopindelphi/a/delphirtti.htm http://robstechcorner.blogspot.com/search/label/RTTI
|
| Автор: bems 13.9.2010, 22:42 | ||
|