1

我有以下示例。
有没有更简单的方法来传递已经为 Container 注册的接口变量来解决它?
或者,还有其他方法可以使用此功能吗?


那是我的界面

    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'])
      )
    ]);
4

2 回答 2

3

首先,这闻起来像Service Locator 反模式- 你应该使用工厂。

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

因此,您可以为您的案例注册一个工厂,而不是仅仅在消费者代码中用 resolve 调用替换 ctor 调用(您应该尽可能避免这种情况):

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应该将其注入当前具有GlobalContainer.Resolve调用的类中。这也有助于向上移动到组合根

于 2016-06-28T09:10:29.707 回答
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'])
    ]);
于 2016-06-28T14:38:13.213 回答