Factory Summary and Runtime Inversion Control

I have the following class and interface structure, and I have a hard time trying to get the code to do what I need.

public interface IUserManager
{
    int Add(User user);
}

public class UserManagerA : IUserManager{}
public class UserManagerB : IUserManager{}

In this example, I use Ninject as an IoC container, but I am open to changing it if any other container solves the problem:

This is inside of mine NinjectWebCommon.cs:

void RegisterServices(IKernel kernel)
{
    string userRole = CurrentUser.Role;//this gets the user logged in
    //This is the part I do not how to do
    //I wish I could just type this in:
    kernel.Bind<IUserManager>().To<UserManagerA>()
        .When(userRole == "RoleA"); // this doesn't work obviously
    kernel.Bind<IUserManager>().To<UserManagerB>()
        .When(userRole == "RoleB"); // same doesn't work
}

All this so that in my (MVC) controller I can do this:

public class UserController
{
    private readonly IUserManager _userManager;
    public UserController(IUserManager userManager)
    {
        _userManager = userManager;
    }
    public ActionResult Add(User user)
    {
        //this would call the correct manager
        //based on the userRole
        _userManager.Add(user);
    }
}

I read articles about abstract Factory, but did not find one that explains how to integrate Factory with the IoC container and pass the parameter received at runtime to allow implementations.

+4
2

IUserManager ( 100 ), UserManager , .

-, IUserManager .

public interface IUserManager
{
    int Add(User user);
    bool AppliesTo(string userRole);
}

public class UserManagerA : IUserManager
{
    // Add method omitted

    public bool AppliesTo(string userRole)
    {
        // Note that it is entirely possible to 
        // make this work with multiple roles and/or
        // multiple conditions.
        return (userRole == "RoleA");
    }
}

public class UserManagerB : IUserManager
{
    // Add method omitted

    public bool AppliesTo(string userRole)
    {
        return (userRole == "RoleB");
    }
}

, userRole. IUserManager DI, .

public interface IUserManagerStrategy
{
    IUserManager GetManager(string userRole);
}

public class UserManagerStrategy
    : IUserManagerStrategy
{
    private readonly IUserManager[] userManagers;

    public UserManagerStrategy(IUserManager[] userManagers)
    {
        if (userManagers == null)
            throw new ArgumentNullException("userManagers");

        this.userManagers = userManagers;
    }

    public IUserManager GetManager(string userRole)
    {
        var manager = this.userManagers.FirstOrDefault(x => x.AppliesTo(userRole));
        if (manager == null && !string.IsNullOrEmpty(userRole))
        {
            // Note that you could optionally specify a default value
            // here instead of throwing an exception.
            throw new Exception(string.Format("User Manager for {0} not found", userRole));
        }

        return manager;
    }
}

public class SomeService : ISomeService
{
    private readonly IUserManagerStrategy userManagerStrategy;

    public SomeService(IUserManagerStrategy userManagerStrategy)
    {
        if (userManagerStrategy == null)
            throw new ArgumentNullException("userManagerStrategy");
        this.userManagerStrategy = userManagerStrategy;
    }

    public void DoSomething()
    {
        string userRole = CurrentUser.Role;//this gets the user logged in

        // Get the correct UserManger according to the role
        IUserManager userManager = this.userManagerStrategy.GetManger(userRole);

        // Do something with userManger
    }
}

void RegisterServices(IKernel kernel)
{
    kernel.Bind<IUserManager>().To<UserManagerA>();
    kernel.Bind<IUserManager>().To<UserManagerB>();

    // Ninject will automatically supply both IUserManager instances here
    kernel.Bind<IUserManagerStrategy>().To<UserManagerStrategy>();

    kernel.Bind<ISomeService>().To<SomeService>();
}

, . .

, case switch, , UserManager. UserManager UserManager , , DI.

, , DI .

CurrentUserProvider RagtimeWilly , .

: StructureMap

+2

, UserManager, :

public class UserManagerProvider : IUserManagerProvider
{
    private readonly IContext _context;

    public UserManagerProvider(IContext context)
    {
        _context = context;
    }

    public IUserManager Create(User currentUser)
    {
        if (currentUser.Role == "User A")
            return _context.Kernel.Get<UserManagerA>();

        if (currentUser.Role == "User B")
            return _context.Kernel.Get<UserManagerB>();

        // Or bind and resolve by name
        // _context.Kernel.Get<IUserManager>(currentUser.Role);
    }
}

:

private readonly IUserManager _userManager;

public UserController(IUserManagerProvider userManagerProvider)
{
    _userManager = userManagerProvider.Create(CurrentUser);
}

, , , CurrentUserProvider . , unit test, , :

private readonly IUserManager _userManager;
private readonly User _currentUser;

public UserController(IUserManagerProvider userManagerProvider, ICurrentUserProvider currentUserProvider)
{
    _currentUser = currentUserProvider.GetUser();
    _userManager = userManagerProvider.Create(_currentUser);
}
+5

All Articles