Delphi服务定位器 [英] Delphi service locator

查看:74
本文介绍了Delphi服务定位器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

就像我以前在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆