使用 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 库提供的生命周期管理中受益。