如何将Interfaced参数传递给Spring4D?

时间:2016-06-27 20:51:53

标签: delphi dependency-injection spring4d

我有以下例子 是否有更简单的方法来传递已经为Container注册的Interfaced变量来解决它? 或者,是否有其他方法可以使用此功能?


这是我的界面

    IString = interface
      function Value: string;  
    end;  

    IUser = interface
      function Name: IString;
    end;

    ILogin = interface
      function User: IUser;
      function Password: IString;
    end;

类实现

    TString = class(TInterfacedObject, IString)
    private
      FValue: String;
    public
      constructor Create(const AValue: String);
      function Value: String;
    end;

    TUser = class(TInterfacedObject, IUser)
    private
      FName: IString;
    public
      constructor Create(const AName: IString);
      function Name: IString;
    end;

    TLogin = class(TInterfacedObject, ILogin)
    private
      FUser: IUser;
      FPassword: IString;
    public
      constructor Create(const AUser: IUser; const APassword: IString);
      function User: IUser;
      function Password: IString;
    end;

在容器上注册

    GlobalContainer.RegisterType<TString>.Implements<IString>;
    GlobalContainer.RegisterType<TUser>.Implements<IUser>;
    GlobalContainer.RegisterType<TLogin>.Implements<ILogin>;

调用
因此,当我必须创建这些接口时,我会这样调用,这个嵌套参数会使代码变得复杂而耗尽阅读(并看到)

    GlobalContainer.Resolve<ILogin>([
      TValue.From(
        GlobalContainer.Resolve<IUser>([
          TValue.From(
            GlobalContainer.Resolve<IString>(['UserName'])
          )
        ])
      ),
      TValue.From(
        GlobalContainer.Resolve<IString>(['SuperSecretPassword'])
      )
    ]);

2 个答案:

答案 0 :(得分:3)

首先,这有点像Service Locator anti pattern - 你应该使用工厂。

当前构造需要有关对象图的知识,并将两个不同的值传递给相同的类型。工厂非常适合的东西。

因此,不仅仅是在消费者代码中使用解决方案调用替换ctor调用(尽可能避免使用),您可以为您的案例注册工厂:

std::istream& operator>>(std::istream &in,  someclass &x)
{
    in>>x.a;
    return in;
}

int main()
{
  someclass test;
 std::cin>>test;
 return 0;
}

然后应将此type ILoginFactory = interface [some guid] function CreateLogin(const userName, password: string): ILogin; end; TLoginFactory = class(TInterfacedObject, ILoginFactory) function CreateLogin(const username, password: string): ILogin; end; function TLoginFactory.CreateLogin(const username, password: string): ILogin; begin // can also inject the container to the factory and use resolve here - // but doing it the pure DI way for now because the graph to create is simple Result := TLogin.Create( TUser.Create( TString.Create(username)), TString.Create(password)); end; 注入当前具有ILoginFactory调用的类中。这也有助于提升composition root

答案 1 :(得分:0)

我找到了一种方法让电话更容易 也许我没有以正确的方式做到这一点。但它使调用更简单。

我创建了一个帮助类

    TContainerHelper = class helper for TContainer
    public
      ResolveAsTValue<T>: TValue; overload;
      ResolveAsTValue<T>(name: string): TValue; overload;
      ResolveAsTValue<T>(arguments: array of TValue): TValue; overload;
      ResolveAsTValue<T>(name: string;arguments: array of TValue): TValue; overload; 
    end;

现在当我需要解决一个依赖于另一个的接口时,我只是:

    GlobalContainer.Resolve<ILogin>([
      GlobalContainer.ResolveAsTValue<IUser>([
        GlobalContainer.ResolveAsTValue<IString>(['UserName'])
      ]),
      GlobalContainer.ResolveAsTValue<IString>(['SuperSecretPassword'])
    ]);
相关问题