Форум: "Основная";
Текущий архив: 2007.10.07;
Скачать: [xml.tar.bz2];
ВнизПридумал архетиктуру с пакетами и медиатором, помогите реализоват Найти похожие ветки
← →
Kolan © (2007-07-03 18:12) [0]ь
:)
Здравствуйте,
Придумал и почти реализовал такую архитектуру:
Есть медиатор в пакете(KMediator.bpl):TSystemMediator = class
strict private
FColleagues: TList;
class var FInstance: TSystemMediator;
constructor Create;
public
class function GetInstance: TSystemMediator;
class procedure DestroyInstance;
class function IsInstanceAssigned: Boolean;
destructor Destroy; override;
procedure SendMessage(Command: TCustomCommand);
procedure Attach(Colleague: TCustomColleague);
procedure Detach(Colleague: TCustomColleague);
end;
TCustomColleague = class abstract
strict private
public
constructor Create;
destructor Destroy; override;
procedure ExecuteCommand(Command: TCustomCommand); virtual; abstract;
end;
То есть он делает броад каст всем коллегам.
В том же пакете есть комманда:TCustomCommand = class
strict private
FAutoDestroy: Boolean;
public
constructor Create;
function This: TCustomCommand;
property AutoDestroy: Boolean read FAutoDestroy write FAutoDestroy;
end;
Главная форма такого приложения загружает пакет с загрузчиком медиатора и коллег.KColleaguesLoader.bpl
Вот пример пакета коллеги:unit KTestColleagueAddresseeUnit;
interface
uses
Dialogs, KSystemMediator, KCustomCommand;
type
TTestColleagueAddressee = class(TCustomColleague)
public
procedure ExecuteCommand(Command: TCustomCommand); override;
end;
var
TestColleagueAddressee: TTestColleagueAddressee;
implementation
{ TTestColleague }
procedure TTestColleagueAddressee.ExecuteCommand(Command: TCustomCommand);
begin
inherited;
if Command is TCustomCommand then
ShowMessage("Colleague test ok.");
end;
initialization
TestColleagueAddressee := TTestColleagueAddressee.Create;
finalization
TestColleagueAddressee.Free;
end.
Итак это работает так:
1. Загружается гл. форма.
2. В свойм конструкторе форма загружает пакетKColleaguesLoader.bpl
3. Загрузившись загрузчик в пакетеKColleaguesLoader.bpl
загружает пакет с медиаторомKMediator.bpl
4. Загрузчик сканирует директорию и загружет всех коллег.
5. Коллеги при загрузке присоединяются к медиатору.
Все это работает.
Теперь вопрос.
Я хочу сделать коллегу в главной форме.
Для этого я
1. в Project-Options-Packages дабавляю пакет с медиатором.
Запускаю, проверяю — работает
2. В uses гл. формы добавляю модулиKCustomCommand, KSystemMediator
.
Запускаю, проверяю — работает
3. Кидаю кнопку, в ней(в OnClick) пишу:
TSystemMediator.GetInstance.SendMessage(TCustomCommand.Create);
Запускаю — AV наbegin
Application.Initialize;
Application.CreateForm(TCustomColleagueMainForm, CustomColleagueMainForm);
Application.Run;
end.
КомментируюTSystemMediator.GetInstance.SendMessage(TCustomCommand.Create);
Опять работает — Что не так?
← →
Kolan © (2007-07-03 18:33) [1]Оч. жду Игоря Шевченко, который сказал, что это нормальное решение + использует пакеты в хвост и гриву :).
← →
Sergey Masloff (2007-07-03 22:18) [2]Ну если AV на бегине то всяко дело в какой-то секции инициализации. Ставь точки останова и смотри.
Кстати сам проект и все пакеты собраны с галкой "build with runtime packages"? я не увидел в описании этого момента
← →
Kolan © (2007-07-04 00:47) [3]> Кстати сам проект и все пакеты собраны с галкой «build
> with runtime packages»? я не увидел в описании этого момента
Да. См[0]:1. в Project-Options-Packages дабавляю пакет с медиатором.
← →
Kolan © (2007-07-04 00:54) [4]
> Ставь точки останова и смотри.
Запустил(указал host application) пакет с медиатором:
Получил сообщение:Не могу загрузить пакет KMediator, так как он содержит модуль KCustomCommand, который содержит KMediator.
Моё имхо, что тут виноват не мой код, а то как загружаются пакеты видимо медиатор загружается дважды…
Как исправить?
← →
SlymRO © (2007-07-04 05:10) [5]1. в Project-Options-Packages дабавляю пакет с загрузчиком медиатора.
По архитектуре: все правильно, но... броад каст всем это черезчур... если Colleagов мало... все гуд... а если много и при обработке команды колега может разослать доп команду... все приехали Stack overflow...
можно добавить в SendMessage Initiator:TSomeClass- чтобы сам на себя не зациклился...
Предлагаю использовать способ подписки на команды...
или древовидную систему обработки сообщений...
System(TSystemMediator)
->FileOp(TFamilyMediator)
-->TCustomColleague
->WndOp(TFamilyMediator)
-->TCustomColleague
SystemMediator загружает TFamilyMediatorы, они в свою очередь регистрируют тип семейства сообщений и его символический идентификатор... и отзываются только на свой тип сообщения... загружает колег своего типа...
← →
Kolan © (2007-07-04 08:14) [6]> команды колега может разослать доп команду… все приехали
> Stack overflow…
Часто бывает. Проблем небыло. Правда без пакетов.
> Предлагаю использовать способ подписки на команды…
Подумать надо.
Я решил проблему(частично) используюя предков для разных типов комманд. Поэтому коллеги проверяют не каждую комманду, а вначале проверяют из той ли она группы вообще…
НО! Это не суть вопроса.
в Project-Options-Packages дабавляю пакет с загрузчиком медиатора.
Почти та же реакция, только ошибка —Project raised too many consecutive exceptions
.
Кстати я не понял. Я убрал пакет с медиатором и подключил пакет с загрузчиком. Почему в uses он не ругается на KSystemMediator, KCustomCommand он же теперь по идее ничего про них незнает…
Мне кажется что написание или не написание строки:TSystemMediator.GetInstance.SendMessage(TCustomCommand.Create);
Приводит к тому что если её нет компилятьр опртимизирует и хоть KSystemMediator, KCustomCommand есть в uses он их не включает.
А если она есть он их включает и — ошибка…
Что делать? Как же решить? Может я мало кода привел? Куда копоть?
← →
Kolan © (2007-07-04 08:55) [7]Поставил точки вов сех пакетах системы где есть initialization. И запускался из каждого(с пом. Host application).
Везде ошибкаProject raised too many consecutive exceptions.
А при запуске из медиатора происходит все так:
Попадаем в консруктор формы:procedure TCustomColleagueMainForm.FormCreate(Sender: TObject);
begin
LoadColleaguesLoader;
end;
Вот код этой процедуры:procedure LoadColleaguesLoader;
begin
if FileExists(GetRootDir + rsColleagueLoader) then
LoadPackage(GetRootDir + rsColleagueLoader)
else
raise Exception.Create(Format(rsNoColleagueLoaderException, [rsColleagueLoader]));
end;
ПослеLoadPackage
как и положено попадаем в инициализациюзагрузчика коллег
initialization
PluginLoader := TPluginLoader.Create;
PluginLoader.LoadPlugins;
finalization
PluginLoader.Free;
Он создаётся нормально и переходит к загрузкеLoadPlugins
function TPluginLoader.LoadPlugins: Boolean;
var
Strings: TStrings;
I: Integer;
MediatorHandle: THandle;
begin
Result := False;
MediatorHandle := LoadMediator;
if MediatorHandle <> 0 then
begin
FPluginsHandles.Add(MediatorHandle);
Result := True;
{All other colleagues load.}
Strings := TStringList.Create;
ScanDirectory(GetRootDir+rsPluginsDir, True, Strings, rsPluginExtension,
"", 0);
for I := 0 to Strings.Count — 1 do
begin
if ExtractFileName(Strings[I]) <> rsMediatorName then
LoadPackage(Strings[I]);
end;
Strings.Free;
end;
end;
Нормально загружает медиатор и всех коллег — проверил отладкой.
Ставлю точку на последнийend
вLoadPlugins
. Жму F7 и получаю
Exception:Не могу загрузить пакет KMediator, так как он содержит модуль KCustomCommand, который содержит KMediator.
То есть видимо форма еще раз загружает(пытается) медиатор. Как от этого уйти. Медиатор — это же синглетон он нужен 1.
Каккие пути решения?
← →
Kolan © (2007-07-04 09:01) [8]Главное когда в Requires пакетов добавляю медиатор, то нормально. А когда в
Build with run time packeges
облом. В чем разница?
← →
Kolan © (2007-07-04 10:02) [9]Может это потому, что коллеги и медиатор лежат не в папке с гл. формаой и соотв exe, а в .\Plugins\
А?
← →
Kolan © (2007-07-04 10:37) [10]Не то чтобы мне не с кем поговорить…
Просто я продумал система и на основе этого каркаса все оч. хорошо получается, только эта проблемма держит, может, извените за наглость, я проект(328кБ) комк-нить скину, а?
← →
Игорь Шевченко © (2007-07-04 10:39) [11]
> Оч. жду Игоря Шевченко, который сказал, что это нормальное
> решение + использует пакеты в хвост и гриву :).
Игорь Шевченко посоветует взять в руки отладчик и решить проблему самостоятельно.
← →
Kolan © (2007-07-04 10:41) [12]Игорь Шевченко посоветует взять в руки отладчик и решить проблему самостоятельно.
А что :[7] Kolan © (04.07.07 08:55)
Не считается за попытку?
← →
Kolan © (2007-07-04 10:46) [13]Ой, блин
[5] SlymRO © (04.07.07 05:10)
1. в Project-Options-Packages дабавляю пакет с загрузчиком медиатора.
Помогло, просто я случайно пакет с загрузчиком медиатора добавил, а сам медиатор не стёр.
Теперь компилится нормально.
НО! Видимо создаётся еще один медиатор, ткTSystemMediator.GetInstance.SendMessage(TCustomCommand.Create);
Ни к чему не приводит. Коллеги не получают это сообщение.
А если посылать сообще ние из одного из коллего, то получают.
← →
Kolan © (2007-07-04 10:46) [14]> Теперь компилится нормально.
Я кстати не понял почему стало компилироваться, вчем смысл был?
← →
Игорь Шевченко © (2007-07-04 11:08) [15]Kolan © (04.07.07 10:41) [12]
> Не считается за попытку?
Попытка, не приведшая к успеху, за попытку не считается.
← →
Игорь Шевченко © (2007-07-04 11:12) [16]А может того, рановато с медиаторами ? Может матчасть подучить слегка ?
← →
DrPass © (2007-07-04 11:30) [17]
> Кстати сам проект и все пакеты собраны с галкой "build
> with runtime packages"?
Это надо еще постараться собрать пакеты со статической компоновкой :)
← →
Kolan © (2007-07-04 12:11) [18]> А может того, рановато с медиаторами ? Может матчасть подучить
> слегка ?
Может и рановато… Но надо сделать.
А мат часть в части пакетов учить или где?
← →
Игорь Шевченко © (2007-07-04 12:12) [19]
> А мат часть в части пакетов учить или где?
В части ответов на вопросы почему не компилировалось, например.
> Может и рановато… Но надо сделать.
А что, нельзя сделать проще ? :)
← →
Kolan © (2007-07-04 18:32) [20]> В части ответов на вопросы почему не компилировалось, например.
Ну я правда не доконца понял. :(А что, нельзя сделать проще ? :)
Можно, но потом будет оч. сложно…
Так что это и есть(имхо) проще всего.
Тем более что каркас такой я апробовал(успешно) на реальном проекте. Еслибы не он, то имхо я бы по срокам не успел… Правда я не использовал пакеты…
← →
Kolan © (2007-07-04 18:53) [21]> В части ответов на вопросы почему не компилировалось, например.
Ладно уточню про мат часть.
Если я еще раз прочту главу про пакеты Тейкста и Пачеко, я всмогу оттуда получить ответ на вопроспочему же не компилилось?
ЗЫ
Глупый действительно вопрос «Почему не компилилось?», он-то компилилось, просто сразу при старте вываливалось с ошибкой.
Итого:
Если я еще раз прочту главу про пакеты Тейкста и Пачеко, я всмогу оттуда получить ответ на вопрос,почему же сразу вываливалось с ошибкой?
.
И почему я получалНе могу загрузить пакет KMediator, так как он содержит модуль KCustomCommand, который содержит KMediator
.
И почему теперь, по всей видимости, загружается два экземпляра пакета с медиатором?
Смогу?
← →
SlymRO © (2007-07-05 08:56) [22]1. build with: KMediator,KColleaguesLoader
KColleaguesLoader requires KMediator
если нет requires то KSystemMediator, KCustomCommand будут скомпилированы дважды, 1 раз в KMediator, 2 раз в KColleaguesLoader.
Не проже лоадер совместить с медиатором в одном пакете?
2. какой LoadPackage(GetRootDir + rsColleagueLoader)? если ты статично их прилинковываешь "build with" KColleaguesLoader
← →
Kolan © (2007-07-05 16:04) [23]
> SlymRO © (05.07.07 08:56)
Тааак,
1. Да у KColleaguesLoader нет медиатора в requires. Шас включю и проверю.
2. Ну раньше же я вообще ничего не подключал к форме. поэтому иLoadPackage
. Тут не понял. Что надо сделать? Не делать вообще LoadPackage, да?
← →
Kolan © (2007-07-05 16:13) [24]Короче добавил в
KColleaguesLoader
в requires KMediator.
А в форме в кострукторе закоментил:procedure TCustomColleagueMainForm.FormCreate(Sender: TObject);
begin
//LoadColleaguesLoader;
end;
Программа запускается, но останалвилается на beginbegin
Application.Initialize;
Application.CreateForm(TCustomColleagueMainForm, CustomColleagueMainForm);
Application.Run;
end.
Жму F9, появляется форма в Evant log начинают сыпатся сообщения. Что то вроде бесконечного цикла что-ли…
ЗЫ
Мож я таки закину прект, а? Явно ведь с создание пакетов что-то… :(
2 раз в KColleaguesLoader
Почему их нет же в uses. Вот всё целиком:
unit KColleaguesLoaderUnit;
interface
uses
SysUtils, Classes, Dialogs;
resourcestring
rsPluginsDir = "Plugins";
rsPluginExtension = ".bpl";
rsMediatorName = "KMediator.bpl";
rsDirectoryDoesNotExists = "Указаная папка не существует.";
rsMediatorNotFound = "Медиатор не найден.";
type
EPluginLoaderException = class(Exception);
THandleList = class(TList)
private
function GetItem(Index: Integer): THandle;
procedure SetItem(Index: Integer; const Value: THandle);
public
function Add(Handle: THandle): Integer;
property Items[Index: Integer]: THandle read GetItem write SetItem; default;
end;
TPluginLoader = class
strict private
FPluginsHandles: THandleList;
strict protected
function GetRootDir: string;
function LoadMediator: THandle;
procedure ScanDirectory(Directory: string; ScanSubFolders: Boolean;
Strings: TStrings; Extension: string; FileName: string; RecursionCount: Integer);
public
function LoadPlugins: Boolean;
constructor Create;
destructor Destroy; override;
end;
var
PluginLoader: TPluginLoader;
implementation
{ THandleList }
function THandleList.Add(Handle: THandle): Integer;
begin
Result := inherited Add(Pointer(Handle));
end;
function THandleList.GetItem(Index: Integer): THandle;
begin
Result := THandle(inherited Items[Index]);
end;
procedure THandleList.SetItem(Index: Integer; const Value: THandle);
begin
inherited Items[Index] := Pointer(Value);
end;
{ TPluginLoader }
constructor TPluginLoader.Create;
begin
FPluginsHandles := THandleList.Create;
end;
destructor TPluginLoader.Destroy;
var
I: Integer;
begin
for I := 0 to FPluginsHandles.Count — 1 do
UnloadPackage(FPluginsHandles[I]);
FPluginsHandles.Free;
inherited;
end;
function TPluginLoader.GetRootDir: string;
begin
Result := IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0)));
end;
function TPluginLoader.LoadMediator: THandle;
var
Strings: TStrings;
begin
Result := 0;
Strings := TStringList.Create;
ScanDirectory(GetRootDir, False, Strings, rsPluginExtension,
rsMediatorName, 0);
if Strings.Count > 0 then
Result := LoadPackage(Strings[0]);
Strings.Free;
end;
function TPluginLoader.LoadPlugins: Boolean;
var
Strings: TStrings;
I: Integer;
MediatorHandle: THandle;
begin
Result := False;
MediatorHandle := LoadMediator;
if MediatorHandle <> 0 then
begin
FPluginsHandles.Add(MediatorHandle);
Result := True;
{All other colleagues load.}
Strings := TStringList.Create;
ScanDirectory(GetRootDir+rsPluginsDir, True, Strings, rsPluginExtension,
"", 0);
for I := 0 to Strings.Count — 1 do
begin
if ExtractFileName(Strings[I]) <> rsMediatorName then
LoadPackage(Strings[I]);
end;
Strings.Free;
end;
end;
procedure TPluginLoader.ScanDirectory(Directory: string;
ScanSubFolders: Boolean; Strings: TStrings; Extension: string;
FileName: string; RecursionCount: Integer);
var
CurrentFile: TSearchRec;
begin
Directory := IncludeTrailingPathDelimiter(Directory);
if Assigned(Strings) and DirectoryExists(Directory) then
begin
try
if FindFirst(Directory + "*.*", faAnyFile, CurrentFile) = 0 then
begin
repeat
if (CurrentFile.Name <> ".") and (CurrentFile.Name <> "…") then
begin
if ((CurrentFile.Attr and faDirectory) <> 0) and ScanSubFolders then
ScanDirectory(Directory+CurrentFile.Name, ScanSubFolders, Strings,
Extension, FileName, RecursionCount + 1);
if (Extension = "") or (ExtractFileExt(CurrentFile.Name) = Extension) then
if (FileName = "") or (FileName = CurrentFile.Name) then
Strings.Add(Directory+CurrentFile.Name)
end;
until FindNext(CurrentFile) <> 0;
end;
finally
FindClose(CurrentFile);
end;
end;
end;
initialization
PluginLoader := TPluginLoader.Create;
PluginLoader.LoadPlugins;
finalization
PluginLoader.Free;
end.
← →
Kolan © (2007-07-05 16:25) [25]Ставил точку до сюда:
initialization
PluginLoader := TPluginLoader.Create;
PluginLoader.LoadPlugins;
finalization
PluginLoader.Free;
Дело не доходит — :(.
← →
SlymRO © (2007-07-06 05:53) [26]Удалено модератором
← →
Kolan © (2007-07-06 08:31) [27]Удалено модератором
← →
Kolan © (2007-07-06 09:01) [28]Короче я ничего не понял.
Уточняю вопрос. Что я хочу:
1. Есть проект с формой. У ничего не отмечена галка Build with run time packages. То есть просто проект.
2. Этот проект загружает загрузчик коллег.LoadPackage
3. Загрузчик коллег загружает медиатор и всех коллег.LoadPackage
4. Коллеги — пакеты. В requires у них медиатор.bpl и ни могут послать и принимать комманды.
Что конкретно мне нужно:
Послать комманду из формы проекта(1). Что конкретно для этого нужно сделать? По шагам?
← →
Kolan © (2007-07-06 10:23) [29]Добавил лог:
procedure TSystemMediator.Attach(Colleague: TCustomColleague);
begin
FColleagues.Add(Pointer(Colleague));
LogManager.WriteString("Attach: "+Colleague.ClassName);
end;
constructor TSystemMediator.Create;
begin
FColleagues := TList.Create;
LogManager.WriteString("Creatinon: "+Self.ClassName);
end;
Файл лога создаётся так:Randomize;
S := ExtractFilePath(Application.ExeName) + Application.Title +IntToStr(Random(10))+ "Log.log";
Тест 1.
В гл форме нетBuild with run time packages
.
В загрузчите коллег нет медиатора в reauires
Получается два файла!
Один пустой. Второй:1 10:16:30:703 Creatinon: TSystemMediator
2 10:16:30:703 Attach: TTestColleagueAddresseeОткуда пустой файл?
Тест 2.
Добавил медиактор в reauires в пакет с загрузчиком
Результат тот же.
Все еще ничего не понимаю :( Откуда берётся этот файл пустой. И как сделать :(
Тест 3.
Добавил загрузчик пакетов Build with run time packages
Результат — AV, фйлы не зоздались.
Тест 4.
Вместо загрузчика добавил медиатор в Build with run time packages
Результат — AV, фйлы не зоздались.
← →
Kolan © (2007-07-06 11:04) [30]Млииин может ошибка в том, что медиатор я клал в папку с плагинами, а не с гл. формой…
← →
Kolan © (2007-07-06 11:06) [31]Ппц,
убрал из загрузчика загрузку медиатора.
В проект с формой добавилKMediator;KColleaguesLoader
.
Ура, работает! И файл с логом только 1. Вроде всё.
Благодарю SlymRO, ты видимо именно это и советовал. :)
← →
Игорь Шевченко © (2007-07-06 11:17) [32]
> 1. Есть проект с формой. У ничего не отмечена галка Build
> with run time packages. То есть просто проект.
> 2. Этот проект загружает загрузчик коллег. LoadPackage
Так не надо делать.
← →
Kolan © (2007-07-06 11:39) [33]> [32] Игорь Шевченко © (06.07.07 11:17)
> Так не надо делать.
А как в [31]? — Вроде всё рабоате.
Еще раз в итоге так:
1. В проекте с гл. формой в Build with run time packages KMediator;KColleaguesLoader. Оба эти пакета в папке с *.exe.
2. При создании загрузчик коллег загружает только их.
← →
имя (2007-07-29 00:22) [34]Удалено модератором
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2007.10.07;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.06 c