使用 IoC(C) 的 Factory 的简单示例
工厂也可以与控制反转(IoC)库一起使用。
- 这种工厂的典型用例是当我们想要基于运行时未知的参数(例如当前用户)创建对象时。
- 在这些情况下,有时很难(如果不是不可能)配置 IoC 库来处理这种运行时上下文信息,因此我们可以将其包装在工厂中。
例
- 假设我们有一个
User
类,其特征(ID,安全许可级别等)在运行时是未知的(因为当前用户可能是使用该应用程序的任何人)。 - 我们需要获取当前用户并为他们获取
ISecurityToken
,然后可以使用它来检查是否允许用户执行某些操作。 - ISecurityToken 的实现将根据用户的级别而变化 - 换句话说,ISecurityToken 使用多态。
在这种情况下,我们有两个实现,它们也使用标记接口,以便更容易地将它们识别到 IoC 库中; 在这种情况下,IoC 库只是由抽象 IContainer
组成和识别。
另请注意,许多现代 IoC 工厂都具有本机功能或插件,允许自动创建工厂,并且无需标记接口,如下所示; 然而,由于并非所有人都这样做,这个例子迎合了一个简单,最低级的功能概念。
//describes the ability to allow or deny an action based on PerformAction.SecurityLevel
public interface ISecurityToken
{
public bool IsAllowedTo(PerformAction action);
}
//Marker interface for Basic permissions
public interface IBasicToken:ISecurityToken{};
//Marker interface for super permissions
public interface ISuperToken:ISecurityToken{};
//since IBasictoken inherits ISecurityToken, BasicToken can be treated as an ISecurityToken
public class BasicToken:IBasicToken
{
public bool IsAllowedTo(PerformAction action)
{
//Basic users can only perform basic actions
if(action.SecurityLevel!=SecurityLevel.Basic) return false;
return true;
}
}
public class SuperToken:ISuperToken
{
public bool IsAllowedTo(PerformAction action)
{
//Super users can perform all actions
return true;
}
}
接下来我们将创建一个 SecurityToken
工厂,它将作为我们的 IContainer
的依赖
public class SecurityTokenFactory
{
readonly IContainer _container;
public SecurityTokenFactory(IContainer container)
{
if(container==null) throw new ArgumentNullException("container");
}
public ISecurityToken GetToken(User user)
{
if (user==null) throw new ArgumentNullException("user);
//depending on the user security level, we return a different type; however all types implement ISecurityToken so the factory can produce them.
switch user.SecurityLevel
{
case Basic:
return _container.GetInstance<BasicSecurityToken>();
case SuperUser:
return _container.GetInstance<SuperUserToken>();
}
}
}
一旦我们用 IContainer
注册了这些:
IContainer.For<SecurityTokenFactory>().Use<SecurityTokenFactory>().Singleton(); //we only need a single instance per app
IContainer.For<IBasicToken>().Use<BasicToken>().PerRequest(); //we need an instance per-request
IContainer.For<ISuperToken>().Use<SuperToken>().PerRequest();//we need an instance per-request
消费代码可以使用它在运行时获取正确的令牌:
readonly SecurityTokenFactory _tokenFactory;
...
...
public void LogIn(User user)
{
var token = _tokenFactory.GetToken(user);
user.SetSecurityToken(token);
}
通过这种方式,我们可以从工厂提供的封装以及 IoC 库提供的生命周期管理中受益。