![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как создать функцию возвращающею разные типы? [D5, Win95/98, Win2k, WinXP]
Erik1 © (2004-09-23 16:39:00)Я пробовал создать базовый клас и от него унаследовать 2 потомков в которых переопределить нужную функцию. Но будет ли это работать?
Базовый клас:
TActivItem = class
private
fItem: TObject;
fStart: TSystemTime;
fStatus: TReportStatus;
protected
fID: integer;
fDescription: string;
function GetItem: TObject; dynamic; abstract; //Общая функция
public
constructor Create(Value: TObject);
destructor Destroy; override;
procedure Cancel; dynamic; abstract;
end;
Потомок:
TVisThread = class(TActivItem)
protected
function GetItem: TCustomThread; overload;
public
procedure Cancel; override;
property Item: TCustomThread read GetItem;
end;
Второй потомок:
TVisReport = class(TActivItem)
private
fReportItem: TReportItem;
..........
protected
function GetItem: TBaseReport; overload; //override;
public
property Item: TBaseReport read GetItem;
end;
И использование:
TReportManager = class(TComponent)
......
public
property Items[Index: Integer]: TActivItem read GetItems write SetItems; default;
end;
В Items записываю нужный клас и всегда могу вызывать общие методы определеные в TActivItem. Насколько это правильно?
Rem (2004-09-23 18:28:00) [1]1. Варианты не работают с классами.
2. Используйте overloaded/abstract/overriden/ метод с var-параметрами.
Sandman25 (2004-09-23 17:58:00) [2][30] Defunct © (23.09.04 17:55)
Лучше учесть [29] Sandman25 © (23.09.04 17:52)
И написать
Procedure TReportManager.Execute(Item: ...);
Begin
if Item.RequiresNewThread then
begin
...// создаем новый Thread
Item.Execute
...
end
else
Item.Execute
End;
Хотя на самом деле новый поток должен создаваться самим TVisReport в его DoStart :)
Defunct (2004-09-23 17:55:00) [3]Erik1 © (23.09.04 17:49) [28]
> меня TVisReport привелигированый класс, он выполняется подругому чем остальные.
берем пример Sandman25 © (23.09.04 17:41) [27]
изменяем реализацию Execute:
Procedure TReportManager.Execute;
Begin
If Item is TVisReport Then
Begin
PrepareToCreatePriviligedReport;
CreateAnExtendedReportThread;
End Else
If Item is ... Then
Begin
DoStart;
DoExecute;
DoFinish;
End и т.д.
End;
Sandman25 (2004-09-23 17:52:00) [4][28] Erik1 © (23.09.04 17:49)
Добавляете метод function RequiresNewThread: Boolean.
Сам Thread или Report не меняется, в этом и есть смысл ввода Адаптеров.
Erik1 (2004-09-23 17:49:00) [5]У меня TVisReport привелигированый класс, он выполняется подругому чем остальные. Для него report manager предоставляет свой тред для его выполнения, а остальным кукиш, приходится самим крутится. Интерфейс для управления хочется иметь общий. Ктоме того все треды от базового пронаследованы. Кащется есть 2 идеии: оставить все как есть и запытать в работе или реорганизовать и переложить обработку тредов на на обертки TVis...
Sandman25 (2004-09-23 17:41:00) [6]TVis = class
protected
procedure DoStart; virtual; abstract;
procedure DoExecute; virtual; abstract;
procedure DoFinish; virtual; abstract;
...
public
procedure Execute;
end;
procedure TVis.Execute;
begin
DoStart;
DoExecute;
DoFinish;
end;
TVisThread = class(TActivItem)
protected
procedure DoStart; override;
procedure DoExecute; override;
procedure DoFinish; override;
end;
...
Manager:
Item[15].Execute;
Defunct (2004-09-23 17:37:00) [7]Sandman25 © (23.09.04 17:18) [16]
Да.. пардон забыл о мелочи... ;)
is/as таки нужно применять перед вызовом у меня это было спрятано в статическом приватном методе, как-то и не задумывался..
Erik1 © (23.09.04 17:27) [20]
сорри, за то что не смог помочь, нормально написать пример тоже нужно время..
Sandman25 (2004-09-23 17:37:00) [8][23] Erik1 © (23.09.04 17:29)
Как оболочка они не должны различаться в interface-секции. Только реализация разная. И у них у всех должны быть virtual методы типа DoFinish и т.д.
Erik1 (2004-09-23 17:36:00) [9]to Sandman25
Говорит, чисто теоритически, ни разу неиспользовал. И как это реализавать в конкретном коде незнаю.
Erik1 (2004-09-23 17:29:00) [10]to Sandman25
А для чего я по твоему написал TVisThread и TVisReport они и есть обольчка. :)
Sandman25 (2004-09-23 17:29:00) [11]Erik1
Если Вам что-то говорит фраза "паттерн Адаптер", то ИМХО это именно он.
Sandman25 (2004-09-23 17:27:00) [12][18] Erik1 © (23.09.04 17:20)
Как он может запустить объект, если он не знает его тип. Либо через интерфейсы, либо пусть вызывает фабричную процедуру, которая лежит в отдельном модуле и которую надо будет изменять каждый раз.
ИМХО лучше написать оболочку - класс, который будет выполнять роль интерфейса. То есть разные наследники данного класса будут уметь запускать разные объекты, хранящиеся в них же.
Erik1 (2004-09-23 17:27:00) [13]to Defunct
Понимаеш TVisThread и TVisReport это просто обертка над уже реализоваными классами. И они ничего незнают о том, что надо наследоватся от общего предка. У меня неальный проекет в котором я переписываю Report manager. Так, что твой способ неподойдет.
Sandman25 (2004-09-23 17:23:00) [14]type
TAbstractFamily1 = class
function GetItem: TAbstractFamily1; virtual; abstract;
end;
TClass1Family1 = class(TAbstractFamily1)
function GetItem: TAbstractFamily1; override;
end;
TAbstractFamily2 = class(TAbstractFamily1)
function GetItem: TAbstractFamily2; reintroduce; virtual; abstract;
end;
TClass1Family2 = class(TAbstractFamily2)
function GetItem: TAbstractFamily2; override;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Object2 : TAbstractFamily1;
begin
Object2 := TClass1Family2.Create;
try
Object2.GetItem;
finally
Object2.Free;
end;
end;
{ TClass1Family1 }
function TClass1Family1.GetItem: TAbstractFamily1;
begin
ShowMessage('1');
end;
{ TClass1Family2 }
function TClass1Family2.GetItem: TAbstractFamily2;
begin
ShowMessage('1');
end;
При запуске получаю AbstractError
Erik1 (2004-09-23 17:20:00) [15]to Sandman25
А если у меня добавится новый клас то я сразу должен исходники переписывать? У меня есть TReportManager он неполностью знает с чем работает. Но должен уметь запустить объект и остановить его, кроме того уведомлять о произошедших событиях. Вобщем проектирую я его сейчас, если будут другии идеии то с удовольствием расмотрю. Можно конечно мойти через интерфейсы, этот вариант я еше необдумывал.
Defunct (2004-09-23 17:19:00) [16][15]
Блин, сам запутался в этих единичках и двоечках...
Object1, Object2 : TAbstractFamily 1;
Object1 := TClass1Family 2.Create;
Object2 := TClass1Family 1.Create;
Object1.GetItem вернет TAbstractFamily 2;
Object2.GetItem вернет TAbstractFamily 1;
Sandman25 (2004-09-23 17:18:00) [17]В классе TClass1Family2 метод TAbstractFamily1.GetItem остался абстрактным.
На каком основании TClassFamily.GetItem привязывается к нему? Ведь Вы же явно указали (reintroduce), что методы не имеют ничего общего.
Defunct (2004-09-23 17:16:00) [18]Erik1 © (23.09.04 17:02) [11]
Я немного поправлю [7], а то там написал не совсем доступно для понимания:
TAbstractFamily 1= class
Private
..
Function GetItem:TAbstractFamily 1; virtual;abstract;
..
End;
TClass1Family1 = class(TAbstractFamily 1)
Function GetItem:TAbstractFamily 1; override;
End;
..
TAbstractFamily2 = class(TAbstractFamily1)
Function GetItem:TAbstractFamily2; reintroduce; virtual; abstract;
End;
TClass1Family2 = class(TAbstractFamily2)
Function GetItem:TAbstractFamily2; override;
End;
Object1, Object2 :AbstractFamily1;
Object1 := TClass1Family2.Create;
Object2 := TClass1Family2.Create;
Object1.GetItem вернет TAbstractFamily2;
Object2.GetItem вернет TAbstractFamily1;
Sandman25 (2004-09-23 17:10:00) [19][12] Defunct © (23.09.04 17:08)
Нет. Будет AbstractError.
Sandman25 (2004-09-23 17:08:00) [20][11] Erik1 © (23.09.04 17:02)
Вопрос. Зачем называть GetItem, если можно назвать GetThread?
Как планируется вызывать GetItem? Ведь тип объекта уже явно будет известен, см. пост by Digitman