I'm just learning Spring4D and i have one question.
If class implement only one interface its all clear:
IWeapon = interface
['{E679EDA6-5D43-44AD-8F96-3B5BD43A147B}']
procedure Attack;
end;
TSword = class(TInterfacedObject, IWeapon)
public
procedure Attack;
end;
GlobalContainer.RegisterType<TSword>.Implements<IWeapon>('sword');
sword := ServiceLocator.GetService<IWeapon>('sword');
and im really happy now, I have sword and i dont need to Free it.
but if class implements two or more interfaces:
IWeapon = interface
['{E679EDA6-5D43-44AD-8F96-3B5BD43A147B}']
procedure Attack;
end;
IShield = interface
['{B2B2F443-85FE-489C-BAF4-538BB5B377B3}']
function Block: Integer;
end;
TSpikedShield = class(TInterfacedObject, IWeapon, IShield)
public
function Block: Integer;
procedure Attack;
end;
GlobalContainer.RegisterType<TSpikedShield>.Implements<IWeapon>.Implements<IShield>;
I can ask ServiceLocator for an instance of TSpikedShield but i need choose one IWeapon or IShield. But I want use it in two ways(or i shouldn't want?) like:
spikedShield.Attack;
spikedShield.Block;
So if I good undestand, I have to create instance of TSpikedShiled directly(i mean without interface).
function MakeSpikedShield: TSpickedShield;
begin
result := TSpickedShield.Create;
end;
There is any way to use this class but with automagical Free?
(there won't be problem if interfaces could implement multi interfeces but its not allowed in delphi)
Edited:
maybe somethink like that?
ISpikedSield = interface
function AsWeapon: IWeapon;
function AsShield: IShield;
end;
TSpikedShield = class(TInterfacedObject, ISpikedShield)
There won't be problem if interfaces could implement multi interfaces but it's not allowed in Delphi
That is the exact cause of the problem.
I would just make an ISpikedShield interface that has the methods of IWeapon and IShield and making sure that every class that implements ISpikedShield also explicitly implements IWeapon and IShield (this is what the compiler basically does for you in C# for example where an interface can inherit from multiple other interfaces).
You then cannot assign an ISpikedShield to an IWeapon and IShield but using as operator will work because the class behind implements them.
However I am not sure if there is not a misconception in your architecture because if you think further there won't be a class that has an ISpikedShield as dependency but rather an IWeapon and/or IShield. Some game code would then check if your IShield supports ICanAttack to do an additional hit apart from those you can do with your IWeapon.
Related
I am trying to use typed interfaces and Spring4D, but have some issues with Resolving. Please review details below.
DB Objects:
unit u_DB;
type
TDBObject = class
public
property ID: TGUID;
end;
TDBCRM = class(TDBObject)
public
property SOME_FIELD: TSomeType;
end;
Declarations:
unit i_BaseDAL;
type
{$M+}
IBaseDAL<T: TDBObject, constructor> = interface
['{56D48844-BD7F-4FF8-A4AE-30DA1A82AD67}']
procedure RefreshData();
....
end;
unit u_BaseDAL;
type
TBaseDAL<T: TDBObject, constructor> = class(TInterfacedObject, IBaseDAL<TDBObject>)
public
procedure RefreshData();
....
end;
After that I was able to register the base IBaseDAL and IBaseDAL
GlobalContainer.RegisterType<IBaseDAL<TDBObject>>;
GlobalContainer.RegisterType<IBaseDAL<TDBCRM>>;
Using in project:
I need to resolve now IBaseDAL, but could not find how do it. Only below ugly approach work
DM := GlobalContainer.Resolve('i_BaseDAL.IBaseDAL<u_DB.TDBObject>#TBaseDAL<u_DBCRM.TDBCRM>').AsInterface as IBaseDAL<TDBObject>;
but I was hoping that below will work :) -
DM := GlobalContainer.Resolve(IBaseDAL<TDBCRM>);
Please advise how could it be resolved correctly?
Edit: I just noticed that somehow the interface table does not contain generic interfaces so you have to explicitly register them as explained below.
First you need to register an implementation and not just an interface.
GlobalContainer.RegisterType<TBaseDAL<TDBObject>>;
GlobalContainer.RegisterType<TBaseDAL<TDBCRM>>;
GlobalContainer.Build;
The container will inspect the class you registered and register all implemented interfaces (except IInterface) so it will know about IBaseDAL<TDBObject> and IBaseDAL<TDBCRM>.
If your class might implement some interfaces you don't want the container to know you have to register explicit:
GlobalContainer.RegisterType<IBaseDAL<TDBObject>, TBaseDAL<TDBObject>>;
GlobalContainer.RegisterType<IBaseDAL<TDBCRM>, TBaseDAL<TDBCRM>>;
GlobalContainer.Build;
Then you can resolve:
GlobalContainer.Resolve<IBaseDAL<TDBCRM>>;
By the way, are you sure your class definition should not be as follows?
type
TBaseDAL<T: TDBObject, constructor> = class(TInterfacedObject, IBaseDAL<T>)
I am trying to implement an interface to convert records in a dataset to Delphi records in a pre-generics version of Delphi. I don't like the interface at the moment, as it will always need calls to Supports which I'd like to avoid if possible and was wondering if there's a better way of doing it that I'm missing.
So far I have an navigation interface and data retrieval interface defined:
IBaseRecordCollection = interface
procedure First;
procedure Next;
function BOF: boolean;
... // other dataset nav stuff
end;
IRecARecordCollection = interface
function GetRec: TRecA;
end;
IRecBRecordCollection = interface
function GetRec: TRecB;
end;
Basically I have a concrete base class that contains a private dataset and implements IBaseRecordCollection and concrete class for each RecordCollection interface which derives from an abstract class implementing the IBaseRecordCollection (handled by an implements property) with the implementation of the record retrieval routine:
TAbstractTypedRecordCollection = class(TInterfacedObject, IBaseRecordCollection)
private
FCollection: IBaseRecordCollection;
protected
property Collection: IBaseRecordCollection read FCollection implements IBaseRecordCollection;
public
constructor Create(aRecordCollection: IBaseRecordCollection);
end;
TRec1RecordCollection = class(TAbstractTypedRecordCollection, IRecARecordCollection);
public
function GetRec: TRecA;
end;
Now, to use this I'm forced to have a builder that returns a IRecARecordCollection and then mess around with Supports, which I'm not keen on as it will always be used in this fashion.
i.e.
procedure GetMyRecASet;
var
lRecARecordCollection: IRecARecordCollection;
lRecordCollection: IBaseRecordCollection;
begin
lRecARecordCollection := BuildRecACollection;
if not supports(lRecARecordCollection, IBaseRecordCollection, lRecordCollection) then
raise exception.create();
while not lRecordCollection.EOF do
begin
lRecARecordCollection.GetRec.DoStuff;
lRecordCollection.Next;
end;
end;
Although this works, I'm not keen on the supports call and mixing my lRecordCollections and my lRecARecordCollections like this. I had originally hoped to be able to do something like:
IBaseRecordCollection = interface
// DBNav stuff
end;
IRecARecordCollection = interface (IBaseRecordCollection)
function GetRec: TRecA;
end;
TRec1RecordCollection = class(TInterfacedObject, IRecARecordCollection)
private
FCollection: IBaseRecordCollection;
protected
property Collection: IBaseRecordCollection read FCollection implements IBaseRecordCollection;
public
function GetRec: TRecA;
end;
but unfortunately Delphi wasn't smart enough to realise that the implementation of IRecARecordCollection was split over the base IBaseRecordCollection in the Collection property implements call and the TRec1RecordCollection object.
Are there any other suggestions for neater ways to acheive this?
-- edit to give a (longer) reply to #David's answer than possible in a comment
The suggested solution of:
IBaseRecordCollection = interface ['{C910BD0A-26F4-4682-BC82-605C4C8F9173}']
function GetRecNo: integer;
function GetRecCount: integer;
function GetFieldList: TFieldList;
function EOF: boolean;
function BOF: boolean;
...
end;
IRec1RecordCollection = interface (IBaseRecordCollection) ['{E12F9F6D-6D57-4C7D-AB87-8DD50D35DCA2}']
function GetRec: TRec1;
property Rec: TRec1 read GetRec;
end;
TAbstractTypedRecordCollection = class(TInterfacedObject, IBaseRecordCollection)
private
FCollection: IBaseRecordCollection;
protected
property Collection: IBaseRecordCollection read FCollection implements IBaseRecordCollection;
public
constructor Create(aRecordCollection: IBaseRecordCollection);
end;
TRec1RecordCollection = class(TAbstractTypedRecordCollection, IRec1RecordCollection, IBaseRecordCollection)
private
function GetRec: TRec1;
public
property Rec: TRec1 read GetRec;
end;
isn't compiling. It's complaining that TRec1RecordCollection cannot find methods related to IBaseRecordCollection. I also tried moving the Collection property from Abstract to Rec1RecordCollection and redeclaring the property in TRec1RecordCollection all with the same result
Looking a bit deeper it appears that direct inheritance of a class implementing IBaseRecordCollection would work but Delphi can't handle doing it indirectly via a property using implements.
Your code is almost there. The implements directive in your code fails to compile because you only declared that your class implements the derived interface. As it stands, your class does not implement the interface that the implements directive refers to, namely IBaseRecordCollection. You might think that would be inferred from the inheritance but it is not.
To solve your problem you simply need to declare that TRec1RecordCollection implements both interfaces:
type
TRec1RecordCollection = class(TInterfacedObject, IBaseRecordCollection,
IRecARecordCollection)
....
end;
Make just the one small change and your code will compile.
Update
Your edit to the question changes this somewhat. The code in my answer does indeed compile, given the code in your original question. However, add any method into IBaseRecordCollection and the compile will not accept it.
The compiler should accept this code and the fact that it does not is because of a compiler bug. Modern versions of Delphi will accept the code in your update to the question.
Unless you upgrade your compiler you will not be able to make your intended design work.
I've been trying to extend a bunch of library classes inheriting from the same base class by overriding a virtual method defined in that base class. The modification is always the same so instead of creating N successors of the library classes I decided to create a generic class parameterized by the library class type, which inherits from the class specified by parameter and overrides the base class' method.
The problem is that the code below doesn't compile, the compiler doesn't allow inheriting from T:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
end;
LibraryClassB = class(LibraryBaseClass)
end;
LibraryClassC = class(LibraryBaseClass)
end;
LibraryClassD = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T) //Project1.dpr(20) Error: E2021 Class type required
procedure foo; override;
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure MyClass<T>.foo;
begin
end;
begin
MyClass<LibraryClassA>.Create.foo;
MyClass<LibraryClassB>.Create.foo;
MyClass<LibraryClassC>.Create.foo;
MyClass<LibraryClassD>.Create.foo;
end.
Any ideas how to make this work? Maybe there is a way to trick the compiler into accepting something equivalent because, for example, inheriting from Dictionary<T,T> compiles without problems.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
Thank you
As you've been told already, this is valid with C++ templates, not with C# or Delphi generics. The fundamental difference between templates and generics is that conceptually, each template instantiation is a completely separately compiled type. Generics are compiled once, for all possible types. That simply is not possible when deriving from a type parameter, because you could get constructs such as
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
procedure foo; reintroduce; virtual;
end;
LibraryClassB = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T)
procedure foo; override; // overrides LibraryClass.foo or LibraryClassA.foo ?
end;
Yet this can work in C++, because in C++ MyClass<LibraryClassA> and MyClass<LibraryClassB> are completely separated, and when instantiating MyClass<LibraryClassA>, foo is looked up and found in LibraryClassA before the base class method is found.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
It is possible to create types at runtime, but almost certainly an extremely bad idea. I have had to make use of that once and would have loved to avoid it. It involves reading the VMT, creating a copy of it, storing a copy of the original LibraryBaseClass.foo method pointer somewhere, modifying the VMT to point to a custom method, and from that overriding function, invoking the original stored method pointer. There's certainly no built-in language support for it, and there's no way to refer to your derived type from your code.
I've had a later need for this in C# once, too, but in that case I was lucky that there were only four possible base classes. I ended up manually creating four separate derived classes, implementing the methods four times, and using a lookup structure (Dictionary<,>) to map the correct base class to the correct derived class.
Note that there is a trick for a specific case that doesn't apply to your question, but may help other readers: if your derived classes must all implement the same interface, and requires no new data members or function overrides, you can avoid writing the implementation multiple times:
type
IMySpecialInterface = interface
procedure ShowName;
end;
TMySpecialInterfaceHelper = class helper for TComponent
procedure ShowName;
end;
procedure TMySpecialInterfaceHelper.ShowName;
begin
ShowMessage(Name);
end;
type
TLabelWithShowName = class(TLabel, IMySpecialInterface);
TButtonWithShowName = class(TButton, IMySpecialInterface);
In that case, the class helper method implementation will be a valid implementation for the interface method.
In Delphi XE and higher, you could also try something completely different: TVirtualMethodInterceptor.
What you are attempting to do is simply not possible with Delphi generics.
For what it is worth, the equivalent code is also invalid in C# generics. However, your design would work with C++ templates.
I probably misunderstood your description of the problem but from your simplified example it seems you could "turn it around" and insert a class in the hierarchy in the middle like this:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryBaseFooClass = class(LibraryBaseClass)
procedure foo; override;
end;
LibraryClassA = class(LibraryBaseFooClass)
end;
LibraryClassB = class(LibraryBaseFooClass)
end;
LibraryClassC = class(LibraryBaseFooClass)
end;
LibraryClassD = class(LibraryBaseFooClass)
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure LibraryBaseFooClass.foo;
begin
end;
begin
LibraryClassA.Create.foo;
LibraryClassB.Create.foo;
LibraryClassC.Create.foo;
LibraryClassD.Create.foo;
end.
I'm a newbie with Dependency Injection containers, and I am trying to get my head around using them in conjunction with Mocking.
Lets say I have a controller and a list (the model):
IBlahList = interface
property Items[AIndex: integer]: IBlah read GetItem;
end;
IController = interface
property List: IBlahList read GetList;
end;
The implementation of IController would look something like (note, it's in the implementaion section:
implementation
TController = class (TInterfacedObject, IController)
private
FList: IBlahList;
function GetList: IBlahList;
public
constructor Create(const AList: IBlahList);
end;
And then, of course, I would register this class (as well as one for IBlahList) with the GlobalContainer:
GlobalContainer.RegisterType<TController>.Implements<IController>;
I place the TController in the implementation section, as suggested by various sources (well, Nick Hodges anyway!), so that we cannot reference the TController class directly.
Now, just say I want to test my implementation of ICollection in a unit test:
procedure TestSomething
var
LMockList: TMock<IBlahList>;
LController: IController;
begin
LMockList := TMock<IBlahList>.Create;
// Oops, I can't do this, I can't access TController
LController := TController.Create(LMockList);
end;
So, my question is, should I move the TController class into my interface section so I can test it, or is there some other way to pass the mock IBlahList to the controller that I have yet to find?
If you have the concrete class in the implementation section, then you could expose a factory function (i.e. have it in the interface section) that creates an IController with the required parameters.
It makes absolutely no sense to have an implementation that can not be instantiated, IMO.
interface
...
function CreateController(AList: IBlahList): IController;
implementation
function CreateController(AList: IBlahList): IController;
begin
Result := TController.Create(AList);
end;
Well you probably should be using the mock framework in your test projects as well, but in these cases I usually "cheat" and move the implementation to where I need it using a DUNIT conditional variable:
// In the real app, we want the implementation and uses clauses here.
{$IFNDEF DUNIT}
implementation
uses
classes;
{$ENDIF}
type
TClassUnderTest = class(TObject)
// ...
end;
// In test projects it is more convenient to have the implemenation and
// uses clauses down here.
{$IFDEF DUNIT}
implementation
uses
classes;
{$ENDIF}
Then make sure that any test projects define the DUNIT conditional var, and move any units needed by the TClassUnderTest declaration to the interface section. The latter you can do permanently or under control of the DUNIT conditional as well.
I can just say: don't listen to Nick in that case.
Putting a class inside the implementation part of a unit just has disadvantages and you are facing one of them.
The whole point of using dependency injection is to decouple pieces of your code.
Now you removed the static dependency of TController and some class that implements IBlahList but you pulled in another (and much worse imo) dependency: the dependency on the DI container.
Don't put the class inside the implementation part of a unit just to prevent someone from directly creating it in your production code. Also don't put in the dependency on the DI container into that unit.
A much better approach is to have 3 units: interface, class, registration.
Edit:
I suggest reading this article and pay attention to the underlined parts: http://www.loosecouplings.com/2011/01/dependency-injection-using-di-container.html
Edit2 - added some pseudo code to show what I mean.
The unit test code could exactly be as in the question.
unit Interfaces;
interface
type
IBlahList = interface
property Items[AIndex: integer]: IBlah read GetItem;
end;
IController = interface
property List: IBlahList read GetList;
end;
implementation
end.
-
unit Controller;
interface
uses
Classes,
Interfaces;
type
TController = class (TInterfacedObject, IController)
private
FList: IBlahList;
function GetList: IBlahList;
public
constructor Create(const AList: IBlahList);
end;
implementation
...
end.
-
unit Registration;
interface
implementation
uses
Interfaces,
Controller,
Spring.Container;
initialization
GlobalContainer.RegisterType<TController>.Implements<IController>;
end.
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".