Delphi服务定位器 [英] Delphi service locator
问题描述
就像我以前在Java中一样,我尝试在Delphi中做一个ServiceLocator.存在一些代码,但无法按预期工作.
As I had before in Java, I try to do a ServiceLocator in Delphi. Some code exist but it's didn't work like expected.
我不希望遇到枚举之类的问题,我想要一个在创建新类时不必接触的代码.
I don't want a case with enum or anything else, I want a code that I don't have to touch when I create a new class.
我有一个用于我的应用程序的全局接口,其他所有接口:
I have a global interface for my application, and all the other :
type
IMyApp = interface
end;
IBuilder = interface(IMyApp)
procedure Build;
end;
IPrint = interface(IMyApp)
procedure Print;
end;
ICalculator = interface(IMyApp)
procedure Calc;
end;
我想要一个这样的类,在该类中,我直接通过接口创建实现,并且通过找到对象来创建对象(也许使用RTTI吗?):
I want a class like that, where I create the implementation directly by the interface, and that the object is create by find it (maybe with RTTI ?) :
class function TServiceLocator.Get(aInterface: IMyApp): IMyApp;
var
C : TRttiContext;
T : TRttiInstanceType;
V : TValue;
ClassNameToCreate: string;
begin
// Ex: TBuilder (Replace I by T)
ClassNameToCreate := 'T' + Copy(aInterface.GetName, 1, aInterface.GetName.Length);
T := (C.FindType(ClassNameToCreate) as TRttiInstanceType);
Result := V as IMyApp;
end;
var
b: IBuilder;
begin
b := TServiceLocator.Get(IBuilder);
b.Build;
end.
推荐答案
使用然后您可以使用 IMyApp
约束只能指定 IMyApp
及其子代.您可以使用参数的RTTI(通过 TypeInfo().Name
)获得请求的接口类型名称.
You can then use an IMyApp
constraint so that only IMyApp
and descendants can be specified. You can get the requested interface type name using the parameter's RTTI (via TypeInfo().Name
).
您还必须定义一个带有虚拟构造函数的基类,以派生您的接口实现类.这样,您就可以根据从 TRttiContext.FindType()
获得的类类型创建一些具体的东西.您不能仅从 TRttiType
实例化一个类对象(请参阅如何从其TRttiType实例化一个类)?).
You will also have to define a base class with a virtual constructor for your interface implementation classes to derive from. That way, you have something concrete that you can create from the class type you get from TRttiContext.FindType()
. You can't instantiate a class object from just a TRttiType
alone (see How do I instantiate a class from its TRttiType?).
例如,尝试如下操作:
type
IMyApp = interface
['{3E8332C3-8C23-481A-9609-8982B66E840A}']
end;
TMyAppBase = class(TInterfacedObject, IMyApp)
public
constructor Create; virtual;
end;
TMyAppBaseClass = class of TMyAppBase;
TServiceLocator = class
public
class function Get<T: IMyApp>(): T;
end;
...
constructor TMyAppBase.Create;
begin
inherited Create;
end;
class function TServiceLocator.Get<T: IMyApp>(): T;
var
ClassNameToCreate: string;
Ctx : TRttiContext;
Typ : TRttiInstanceType;
Cls: TClass;
begin
Result := nil;
// Ex: TBuilder (Replace I by T)
ClassNameToCreate := 'T' + Copy(TypeInfo(T).Name, 2, MaxInt);
Typ := Ctx.FindType(ClassNameToCreate);
if not ((Typ <> nil) and Typ.IsInstance) then
Exit; // or raise...
Cls := Typ.AsInstance.MetaclassType;
if not Cls.InheritsFrom(TMyAppBase) then
Exit; // or raise...
Result := TMyAppBaseClass(Cls).Create as T;
end;
然后您可以执行以下操作:
Then you can do this:
type
IBuilder = interface(IMyApp)
['{350FA31A-ECA5-4419-BAB5-5D2519B8BF03}']
procedure Build;
end;
IPrint = interface(IMyApp)
['{F726FDDE-A26E-4D0D-BB48-0F639EE34189}']
procedure Print;
end;
ICalculator = interface(IMyApp)
['{27E3836B-05B6-4C0B-ABED-C62E6BE194F2}']
procedure Calc;
end;
TBuilder = class(TMyAppBase, IBuilder)
public
constructor Create; override; // if needed
procedure Build;
end;
TPrint = class(TMyAppBase, IPrint)
public
constructor Create; override; // if needed
procedure Print;
end;
TCalculator = class(TMyAppBase, ICalculator)
public
constructor Create; override; // if needed
procedure Calc;
end;
...
constructor TBuilder.Create;
begin
inherited Create;
...
end;
procedure TBuilder.Build;
begin
...
end;
constructor TPrint.Create;
begin
inherited Create;
...
end;
procedure TPrint.Print;
begin
...
end;
constructor TCalculator.Create;
begin
inherited Create;
...
end;
procedure TCalculator.Calc;
begin
...
end;
var
b: IBuilder;
begin
b := TServiceLocator.Get<IBuilder>();
b.Build;
end.
这篇关于Delphi服务定位器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!