Concrete instance of singleton - like a multiple singleton?

166 views
Skip to first unread message

Jacek Laskowski

unread,
Oct 18, 2018, 7:05:25 AM10/18/18
to Spring4D
I have an ISomething interface. I would like a certain group of objects to use a specific instance of ISomething (A), and another group of another ISomething (B) instance.
So there is one interface, one implementation, but two instances of this interface are created, which many other objects use.
How to register this interface (maybe with identifier?) in the container and how to resolve instance A or B via the factory method?

Philipp Schäfer

unread,
Oct 18, 2018, 7:23:00 AM10/18/18
to spri...@googlegroups.com
As far as I am aware, you can only name the registration and overwrite the resolving mechanich of each and every depend type (by specifying the named value and nil for the other constructor parameters). This specification is made during the registration phase. I do not recall the exact method name.

This will be improved in upcoming versions.

Another possibly more simple approach might be to derive two interfaces from ISomething with no further method. And register implementation A and B as singletons to these derived interfaces.

If you want to dive really deep you could influence the resolving process by a container extension. We do this for something else in one of our projects. This takes probably the most effort and might be subject to changes in updates.

Sorry that I talk mostly out of my head here, as I am on mobile only.

Stefan Glienke

unread,
Oct 18, 2018, 8:17:58 AM10/18/18
to Spring4D
{$APPTYPE CONSOLE}

uses
  Spring.Container,
  System.SysUtils;

type
  ISomething = interface
    ['{829E67EE-EA29-4D90-8CD3-558DB168F150}']
  end;

  TSomething = class(TInterfacedObject, ISomething)
  end;

  TCompBase = class
  private
    fSomething: ISomething;
  public
    constructor Create(const something: ISomething);
    property Something: ISomething read fSomething;
  end;

  TCompA = class(TCompBase);
  TCompB = class(TCompBase);
  TCompC = class(TCompBase);

constructor TCompBase.Create(const something: ISomething);
begin
  fSomething := something;
end;

var
  a,b,c: TCompBase;
begin
  GlobalContainer.RegisterType<ISomething, TSomething>('somethingA').AsSingleton;
  GlobalContainer.RegisterType<ISomething, TSomething>('somethingB').AsSingleton;
  GlobalContainer.RegisterType<TCompA>.InjectConstructor(['somethingA']);
  GlobalContainer.RegisterType<TCompB>.InjectConstructor(['somethingB']);
  GlobalContainer.RegisterType<TCompC>.InjectConstructor(['somethingB']);
  GlobalContainer.Build;
  a := GlobalContainer.Resolve<TCompA>;
  b := GlobalContainer.Resolve<TCompB>;
  c := GlobalContainer.Resolve<TCompC>;
  Writeln(a.Something = b.Something);
  Writeln(a.Something = c.Something);
  Writeln(b.Something = c.Something);
end.


Message has been deleted

Jacek Laskowski

unread,
Oct 18, 2018, 9:15:56 AM10/18/18
to Spring4D

I can't do this on two interfaces or two registrations.
In fact, these groups of objects using one singleton can be much more. I will describe it specifically.

I have a generic interface to write data to the database: IDBStorer. This interface can write data to any pre-defined table (generates inserts and updates). I would like a group of objects that saves, for example, orders, to use one instance of this interface, but configured to store orders. Completely in other place, another group of objects saves, for example, car routes, also uses the IDBStorer interface, but with a completely different configuration.

Therefore, I would need to resolve the interface from the factory using some type of "order" or "route" and to get the same instance for each "route", but different than when I resolve for "order".

Something like:

OrdersStorer := Container.Resolve<IDBStorer>.NamedSingleton('orders');
RouteStorer := Container.Resolve<IDBStorer>.NamedSingleton('route');

or better by factory:

TStorerFactory = reference to function(aStorerIdentifier : string) : IDBStorer;
Container.RegisterFactory<TStorerFactory>.AsNamedSingleton;

OrderStorer := StorerFactory('orders');
RouteStorer := StorerFactory('route');

and I get one instance IDBStorer per unique string.

Is possible?
Reply all
Reply to author
Forward
0 new messages