【问题标题】:Is it sometimes okay to use service locator pattern in a domain class?有时可以在域类中使用服务定位器模式吗?
【发布时间】:2012-03-21 14:38:19
【问题描述】:

这个问题可能更适合程序员堆栈。如果是这样,我会移动它。不过我想我可能会在这里得到更多答案。

到目前为止,我的域中的所有接口依赖项都是使用来自执行程序集的 DI 解决的,该程序集目前是一个 .NET MVC3 项目(+ Unity IoC 容器)。但是,我遇到了一种情况,我认为服务定位器可能是更好的选择。

域中有一个实体存储(缓存)来自 URL 的内容。具体来说,它存储来自元数据 URL 的 SAML2 EntityDescriptor XML。我有一个带有单一方法的接口 IConsumeHttp:

public interface IConsumeHttp
{
    string Get(string url);
}

当前实现使用 System.Net 中的静态 WebRequest 类:

public class WebRequestHttpConsumer : IConsumeHttp
{
    public string Get(string url)
    {
        string content = null;
        var request = WebRequest.Create(url);
        var response = request.GetResponse();
        var stream = response.GetResponseStream();
        if (stream != null)
        {
            var reader = new StreamReader(stream);
            content = reader.ReadToEnd();
            reader.Close();
            stream.Close();
        }
        response.Close();
        return content;
    }
}

缓存 XML 内容的实体在更大的实体聚合中作为非根存在。对于聚合的其余部分,我正在实现一个有点大的 Facade 模式,它是 MVC 控制器的公共端点。我可以像这样在外观构造函数中注入 IConsumeHttp 依赖项:

public AnAggregateFacade(IDataContext dataContext, IConsumeHttp httpClient)
{
    ...

我看到的问题是外观中只有一个方法依赖于这个接口,所以为整个外观注入它似乎很愚蠢。 WebRequestHttpConsumer 类的对象创建不应该增加很多开销,但是域没有意识到这一点。

我正在考虑将实体的所有缓存逻辑移出到单独的静态工厂类中。不过,代码将取决于IConsumeHttp。所以我正在考虑在静态工厂方法中使用静态服务定位器来解析 IConsumeHttp,但前提是需要初始化或刷新缓存的 XML。

我的问题:这是个坏主意吗?在我看来,确保适当缓存 XML 元数据应该是域的责任。作为其他相关操作的一部分(例如获取 SAML Authn 请求和响应的元数据、更新 SAML EntityID 或元数据 URL 等),域会定期执行此操作。还是我太担心了?

【问题讨论】:

  • IMO 这是一个对 SO 有效的问题。
  • @Steven 感谢您提供的链接、信任投票以及您关于如何使用架构的查询 + 命令方面的博客。非常有趣的东西。

标签: caching dependency-injection httpwebrequest domain-driven-design service-locator


【解决方案1】:

在我看来确实应该是域的责任 确保适当缓存 XML 元数据

我不确定,除非您的域真的是关于元数据操作、http 请求等。对于具有非技术领域的“普通”应用程序,我宁愿在基础设施/技术服务层处理缓存问题。

我看到的问题是外观中只有一个方法具有 依赖于这个接口,所以注入它似乎很愚蠢 整个立面

显然,Facades 通常不适合构造函数注入,因为它们自然倾向于指向许多依赖项。您可以考虑其他类型的注入,或者正如您所指出的,使用定位器。但是我个人会问自己一个 Facade 是否真的合适,并考虑在我的所有控制器中使用更细粒度的对象而不是相同的大接口。这将允许更多的模块化和临时注入,而不是预先膨胀一个巨大的对象。

但这可能只是因为我不是 Facade 的忠实粉丝 ;)

【讨论】:

  • 感谢您的意见。该域与 HTTP 无关,并且不引用 System.Web、MVC 或任何类似的 dll,这就是我将 HttpConsumer 包装在接口中的原因。这是在域中使用它的唯一情况。控制器处理 SAML http 事物并将元数据用于操作,例如发送 Authn 请求。让控制器确保域具有正确的 XML 似乎过于细化,给客户端太多责任。域已经知道 URL,并且可以自己执行此操作。不过,您确实有一点,我正在研究其他模式。
【解决方案2】:

在您对@ian31 的评论中,您提到“让控制器确保域具有正确的 XML 似乎过于细化,给客户端太多责任”。出于这个原因,我更希望控制器向其服务/存储库(可以实现缓存层)询问正确且当前的 XML。对我来说,这个责任对领域实体有很多要求。

但是,如果您对所概述的职责感到满意,并且您提到创建对象的开销并不大,我认为将 IConsumeHttp 留在实体中就可以了。
坚持这个责任,另一种方法可能是将这个接口向下移动到一个子实体中。如果这对您的情况是可能的,那么至少依赖关系仅限于需要它的场景。

【讨论】:

  • 感谢您的回答,抱歉回复晚了。在这个项目中,没有服务层。 MVC 项目使用工厂和外观模式直接访问域表面。 IConsumeHttp 依赖项不在域实体上,它在另一个域类上。最终,元数据存储在域实体属性上,但它不是执行 HTTP 查找的实体。另外,当我说“缓存”时,我并不是指使用内存缓存。我的意思是 XML 内容存储在一个实体上,并使用元数据 URL 定期刷新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
  • 1970-01-01
相关资源
最近更新 更多