1

请在以下情况下纠正我。(问题在最后)

(我问了一个类似的问题,没有组织,投票结束。所以我把这里的问题总结成一个可以用准确答案回答的范围。)

我正在使用 nhibernate 作为 ORM 开发具有多个层的 Web 应用程序。我的层结构如下

  1. 模型层
  2. 存储层
  3. 服务层
  4. 界面层

有了上面的层,类和接口放置如下。

ProductController.cs(用户界面层)

public class ProductController : Controller
{
    ProductServices _ProductServices;
    NHibernate.ISession _Session;

    public ProductController()
    {
        _Session = SessionManager.GetCurrentSession();

        _ProductServices = new ProductServices(
            new ProductRepository(), _Session);
    }
    // Cont..
 }

ProductServices.cs(服务层)

public class ProductServices : IProductServices
{
    protected IProductRepository _ProductRepository;
    protected NHibernate.ISession _Session;

    public ProductServices(IProductRepository productRepository,
        NHibernate.ISession session)
    {
        _ProductRepository = productRepository;
        _Session = session;
        _ProductRepository.SetSession(_Session);
    }

    // cont...
}

ProductRepository.cs(存储库层)

public class ProductRepository : IProductRepository
{
    NHibernate.ISession _Session;

    public void SetSession(NHibernate.ISession session)
    {
        _Session = session;
    }

    public IEnumerable<Product> FindAll()
    {
        return _Session.CreateCriteria<Product>().List<Product>();
    }

    //cont..
}

在 UI 层,我将会话创建为每个会话的请求,并在类构造函数的帮助下注入服务层。然后借助方法设置存储库的会话。

恐怕如果我将 _Session 作为构造函数直接传递给存储库,我将无法在服务层下控制它。还有一个使用web服务层的未来扩展计划。

** 有没有办法确保在_Session已经设置的 ProductRepository 类的每个方法中,无需在每个方法中编写代码if(_Session==null),因为它重复相同的代码。

**如果上述模式是错误的,请告诉我实现这一目标的正确方法。

4

2 回答 2

5

你的所作所为让我有点吃惊。您在中应用构造函数注入模式ProductService,这绝对是要走的路。另一方面,您并没有将依赖项注入到 中ProductController,而是该类通过静态类(这是服务定位器反模式)请求其中一个依赖项并ProductServices自己创建一个类。ProductServices这使得该类难以测试,并且使您的应用程序的灵活性和可维护性降低,因为当它在多个地方使用时,您无法轻松更改、装饰或拦截该类的使用。

尽管您(正确地)对 中的依赖项使用构造函数注入,但ProductServices您将这些依赖项传递到产品存储库,而不是在 中应用构造函数注入模式ProductResopistory

请告诉我实现这一目标的正确方法。

正确的方法是在任何地方都应用构造函数注入模式。执行此操作时,您的代码将开始如下所示:

public class ProductController : Controller
{
    private ProductServices _ProductServices;

    public ProductController(ProductServices services)
    {
        _ProductServices = services;
    }
    // Cont..
 }

public class ProductServices : IProductServices
{
    private IProductRepository _ProductRepository;

    public ProductServices(
        IProductRepository productRepository)
    {
        _ProductRepository = productRepository;
    }
    // cont...
}

public class ProductRepository : IProductRepository
{
    private ISession _Session;

    public ProductRepository (ISession session)
    {
        _Session = session;
    }

    public IEnumerable<Product> FindAll()
    {
        return _Session
            .CreateCriteria<Product>().List<Product>();
    }
    //cont..
}

看看每个类如何只接受它自己使用的依赖项。所以ProductControllerandProductServices不依赖于(我做了只需要ISession的假设)。看看 - 从一个班级的角度来看 - 现在一切都变得简单多了?ProductRepoistoryISession

我们真的在这里解决了一个问题吗?似乎我们只是将所有类连接在一起的问题移到了依赖图上。是的,我们确实解决了问题。这是一件好事。现在每个类都可以单独测试,更容易遵循,整个应用程序更易于维护。

然而,在应用程序的某个地方,ProductController必须创建一个。这可能看起来像这样:

new ProductController(
    new ProductServices(
        new ProductRepository(
            SessionManager.GetCurrentSession())));

在其正常配置中,ASP.NET MVC 将为您创建控制器类,并且它需要一个默认构造函数来执行此操作。如果你想使用构造函数注入来连接控制器(你绝对应该这样做),你需要做一些“特殊”的事情来让它工作。

ASP.NET MVC 允许您覆盖默认ControllerFactory类。这使您可以决定如何创建控制器实例。但是,当您的应用程序开始增长时,当您手动创建依赖关系图时,它会很快变得非常尴尬(正如我的最后一个示例所示)。在这种情况下,使用依赖注入框架会更好。它们中的大多数包含一个功能/包,允许您将其与 ASP.NET MVC 集成并自动允许在您的 MVC 控制器上使用构造函数注入。

我们完成了吗?嗯......我们曾经吗?你的设计中有一件事在我的脑海中触发了一个标志。您的系统包含一个名为ProductServices. 虽然是一个疯狂的猜测,但这个名称Services似乎将所有与产品相关的业务操作都包含在该类中。根据系统的大小、团队中的人数以及需要进行的更改量,这可能会出现问题。例如,您如何有效地应用横切关注点(例如日志记录、验证、分析、事务管理、容错改进)以使系统保持可维护性?

So instead of wrapping all operations in a single ProductServices class, try giving each business transaction / use case its own class and apply the same (generic) interface to all those classes. This description might be a bit vague, but it is a great way to improve the maintainability of small and big systems. You can read more about that here.

于 2013-01-07T10:24:43.800 回答
0

您可以使用诸如 Autofac 之类的依赖注入容器来实例化您的会话并管理它的生命周期。将会话实例化的责任留给 Autofac,只需将 ISession 接口注入到任何需要依赖项的类中。看看这篇文章:使用 Autofac 管理 NHibernate ISession

您还会发现此 wiki 页面对使用 MVC3 配置 Autofac 很有用:http ://code.google.com/p/autofac/wiki/MvcIntegration3

于 2013-01-07T08:16:56.050 回答