如何解决Delphi服务定位器
就像我以前在Java中一样,我尝试在Delphi中执行ServiceLocator。存在一些代码,但无法按预期工作。
我不希望遇到枚举或其他任何问题,我想要一个在创建新类时不必接触的代码。
我有一个用于我的应用程序的全局接口,其他所有接口:
type
IMyApp = interface
end;
IBuilder = interface(IMyApp)
procedure Build;
end;
IPrint = interface(IMyApp)
procedure Print;
end;
ICalculator = interface(IMyApp)
procedure Calc;
end;
我想要一个这样的类,在该类中,我直接通过接口创建实现,并且通过找到对象来创建对象(也许使用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.
解决方法
让TServiceLocator.Get()
使用Generic参数来代替普通函数参数。
然后可以使用IMyApp
constraint,以便仅指定IMyApp
和子孙。您可以使用参数的RTTI(通过TypeInfo().Name
)获得请求的接口类型名称。
您还必须定义一个带有虚拟构造函数的基类,以派生您的接口实现类。这样,您就可以根据从TRttiContext.FindType()
获得的类类型创建一些具体的东西。您不能仅从TRttiType
实例化类对象(请参见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;
然后您可以执行以下操作:
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.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。