Tuesday, August 22, 2006

Avoiding circular refrences

Sometimes its the simple things that make it all worth while. As I once again took out my fork and began to separate out a huge pile of spaghetti code that was left for me, I needed to come up with a better method to avoid the circular reference trap. I had several units which contained classes which were directly referencing the main form. The circular reference here was troubling me as if I needed to pull one of the units out for another project, the entire application would go along with it.

My solution turned out to be quite simple. I created a new interface unit which contained nothing more than a set of interfaces:

unit MyProgram_Intf;
interface
// ---------------------------
type
iMainGui = interface
['{3D8EC075-0A0D-438E-9BCD-9BDDE10112E8}']
procedure SetStatus(sStatusMsg:String;iProgress:Integer);
end;

iMyModule = interface
['{A6A09A36-C4F2-4E2E-B231-B51A948FE4D4}']
procedure SetMainGui(pMainGui:iMainGui);
function PerformTask : boolean;
end;
//----------------------------
implementation
end.

After saving this unit and adding it to my main form and my child forms, I then changed each child form unit to something like:

tModuleOne = class(tForm,iMyModule)
private
fMainGui : iMainGui;
procedure SetMainGui(pMainGui:iMainGui);
function PerformTask:boolean;
end;

The implementation of SetMainGui is very simple:

procedure tModuleOne.SetMainGui(pMainGui:iMainGui);
begin
fMainGui := pMainGui;
end;

After adding the implmentation for each of these two methods, I added the following code to the initialization section of the unit (replacing tModuleOne with the name of the form class for this unit):

initialization
register(tModuleOne);
end.

Next I removed each one of the units from the main form to force myself to only use the interface. I implemented the SetStatus routine in the main form. The only thing left was the method to invoke each item. I ended up with the following:

function tMainForm.InvokeTask(sTaskname:String):boolean;
var
fTaskClass : TCustomFormClass;
fTask : tCustomForm;
fModule : iMyModule;
begin
Result := false;
try
fTaskClass := tCustomFormClass(FindClass(sTaskname));
except
// an exception here signals the class was not found
exit;
end;
fTask := fTaskClass.Create(nil);
try
if not Supports(fTask,iMyModule,fModule) then
begin
// if we get here then the module
//doesn't support the correct interface
exit;
end;
fModule.SetMainGui(Self);
result := fModule.PerformTask;
finally
fModule := nil;
fTask.Free;
end;
end;


Then, when I needed to call one of the tasks, I just called the InvokeTask method passing it the name of the class I needed to use. No more direct circular refrences, and each unit could easily be picked up and dropped into another project only requiring the unit with the interfaces is brought along also.

Windows Live Writer

This is interesting, the new Windows Live Writer can write to my blogger blog.  It supports multiple blog accounts, and has the ability to upload images. It is still in beta, but definately worth a look.

Good to grant!

Sometimes it helps to have knowledge of life before Google. When attempting to navigate to the Managed VCL pages at http://www.managedvcl.com, I discovered that they were not working properly and I was immediately prompted by some sort of error message in obvious Russian. Not being fluent in that language, I thought I would run it thru the translator at Google... but they don't have a translation option for Russian. Then I remembered my "before Google" days with altavista. So after navigating to http://babelfish.altavista.com I was able to enter the url, locate the appropriate translation option and pressed the go button.

I guess not everything translates well. What I received was the following message:

Good to grant!

The site of the client of hosting- provider HostZilla.ru is temporarily blocked.

Obviously the site is being blocked...the question is for how long and for why? And why is that Google doesn't have a Russian language translator?