依赖注入和工厂模式

6

试图找出如何最好地处理以下场景:

假设有一个RequestContext类,它依赖于一个外部服务,例如:

public class RequestContext : IRequestContext
{
    private readonly ServiceFactory<IWeatherService> _weatherService;

    public RequestContext(ServiceFactory<IWeatherService> weatherService, UserLocation location, string query)
    {
       _weatherService = weatherService;
       ...

我需要在最终实例化RequestContext的类中引用哪种依赖项?它可以是ServiceFactory<IWeatherService>,但那似乎不太对,或者我可以按照以下方式创建一个IRequestContextFactory

public class RequestContextFactory : IRequestContextFactory
{
    private readonly ServiceFactory<IWeatherService> _weatherService;

    public RequestContextFactory(ServiceFactory<IWeatherService> weatherService)
    {
        _weatherService = weatherService;
    }

    public RequestContext Create(UserLocation location, string query)
    {
        return new RequestContext(_weatherService, location, query);
    }
}

然后通过构造函数注入传递IRequestContextFactory

这似乎是一个不错的方法,但这种方法的问题在于我认为它会阻碍发现(开发人员必须知道工厂并实现它,这并不明显)。

是否有更好/更易发现的方法我可能错过了?

2个回答

5
松散耦合的美妙之处在于我们可以不断地隐藏以前的细节。
从IRequestContext的消费者的角度来看,RequestContext及其依赖关系的存在纯粹是一种实现细节。由于Liskov替换原则,消费者只能处理IRequestContext。
public class MyClass
{
    private readonly IRequestContext reqCtx;

    public MyClass(IRequestContext reqCtx)
    {
        if (reqCtx == null)
        {
            throw new ArgumentNullException("reqCtx");
        }

        this.reqCtx = reqCtx;
    }

    // Implement using this.reqCtx...
}

只有在应用程序的组合根处,您需要最终将所有内容连接起来。以下是一个简单的DI方法的草图:

ServiceFactory<IWeatherService> weatherService =
    new ServiceFactory<IWeatherService>();
UserLocation location = new UserLocation;
string query = "foo";

IRequestContext reqCtx = new RequestContext(weatherService, location, query);

var mc = new MyClass(reqCtx);

有趣的是,我从未考虑过直接注入RequestContext,因为它的参数会因每个页面请求(ASP.NET MVC)而异。使用NInject来正确实例化类是否是一个好主意,通过查看查询字符串来获取实例?或者我应该配置NInject使用工厂返回一个实例,但在基本层面上只注入RequestContext? - andreialecu
我对Ninject还不够了解,无法回答关于具体细节的问题。但是,如果它不直接支持此功能,您可以始终使用注入到更高级别消费者中的抽象工厂自己实现这个小部分。 - Mark Seemann

0

工厂模式是一种众所周知、有文档记录和广泛使用的方法。 如果你很担心其他开发人员不了解这个模式,那么在代码的(xml)文档中放置wikipedia的工厂模式页面的链接。

此外,请确保您一致地命名您的工厂 - 微软似乎喜欢使用Provider后缀。


1
你知道为什么它们后缀为“Provider”吗?不要盲目地采用它,只是因为微软使用它。这可能是出于完全不同的原因。 - Steve Casey
4
http://msdn.microsoft.com/en-us/library/ms972319.aspx 表明他们使用 Provider 来指代扩展 ProviderBase 并使用 ASP.NET Provider 模型的类。仅在这些情况下,使用 Provider 后缀才是合适的。 - Steve Casey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接