抽象工厂和控制反转解决在运行时 [英] Abstract Factory and Inversion of Control resolve at runtime

查看:117
本文介绍了抽象工厂和控制反转解决在运行时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的类和接口的结构,我有一个很难试图获得code做什么,我需要的。

I have the following class and interface structure and I'm having 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{}

在这个例子中,我使用Ninject作为IoC容器,但我接受,如果一些其它容器解决问题更改它:

In this example I'm using Ninject as the IoC container but I'm open to changing it if some other container resolves the issue:

这是我里面的 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
}

所有这一切,使我在(MVC)控制器,我可以做到这一点:

All of that 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);
    }
}

我一直在阅读有关抽象工厂的文章,但还没有找到一个解释如何在出厂时IoC容器集成并通过在运行时获得的参数来解决实现。

I've been reading articles about Abstract Factory but haven't found one that explains how to integrate the factory with the IoC container and pass a parameter obtained at run-time to resolve the implementations.

推荐答案

提供的 IUserManager 实施的数量不是很多(可能不会达到100实现),你可以使用策略模式的组成过程中解决所有的UserManager实例,然后挑最好的实例在使用运行时。

Provided the number of IUserManager implementations is not very many (not likely to reach 100 implementations), you can use a Strategy Pattern to resolve all of your UserManager instances during composition and then pick the best instance for use at runtime.

首先,我们需要一种方法来映射 IUserManager 实现角色。

First, we need a way to map IUserManager implementations to roles.

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容器提供的。

Then we need a strategy class that simply picks the correct instance based on the userRole. The IUserManager instances are supplied by the DI container when the application is composed.

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>();
}

此方法不需要你到容器注入应用。有没有使用服务的位置。

This method doesn't require you to inject the container into the application. There is no service location being used.

请注意还存在,将在每次添加一个新的的UserManager 应用程序的时间进行修改,无需开关case语句。何时使用的逻辑的UserManager 的UserManager 实施工作的一部分,并在其中执行的逻辑顺序由DI配置决定。

Note also that there is no switch case statement that would have to be modified every time you add a new UserManager to the application. The logic of when to use a UserManager is part of the UserManager implementation and the order in which the logic is executed is determined by the DI configuration.

此外,这将不管您使用的DI容器的工作。

In addition, this will work regardless of which DI container you are using.

您可以与CurrentUserProvider从RagtimeWilly的回答一个干净的方式来获得用户角色到这何处使用的服务结合起来这一点。

You could combine this with the CurrentUserProvider from RagtimeWilly's answer for a clean way to get the user role into the service where this is used.

参考:<一href=\"http://stackoverflow.com/questions/1499442/best-way-to-use-structuremap-to-implement-strategy-pattern#1501517\">Best方式使用StructureMap实施策略模式

这篇关于抽象工厂和控制反转解决在运行时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆