spring4d resolve a local constructed class - delphi

Let's say, I have the following code:
interface
type
IMyInterface1 = interface // GUID
procedure ButtonEvent(Sender: TObject);
end;
IMyInterface2 = interface // GUID
procedure DoSomething;
end;
TMyClass1 = class(TInterfacedObject, IMyInterface1)
public
procedure ButtonEvent(Sender: TObject);
end;
TMyClass2 = class(TInterfacedObject, IMyInterface2)
public
procedure DoSomething;
end;
// ...
implementation
procedure TMyClass1.ButtonEvent(Sender: TObject);
var
aIntf2: TMyInterface2;
begin
// Pseudo code:
// aIntf2 := ServiceLocator.GetService<IMyInterface2>;
try
aIntf2.DoSomething;
finally
aIntf2 := nil; // will free the instance...
end;
end;
initialization
// Pseudo code:
// GlobalContainer register IMyInterface1 / TMyClass1
// GlobalContainer register IMyInterface2 / TMyClass2
// GlobalContainer.Build
end.
The method ButtonEvent is called by a delphi form button click event.
Now my question:
Is there a better way to instantiate the class TMyClass2?
Injection into the class TMyClass1 is not possible in my case, the lifetime of TMyClass2 instance is only inside ButtonEvent.
Next call to ButtonEvent should use a different instance...
AFAIK, method parameter injection or local variable injection is not possible in Spring4D, is it?

If you want to avoid the dreaded service locator pattern which does not solve the problem that DI solves but just shifts it (or in many cases even makes things worse because you have pseudo decoupled code which still has dependencies that you only experience once you run the code and figure out that you have to register some type in order to make the service locator to return the correct thing).
Method parameter injection or local variable injection? How on earth would that be possible. It would require some interception of the call in order for the container to inject something into the registers/stack.
While interception is possible for certain methods (virtual ones) that still requires the called instance to be set up for that. And if you do that you could have injected your dependency in the first place.
If you don't place DI in your composition root you always have to use some kind of service locator inside the code from where you want to start the process of dependency injection.
Think of DI and especially the use of a container as tool to achieve something specific: mostly decoupling your code for its various benefits. As I said the use of a service locator in such cases can cause more problems than it solves.
However back to your example: this is the classic case for using a factory. You need to inject that into your TMyClass1. It then can call the factory in your method and retrieve the IMyInterface2. Depending on the Spring4D version you are using there are different ways the container can save you some work as it is able to construct the factory for you. But I suggest writing the factory yourself using the classic pattern. That way you get a feel for it. Later when you are more experienced and confident with its use and where to use the container can easily take over that part.

Related

Delphi: declare variable avoiding circular reference

I've got a Delphi unit which needs to keep the pointer of various forms of the application, to do operations on them later.
In order to do those operations, I need to cast the pointer to a form type, ex.
var
ptrFrmMain: Pointer;
CurrentFrmMain: TfrmMain;
begin
CurrentFrmMain := ptrFrmMain;
CurrentFrmMain.Close();
end;
The problem is that this unit is contained in the uses of all the other Delphi units of the application. So while I can declare a simple Pointer type in the interface section, I cannot declare a type declared in the other units (such as TfrmMain of the unit frmMain.pas).
I could solve this by placing a use in the implementation section, such as:
interface
type TMyThread = class(TThread)
Public
ptrFrmMain:Pointer
...
implementation
uses frmMain
var
CurrentFrmMain: TfrmMain;
but there is still a problem: I need the variable to be specific to my class instance, for multithread purposes, and not a generic global variable.
But I cannot place it inside my TmyThread class, since TfrmMain is not declared there and I cannot place it in the uses of the interface section.
A solution would be to place CurrentFrmMain as a local variable in all the procedures which use it and then do the CurrentFrmMain := ptrFrmMain conversion each time, but do you know a better solution?
Thank you very much in advance.
I wouldn't put a Form pointer in the thread at all. I would have the thread hold callback functions instead, or even an interface:
type
TCloseProc: procedure of object;
TMyThread = class(TThread)
public
CloseProc: TCloseProc;
...
end;
...
begin
if Assigned(CloseProc) then CloseProc();
end;
type
IMyIntf = interface(IInterface)
['{9CC7DB9E-D47F-4B7D-BBF9-6E9B80823086}']
procedure DoClose;
end;
TMyThread = class(TThread)
public
Intf: IMyIntf;
...
end;
...
begin
if Assigned(Intf) then Intf.DoClose();
end;
...
type
TfrmMain = class(TForm, IMyIntf)
public
procedure doClose;
end;
procedure TfrmMain.doClose;
begin
Close;
end;
When the thread is created, assign the Form methods to those callbacks, or pass the Form's interface implementation to the thread:
Thread := TMyThread.Create(True);
Thread.CloseProc := frmMain.Close;
Thread.Resume;
Thread := TMyThread.Create(True);
Thread.Intf := frmMain as IMyIntf;
Thread.Resume;
Either way, the thread doesn't need to know about the actual Forms at all while still catering to Form-specific functionality.
Depends upon what do you mean by "keep the pointer of various forms of the application, to do operations on them later." - what kind (or kinds) of work that is? This is a question about generic software design, about decomposition, not just circular reference or any other language-specific issue.
If all you want to do is making same work over any form - then you should derive your forms from the same BASE-FORM-CLASS and keep references to that base class, not to the specific form classes. For example if you just need to .Release them you can just keep them all as TForm type reference which they all are derived from. This is just a typical case of extracting common abstract interface.
TMyFormWithActions = class ( TForm ) .... end;
TMyForm1234 = class ( TMyFormWithActions ) .... end;
TMyFormABCD = class ( TMyFormWithActions ) .... end;
You can also extract the common functionality not into intermediate class, but into the MS COM interface like Remy shown in his answer. This however is bordering with quite different memory model (ARC one) MS COM was based upon. While I do not expect TForm have auto-destroy reference counting, I also am not totally sure it can't happen, especially in inherited and complex application. So while I do like that approach, I omitted it because sometimes in practice it might cause unexpected and premature death of objects. If you can ensure that would not happen though it might be the most clean solution.
And if you need to do DIFFERENT actions, then you can indeed not merely store references to forms themselves, but also to actions, to software snippets. Then your thread-declaring class would build a general framework to keep forms-and-procedures data cells. And then you would have extra units implementing those specific actions to be passed.
( thread-and-action interface unit ) == uses ==> ( actions for TMyFormABCD unit ) <== uses == ( TMyFormABCD form declaration unit )
As a simplified option, you can declare those actions in the same units as forms themselves. Then you would have all form-units depend upon thread-unit, but thread-unit (remade to be generic and specific forms-agnostic) would no more depend upon any of forms-unit. Probably it might be called "Inversion of control".
See this series: http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-1/
And one more scheme to design this, which can be seen as implementing BOTH of those approaches - would be using Windows Messages.
Your "common interface", your "actions" would be represented by custom WM_xxx messages (integer consts) you would make. Then your thread would use PostMessage API to signal those actions to the forms. And those forms - by implementing methods to deal with those messages ( or by non-implementing = ignoring those messages ) would provide those action-implementations.
See: http://www.cryer.co.uk/brian/delphi/howto_send_custom_window_message.htm
PostMessage can be used from external thread but can not (easily) return values. SendMessage can only be used from the main Delphi thread. Also you have to check if MyTargetForm.HandleAllocated() before posting messages.

Calling child class non-virtual method or setting child class property

I have a base class TThread which has child classes like TThreadSock and TThreadPool, which override the .Terminate() method. And childs of those childs (like TThreadSockDownload or TThreadPoolCollect) inherite those .Terminate() methods (or might even override them):
type
TThreadSock= class( TThread )
procedure Terminate; // Hides TThread.Terminate
end;
TThreadSockDownload= class( TThreadSock );
TThreadSockUpload= class( TThreadSock )
procedure Terminate; // Hides TThreadSock.Terminate
end;
TThreadPool= class( TThread )
procedure Terminate; // Hides TThread.Terminate
end;
TThreadPoolCollect= class( TThreadPool );
My problem is: I have a list which can contain everything, so the most common denominator is TThread. And from that base class I need to call the most "childish" .Terminate() method. Currently my approach is this:
var
oThread: TThread;
begin
oThread:= GetNextThread();
if oThread is TThreadSockDownload then TThreadSockDownload(oThread).Terminate() else
if oThread is TThreadSockUpload then TThreadSockUpload(oThread).Terminate() else
if oThread is TThreadPoolCollect then TThreadPoolCollect(oThread).Terminate() else ...
...and you get an idea where this leads to. Not much to speak of that I have to use this code elsewhere as well. If I'd call oThread.Terminate() then the code of the base class is executed, which is not what I want. And defining the method as virtual also won't fully work, as every child level could be the "last" one. Or not.
My ultimate goal is to generalize this as much as possible, so I don't need to ask for each class as a candidate. Maybe I'm missing something fundamental here, like GetRealClass( oThread ).Call( 'Terminate' ); and GetRealClass( oThread ).Set( 'Stop', TRUE ); would be a dream.
Am I at least able to generalize this code so I only need to write it once? Something like FindMethod on an object I also have tell its class type to?
The correct way to deal with this is to use a virtual method. This mechanism is designed to allow method dispatch based on the runtime type of an object. In other words, precisely your your laboured type checking code does.
But you are grappling with the fact that you want to name your method Terminate, which is the name of an existing method that is not virtual. So, how to get past that.
Well, if you decided on the name Terminate because your methods call the TThread.Terminate, and then do other tasks, then the framework provides you with a simple way out. Let's look at the implementation of TThread.Terminate.
procedure TThread.Terminate;
begin
if FExternalThread then
raise EThread.CreateRes(#SThreadExternalTerminate);
FTerminated := True;
TerminatedSet;
end;
Note the call to TerminatedSet. That is a virtual method whose implementation is like so:
procedure TThread.TerminatedSet;
begin
end;
It does nothing. It has been provided to allow you to override it in derived classes, and have it called whenever the non-virtual method Terminate is called.
So you would do this:
type
TMyDerivedThread = class(TThread)
protected
procedure TerminatedSet; override;
end;
....
procedure TMyDerivedThread.TerminatedSet;
begin
inherited;
// do your class specific tasks here
end;
And then the code that controls the threads can call the non-virtual Terminate method, but still have this virtual method be called.
oThread := GetNextThread;
oThread.Terminate;
Now, on the other hand, it's plausible that your Terminate methods do not call TThread.Terminate. In which case the approach would be different. You still need a virtual method, but if the TThread class does not contain an appropriate virtual already, you need to introduce one. Which means deriving a new base class in order to introduce that virtual method.
type
TBaseThread = class(TThread)
public
procedure MyTerminate; virtual; abstract;
end;
I've made this abstract but you may not want to. We can't tell because we don't know what your thread implementations do. You can decide whether or not this method should be abstract.
Now you can override this virtual method like any other, which is something I believe you already understand. The other change you need to make is that instead of holding TThread references when operating on the thread instances, you hold TBaseThread references.

How to correctly inject a property to form?

I will up the question at second time.
Do not blame me please.
Situation:
I have a form
TfrmMain = class(TForm)
private
[Inject('IniFileSettings')]
FSettings: ISettings;
public
end;
I have container initialization procedure:
procedure BuildContainer(const container: TContainer);
begin
container.RegisterType<TIniSettings>.Implements<ISettings>('IniFileSettings');
container.RegisterType<TfrmMain, TfrmMain>.DelegateTo(
function: TfrmMain
begin
Application.CreateForm(TfrmMain, Result);
end);
container.Build;
end;
So I initialize both TfrmMain as well as TIniSettings via container.
in .DPR I have:
begin
BuildContainer(GlobalContainer);
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.
Also I have a helper for TApplication:
procedure TApplicationHelper.CreateForm(InstanceClass: TComponentClass; var Reference);
var
locator: IServiceLocator;
begin
locator := TServiceLocatorAdapter.Create(GlobalContainer);
if locator.HasService(InstanceClass.ClassInfo) then
TObject(Reference) := GlobalContainer.Resolve(InstanceClass.ClassInfo).AsObject
else
inherited CreateForm(InstanceClass, Reference);
end;
Problem:
when I try to
procedure TfrmMain.FormCreate(Sender: TObject);
begin
s := FSettings.ReadString('Connection', 'Server', 'localhost');
end;
I get AV exception because FSettings currently is NIL.
What is correct way to get FSettings object from the container?
UPDATE:
FSettings := GlobalContainer.Resolve<ISettings>;
This row works perfectly... As in last time I have problem to use [Inject] attribute.
Even with solution from Stefan I can make the method working:
How to initialize main application form in Spring4D GlobalContainer?
First the reason why the container does not have a HasService anymore is because that method has been removed. You can access it as follows:
if container.Kernel.Registry.HasService(...) then // yeah yeah, I know LoD is crying right now ;)
I would avoid mixing using ServiceLocator and GlobalContainer. While they should point to the same instance it might not be the case because actually someone could point one of them to another instance. If you really want to use ServiceLocator in this case then also resolve from ServiceLocator. But keep in mind that there is nothing on it that the container does not know (even if you have to call some different parts of the kernel.
But that is not the problem you are facing here with your settings injection. The problem you have is the timing. The FormCreate method (I just guess it is attached to the OnCreate event). So the container instantiates the TfrmMain, the event gets called and then returns to the container code which afterwards does all the injections. So calling something that has not been injected via constructor in some code being called during construction is a temporal coupling.
There are different approaches to this problem:
moving your access to the FSettings to some event that gets triggered later (like OnShow or OnActivate)
don't use field injection it can be nice but that couples your code to the container because "traditional" code cannot do that. Use property injection and a setter that executes the code.
When you consider constructor injection as for dependencies that are mandatory and property injection for those that are optional I would say go for the constructor injection. But knowing that you working with a TComponent descendant I probably would use the property injection in that case although that dependency is not optional.

Delphi Dependency Injection: Framework vs Delegating Constructor

Why would you use a Dependency Injection Framework when you can simple use the following pattern?
unit uSomeServiceIntf;
interface
type
ISomeService = interface
procedure SomeMethod;
end;
var
CreateSomeService: function: ISomeService;
implementation
end.
unit uSomeServiceImpl;
interface
type
TSomeService = class(TInterfacedObject, ISomeService)
procedure DoSomething;
end;
function CreateSomeService: ISomeService;
implementation
function CreateSomeService: ISomeService;
begin
Result := TSomeService.Create;
end;
procedure TSomeService.DoSomeThing;
begin
...
end;
end.
unit uInitializeSystem;
interface
procedure Initialze;
implementation
uses
uSomeServiceIntf,
uSomeServiceImpl;
procedure Initialze;
begin
uSomeServiceIntf.CreateSomeService := uSomeServiceImpl.CreateSomeService;
end;
end.
I am trying to grasp the benefits of using a framework instead of doing this but so far I only see the benefits of this simple approach:
1) Parameterized constructors are easier to implement. E.g.:
var
CreateSomeOtherService: function(aValue: string);
2) Faster (no lookups necessary in a container)
3) Simplier
This is how I would use it:
unit uBusiness;
interface
[...]
implementation
uses
uSomeServiceIntf;
[...]
procedure TMyBusinessClass.DoSomething;
var
someService: ISomeService;
begin
someService := CreateSomeService;
someService.SomeMethod;
end;
end.
What would be your reasoning to use a DI framework instead of this approach?
How this would look like using a DI framework?
As far as I know if you would use a DI framework than you would register the concrete class against the interface and then consumers of the system would ask an implementation for the given framework.
So there would be a registering call:
DIFramework.Register(ISomeInterface, TSomeInterface)
and when you need an ISomeInterface implementation you can ask the DI framework for it:
var
someInterface: ISomeInterface;
begin
someInteface := DIFrameWork.Get(ISomeInterface) as ISomeInterface;
Now obviously if you do need to pass parameters to create an ISomeInterface the whole thing gets more complicated with the DIFramework (but simple with the approach described above).
In your case you have to know the name of the factory function ptr (var CreateSomeService) in advance, at design-time. Sure, the interface and the function ptr are coupled together in the same Delphi unit file, but that's just a Delphi relic, global var is not thread safe and not access-protected.
And what if you got an interface at runtime, as a result of some function or a read from a config file - you don't know what factory function to call to get the actual instance of an implementor.
DIFrameWork.Get(ISomeInterface) as ISomeInterface hides the factory function from you so you only need the interface, not both the interface and the factory function. If you would try to hide the factory function then you'd also have to hide the parameters. (and would end up with something much like that DI framework).
the DI factory helps when you need an interface that someone else made and instructed the IoC container to create, sometimes an external library will hide the implementation from you. If you are the one creating the interfaces as well as using the interfaces you should look at the factory pattern creating the object for you based on the scope of the item, with the consideration of it being scoped as a singleton or the same for all in a "transaction".
You could generate a static class for singletons like "settings" what about the database session involved with a transaction that is touching the state of several objects... not so funny then. You should consider the right solution for the "right problem".

How to inherit if the child class is TForm?

I admit this is the first time I use inheritance,so I might even have choosen the wrong way,that's why I'm here asking you.
I wrote a Message Handler in my delphi application to catch the messages from WSAAsyncSelect()
procedure FormMain.MessageHandler(var Msg:Tmessage);
begin
case WSAGetSelectEvent(MSG.LParam) of
FD_READ: //OnSocketRead(MSG.WParam);
FD_CLOSE: //OnSocketClose(MSG.WParam);
end;
end;
The problem is that OnSockerRead and OnSocketClose are functions in another class.
I want to make a good relationship between the classes so the class with those two functions can access it's parent ,but in the same time the things to be private to other classes.
Please show me an example how should I do it,because I don't know if it's better to be abstract or inherited since I have never used both of them.I want to make my code more OO.
Thank you!
One thing you can do is to use interfaces to gain access to main form functionality. For example, lets say that you want to call either SocketRead or SocketClose which are on the main form from your child form. you COULD just use mainform in the implementation of the unit, but I try to avoid these types of circular references. The other option is to create a new unit to contain a shared interface and use it by both the main form and the child unit. For example:
unit MainFormShared;
interface
type
IMainFormShared = interface
['{A2C624D5-DDCF-49D6-8B03-791BA0B79A42}']
procedure SocketRead(var Handle : Integer);
procedure SocketClose(Var Handle : Integer);
end;
implementation
end.
your main form would implement this interface (ok to keep the implementation private):
type
tMainForm = class(TForm,IMainFormShared)
:
private
procedure SocketRead(var Handle : Integer);
procedure SocketClose(Var Handle : Integer);
end;
From the parent object in your inheritance chain you can implement your message handler like so:
procedure TParentForm.MessageHandler(var Msg:Tmessage);
var
fMainFormShared : IMainFormShared;
begin
case WSAGetSelectEvent(MSG.LParam) of
FD_READ:
if Supports(Application.MainForm, IMainFormShared,fMainFormShared) then
fMainFormShared.SocketRead(Msg.WParam);
FD_CLOSE: //OnSocketClose(MSG.WParam);
if Supports(Application.MainForm, IMainFormShared,fMainFormShared) then
fMainFormShared.SocketClose(Msg.WParam);
end;
end;
I don't think inheritance is the answer here, unless that OtherClass can be derived from MainForm, but that looks doubtful.
One way to open up access is to put both classes in the same Unit. That gives them instant access to each others implementation details.
But maybe you are trying to hard here, if OtherClass in it's own (small) unit that nobody else is USES then it won't be that bad to make those functions public.

Resources