我有下面的例子:
是否有更简单的方法来传递已经为容器注册的接口变量来解决它?
或者,是否有其他方法使用此功能?
这是我的接口
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'])
)
]);
首先,这有点像服务定位器反模式——你应该使用工厂。
当前构造需要了解对象图并将两个不同的值传递给相同的类型。这是工厂最适合做的事。
因此,与其在消费者代码中用resolve调用替换一个actor调用(这是你应该尽可能避免的),不如为你的案例注册一个factory:
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
调用的类中。这也有助于移动到合成根。
我找到了一种使呼叫更容易的方法。
也许我做得不对。但它使调用更简单。
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'])
]);