With Spring4d, you can register custom factories like so
aContainer.RegisterInstance<TFunc<string, TMyObject>>(function(aName : string):TMyObject
begin
Result := TMyObject.Create(aName);
end);
In this manner, I would beleive that for every dependency that inherits from TComponent
, one who wants to pass the owner would either do
// Registrations
aContainer.RegisterInstance<TFunc<TComponent, TMyObject>>(function(Owner : TComponent):TMyObject
begin
Result := TMyObject.Create(Owner);
end);
// Then in code
constructor TMyClass.Create(aFctry : TFunc<TComponent, TMyObject>);
begin
fObj := aFctry(Self);
end;
Or one could also do
aContainer.RegisterType<TMyObject, TMyObject>;
// In code
constructor TMyClass.Create(aObj : TMyObject);
begin
fObj := aObj;
InsertComponent(aObj);
end;
Though, this is error prone / adds code just to pass in the owner. Is there a built-in way of getting a factory that takes a TComponent as parameter without having to register it in the container beforehand ?
Because often I will use
constructor MyObject.Create(aDep : TFunc<TMyDep>);
Without registering the TFunc<TMyDep>
dependency, but only the TMyDep
type.
It it possible to pass something like
constructor MyObject.Create(aDep : TFunc<TComponent, TMyDep>);
Without having to register it in the container ?
From what I know, this isnt possible without registration.
But, there is a way getting rid of a manual factory implementation for 1-4 parameters using the differentIFactory<T,TResult>
interfaces from Spring.Container.Common
, which will get automagically implemented by the DI Container when registered.
So you would register that like this:
aContainer.RegisterType<TMyObject>;
aContainer.RegisterType<IFactory<TComponent, TMyObject>>.AsFactory;
Registering the factory like this, does not require an implementation on your side - the container will resolve it for you.
That means, that whenever you need an instance of TMyObject
, you do not request it directly anymore (from the container). Instead you do request an instance of IFactory<TComponent, TMyObject>
, where TComponent
is the only parameter accepted by the TMyObject
constructor.
As a example of usage with constructor injection from another class TSomeClass
, (where TSomeClass
is also a TComponent
descendant) it would look like the following:
constructor TSomeClass.Create(const AMyObjectFactory: IFactory<TComponent, TMyObject>);
begin
fMyObjectInstance := AMyObjectFactory(Self);
end;
At least for me, that made things much easier.