![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Адрес метода класса :) [D7, WinXP]
Pa5ha © (2007-09-23 00:51:00)Тема звучит обсурдно. Не знал как назвать.
В общем написал класс (на самом деле object, но не суть) "автомат", который являет собой конечный автомат. Все бы хорошо, но для каждой надстройки нужен свой "драйвер", работающий с данными и обрабатывающий состояния, поэтому в автомат при инициализации передается адрес процедуры-драйвера, которая вызваеца при смене состояния и выполняет необходимые действия. Надстройка - парсер xml или просто парсер файла настроек невозможно обернуть в класс или объект из-за того что метод класса или объекта один на все экземпляры и следовательно нам нужна реальная процедура-обработчик-драйвер, которую в свою очередь можно привязать только к экземпляру.
собственно не знаю как решить данную проблему, кроме как запихать все в один класс. Но такое решение мне не очень нравица ибо неудобно. Мб кто делал подобное? )
Юрий Зотов (2007-09-23 22:20:00) [1]> Kolan © (23.09.07 21:56) [12]
> хранить исходные данные, помогающие выбрать какой класс надо
> инстанцировать, имхо, должны быть в самом классе…
Могут, но не обязательно. Мы же не знаем всей задачи. Во-первых, эти данные в каждом классе могут иметь свою собственную структуру, поэтому объявить в базовом классе что-то абстрактно-универсальное может и не получиться - а без этого логика выбора класса улетает в трубу. Во-вторых, в подобных задачах нередко требуется еще и класс-менеджер, который управляет всей этой кухней и решает, какой именно класс ему в данный момент нужен. И т.д.
> Тогда дальше думать нельзя. Надо изучить все возможные способы
> хронения.
Совершенно верно. А это знает только автор вопроса. Поэтому я дальше думать и не стал, а просто дал одну из возможных схем. Остальное автор и сам доработает, как ему нужно.
Kolan (2007-09-23 21:56:00) [2]> И с точки зрения проектирования классов это уже не мелочь,
> потому что метод GetExtension в базовом классе
Согласен не продумал. Но хранить исходные данные, помогающие выбрать какой класс надо инстанцировать, имхо, должны быть в самом классе
Тогда дальше думать нельзя. Надо изучить все возможные способы хронения. Или вы предлогаете сделать для обсалютно неизвестного источника данных?
В любом случае можно переименовать GetExtension во что-то подходящее для всех случаев.
Юрий Зотов (2007-09-23 21:42:00) [3]> Kolan © (23.09.07 20:43) [10]
1. В коде 2 ошибки, но это мелочь.
2. Один класс может обслуживать и несколько расширений, но это тоже мелочь.
3. А может и не обслуживать ни одного (ведь входные данные не обязаны находиться обязательно в файле). И с точки зрения проектирования классов это уже не мелочь, потому что метод GetExtension в базовом классе тогда становится совершенно нелогичным, потому что он предполагает хранение данных именно в файле. Поэтому у меня его в базовом классе и нет.
Kolan (2007-09-23 20:43:00) [4]> Юрий Зотов © (23.09.07 12:17)
> Extensions: array[0 (ParserCount 1)] of string =
> ('XML', 'INI');
> ParserClasses: array[0 (ParserCount 1)] of TAutomatClass
> =
> (TXMLParser, TSettingsParser);
А мне не очень нравится что расширение почти не связано с классом. Имхо нужное расширение должно находится прямо в классе.
Может придложете другое решение?
Я предлогаю так:
TAutomat = class( )
protected
procedure StateChanged( ); virtual; abstract;
public
constructor Create( ); virtual;
procedure ReadInput( );
class function GetExtension: string;
end;
ParserClasses: array[0 (ParserCount 1)] of TAutomatClass =
(TXMLParser, TSettingsParser);
function CreateParser(const FileName: string; );
var
Ext: string;
i: integer;
begin
Ext = AnsiUpperCase(ExtractFileExt(FileName));
for i := 0 to ParserCount 1 do
if Extensions[i] = ParserClasses.Extension then
begin
Result := ParserClasses[i].Create( );
Exit
end
raise
Exception.CreateFmt('Класс парсера для расширения %s не найден', [Ext])
end;
Юрий Зотов (2007-09-23 17:58:00) [5]Чтобы компилятору было полегче:
function CreateParser(const FileName: string; ...): TAutomat;
:o)
Pa5ha (2007-09-23 17:27:00) [6]О, как здорово и оперативно ) Спсип, щас будем рыть в новосм направлении.
Юрий Зотов (2007-09-23 16:51:00) [7]> b z (23.09.07 16:15) [4]
Зависит от того, у кого какой компилятор. Некоторые - не пропускают.
:о)
DrPass (2007-09-23 16:21:00) [8]
> и компилятор это пропускает?
Пропускает, конечно. Ты что, правил Паскаля не знаешь?
Zeqfreed (2007-09-23 16:20:00) [9]> b z (23.09.07 16:15) [4]
Разумеется. Если через препроцессор пропустить.
b z (2007-09-23 16:15:00) [10]
> function CreateParser(const FileName: string; ...);
и компилятор это пропускает?
Юрий Зотов (2007-09-23 12:17:00) [11]> Pa5ha © (23.09.07 00:51)
Добавление к [2].
Создавать нужный экземпляр надстройки можно, например, так:
const
ParserCount = 2;
Extensions: array[0..(ParserCount -1)] of string =
('XML', 'INI');
ParserClasses: array[0..(ParserCount -1)] of TAutomatClass =
(TXMLParser, TSettingsParser);
function CreateParser(const FileName: string; ...);
var
Ext: string;
i: integer;
begin
Ext = AnsiUpperCase(ExtractFileExt(FileName));
for i := 0 to ParserCount - 1 do
if Extensions[i] = Ext then
begin
Result := ParserClasses[i].Create(...);
Exit
end
raise
Exception.CreateFmt('Класс парсера для расширения %s не найден', [Ext])
end;
Юрий Зотов (2007-09-23 11:59:00) [12]> Pa5ha © (23.09.07 00:51)
Одна из возможных схем:
type
TAutomat = class(...)
protected
procedure StateChanged(...); virtual; abstract;
public
constructor Create(...); virtual;
procedure ReadInput(...);
end;
TAutomatClass = class of TAutomat;
TXMLParser = class(TAutomat)
protected
procedure StateChanged(...); override;
end;
TSettingsParser = class(TAutomat)
protected
procedure StateChanged(...); override;
end;
==============
constructor TAutomat.Create(...);
begin
inherited Create(...);
...
end;
procedure TAutomat.ReadInput(...);
begin
...
StateChanged(...);
...
end;
procedure TXMLParser.StateChanged(...);
begin
...
end;
procedure TSettingsParser.StateChanged(...);
begin
...
end;
Джо (2007-09-23 02:40:00) [13]Конечно, никто не мешает воспользоваться «адресом метода класса».
Но не лучше ли использовать возможности языка и обратиться к процедурным типам. Например, так:
type
TSomeMethod = procedure (SomeParam: TSomeType) of object.
Или вообще использовать в качестве «драйвера» абстрактный класс или интерфейс.