8

我正在使用 MVC3、Entity Framework v4.3 Code First 和 SimpleInjector。我有几个看起来像这样的简单类:

public class SomeThing
{
    public int Id { get; set; }
    public string Name { get; set; }
}

我有另一个看起来像这样的实体:

public class MainClass
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual AThing AThingy { get; set; }
    public virtual BThing BThingy { get; set; }
    public virtual CThing CThingy { get; set; }
    public virtual DThing DThingy { get; set; }
    public virtual EThing EThingy { get; set; }
}

每个 Thingy(当前)都有自己的 Manager 类,如下所示:

public class SomeThingManager
{
    private readonly IMyRepository<SomeThing> MyRepository;

    public SomeThingManager(IMyRepository<SomeThing> myRepository)
    {
        MyRepository = myRepository;
    }
} 

因此,我的 MainController 如下:

public class MainController
{
    private readonly IMainManager MainManager;
    private readonly IAThingManager AThingManager;
    private readonly IBThingManager BThingManager;
    private readonly ICThingManager CThingManager;
    private readonly IDThingManager DThingManager;
    private readonly IEThingManager EThingManager;

    public MainController(IMainManager mainManager, IAThingManager aThingManager, IBThingManager bThingManager, ICThingManager cThingManager, IDThingManager dThingManager, IEThingManager eThingManager)
    {
        MainManager = mainManager;
        AThingManager = aThingManager;
        BThingManager = bThingManager;
        CThingManager = cThingManager;
        DThingManager = dThingManager;
        EThingManager = eThingManager;
    }

    ...various ActionMethods...
}

实际上,这个控制器中注入的依赖项是原来的两倍。它闻起来臭臭的。当您还知道存在具有所有或大部分相同依赖项的 OtherController 时,气味会更糟。我想重构它。

我已经对 DI 有足够的了解,知道属性注入和服务定位器不是好主意。

我无法拆分我的 MainController,因为它是一个单一的屏幕,需要通过单击一个保存按钮来显示和编辑所有这些内容。换句话说,单个 post 操作方法可以保存所有内容(尽管我愿意更改它,只要它仍然是单个 Save 按钮)。这个屏幕是用 Knockoutjs 构建的,如果有影响的话,它会用 Ajax 帖子保存。

我幽默地使用了环境上下文,但我并不肯定这是正确的方法。我也幽默地使用了注入 Facade。我也想知道我是否应该在这一点上实现一个命令架构。(以上所有内容不只是将气味转移到其他地方吗?)

最后,也许独立于上述三种方法,我是否应该使用一个具有显式方法的 LookupManager,例如 GetAThings()、GetAThing(id)、GetBThings()、GetBThing(id) 等?(但是那个 LookupManager 需要注入几个存储库,或者一种新型的存储库。)

除了我的想法之外,我的问题是,重申一下:重构此代码以减少注入依赖项的疯狂数量的好方法是什么?

4

3 回答 3

4

您是否考虑过使用工作单元设计模式?关于什么是工作单元,有一篇很棒的 MSDN帖子。那篇文章的摘录:

在某种程度上,您可以将工作单元视为转储所有事务处理代码的地方。工作单位的职责是:

  • 管理交易。
  • 对数据库的插入、删除和更新进行排序。
  • 防止重复更新。在 Unit of Work 对象的单一用法中,代码的不同部分可能会将同一个 Invoice
    对象标记为已更改,但 Unit of Work 类只会
    向数据库发出单个 UPDATE 命令。

使用工作单元模式的价值在于将其余代码从这些问题中解放出来,这样您就可以专注于业务逻辑。

有几篇关于这个的博客文章,但我发现的最好的一篇关于如何实现它是here。还有一些其他的已经从这个网站herehere中提到过。

最后,也许独立于上述三种方法,我是否应该使用一个具有显式方法的 LookupManager,例如 GetAThings()、GetAThing(id)、GetBThings()、GetBThing(id) 等?(但是那个 LookupManager 需要注入几个存储库,或者一种新型的存储库。)

工作单元将能够处理所有这些,特别是如果您能够为大多数数据库处理需求实现通用存储库。您的标签提到您正在使用 Entity Framework 4.3 对吗?

希望这可以帮助!

于 2012-08-21T01:04:44.107 回答
4

使用命令架构是一个好主意,因为这会将所有业务逻辑移出控制器,并允许您添加横切关注点而无需更改代码。但是,这不会解决您的构造函数过度注入问题。标准解决方案是将相关依赖项移动到聚合服务中。但是,我同意 Mark 的观点,您应该看看unit of work pattern

于 2012-08-21T07:32:10.077 回答
0

我认为您的主要问题是抽象层太多。您正在使用实体框架,因此您已经有一个围绕数据的抽象层,通过存储库和管理器接口添加了另外两个层(每个实体一个),这导致您的控制器依赖于大量接口。它并没有增加很多价值,此外还有YAGNI

我会重构,摆脱你的存储库和管理层,并使用“环境上下文”。

然后,查看您的控制器向管理器层询问的查询类型。在这些非常简单的地方,我认为直接在控制器中查询“环境上下文”没有问题——这就是我要做的。在它们更复杂的地方,将其重构为一个新界面,对事物进行逻辑分组(不一定每个实体一个)并为此使用您的 IOC。

于 2012-08-21T01:11:52.677 回答