Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.10.07;
Скачать: CL | DM;

Вниз

Придумал архетиктуру с пакетами и медиатором, помогите реализоват   Найти похожие ветки 

 
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.

Моё имхо, что тут виноват не мой код, а то как загружаются пакеты видимо медиатор загружается дважды&#133
Как исправить?


 
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]

> команды колега может разослать доп команду&#133 все приехали
> Stack overflow&#133

Часто бывает. Проблем небыло. Правда без пакетов.


> Предлагаю использовать способ подписки на команды&#133

Подумать надо.

Я решил проблему(частично) используюя предков для разных типов комманд. Поэтому коллеги проверяют не каждую комманду, а вначале проверяют из той ли она группы вообще&#133

НО! Это не суть вопроса.
в Project-Options-Packages дабавляю пакет с загрузчиком медиатора.
Почти та же реакция, только ошибка — Project raised too many consecutive exceptions.
Кстати я не понял. Я убрал пакет с медиатором и подключил пакет с загрузчиком. Почему в uses он не ругается на  KSystemMediator, KCustomCommand он же теперь по идее ничего про них незнает&#133

Мне кажется что написание или не написание строки:
TSystemMediator.GetInstance.SendMessage(TCustomCommand.Create);

Приводит к тому что если её нет компилятьр опртимизирует и хоть KSystemMediator, KCustomCommand есть в uses он их не включает.

А если она есть он их включает и — ошибка&#133

Что делать? Как же решить? Может я мало кода привел? Куда копоть?


 
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 &#151; 1 do
   begin
     if ExtractFileName(Strings[I]) <> rsMediatorName then
       LoadPackage(Strings[I]);
   end;
   Strings.Free;
 end;
end;


Нормально загружает медиатор и всех коллег &#151; проверил отладкой.

Ставлю точку на последний end в LoadPlugins. Жму F7 и получаю
Exception: Не могу загрузить пакет KMediator, так как он содержит модуль KCustomCommand, который содержит KMediator.

То есть видимо форма еще раз загружает(пытается) медиатор. Как от этого уйти. Медиатор &#151; это же синглетон он нужен 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]

Не то чтобы мне не с кем поговорить&#133

Просто я продумал система и на основе этого каркаса все оч. хорошо получается, только эта проблемма держит, может, извените за наглость, я проект(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]

> А может того, рановато с медиаторами ? Может матчасть подучить
> слегка ?

Может и рановато&#133 Но надо сделать.

А мат часть в части пакетов учить или где?


 
Игорь Шевченко ©   (2007-07-04 12:12) [19]


> А мат часть в части пакетов учить или где?


В части ответов на вопросы почему не компилировалось, например.


> Может и рановато… Но надо сделать.


А что, нельзя сделать проще ? :)


 
Kolan ©   (2007-07-04 18:32) [20]

> В части ответов на вопросы почему не компилировалось, например.

Ну я правда не доконца понял. :(

А что, нельзя сделать проще ? :)
Можно, но потом будет оч. сложно&#133

Так что это и есть(имхо) проще всего.

Тем более что каркас такой я апробовал(успешно) на реальном проекте. Еслибы не он, то имхо я бы по срокам не успел&#133 Правда я не использовал пакеты&#133


 
Kolan ©   (2007-07-04 18:53) [21]

> В части ответов на вопросы почему не компилировалось, например.

Ладно уточню про мат часть.
Если я еще раз прочту главу про пакеты Тейкста и Пачеко, я всмогу оттуда получить ответ на вопрос почему же не компилилось?

ЗЫ
Глупый действительно вопрос &laquo;Почему не компилилось?&raquo;, он-то компилилось, просто сразу при старте вываливалось с ошибкой.

Итого:
 Если я еще раз прочту главу про пакеты Тейкста и Пачеко, я всмогу оттуда получить ответ на вопрос, почему же сразу вываливалось с ошибкой?.
И почему я получал Не могу загрузить пакет 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;


Программа запускается, но останалвилается на begin

begin
 Application.Initialize;
 Application.CreateForm(TCustomColleagueMainForm, CustomColleagueMainForm);
 Application.Run;

end.


Жму F9, появляется форма в Evant log начинают сыпатся сообщения. Что то вроде бесконечного цикла что-ли&#133

ЗЫ
 Мож я таки закину прект, а? Явно ведь с создание пакетов что-то&#133 :(

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 &#151; 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 &#151; 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 <> "&#133") 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;


Дело не доходит &#151; :(.


 
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. Коллеги &#151; пакеты. В 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
Результат &#151; AV, фйлы не зоздались.

Тест 4.
Вместо загрузчика добавил медиатор в Build with run time packages
Результат &#151; AV, фйлы не зоздались.


 
Kolan ©   (2007-07-06 11:04) [30]

Млииин может ошибка в том, что медиатор я клал в папку с плагинами, а не с гл. формой&#133


 
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]? &#151; Вроде всё рабоате.
Еще раз в итоге так:
1. В проекте с гл. формой в Build with run time packages KMediator;KColleaguesLoader. Оба эти пакета в папке с *.exe.

2. При создании загрузчик коллег загружает только их.


 
имя   (2007-07-29 00:22) [34]

Удалено модератором



Страницы: 1 вся ветка

Текущий архив: 2007.10.07;
Скачать: CL | DM;

Наверх




Память: 0.59 MB
Время: 0.02 c
15-1189397321
Мая
2007-09-10 08:08
2007.10.07
Хотитите ли вы конец света?


6-1170777738
M@kc
2007-02-06 19:02
2007.10.07
idMessage.Subject


15-1189061708
infom
2007-09-06 10:55
2007.10.07
Нужна простенькая программа для тестирования студентов.


3-1180465570
tarkus
2007-05-29 23:06
2007.10.07
Использование DISTINCT в LocalSQL


8-1167250641
crasher
2006-12-27 23:17
2007.10.07
Слежение за объектом через веб-камеру