我正在使用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;
}
}
我的主控制器因此如下:
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,因为它是一个单一的屏幕,只需单击一个Save按钮就可以显示和编辑所有这些内容。换句话说,一个post post方法可以保存所有内容(尽管如果它有意义,我可以更改它,只要它仍然是一个Save按钮)。这个屏幕是使用Knockoutjs构建的,如果有所不同,可以使用Ajax帖子进行保存。
我很幽默使用环境语境,但我不肯定这是正确的方法。 我也很乐意使用注入Facade。 我也想知道我是否应该在此时实现Command架构。 (难道上面的所有这些都不会把气味移到其他地方吗?)
最后,并且可能独立于上述三种方法,我应该使用像GetAThings(),GetAThing(id),GetBThings(),GetBThing(id)等显式方法来使用LookupManager。 ? (但是那个LookupManager需要注入几个存储库,或者是一种新类型的存储库。)
除了我的想法之外,我的问题是,重申:重构这段代码以减少注入依赖项的疯狂数量有什么好方法?
答案 0 :(得分:4)
您是否考虑过使用工作单元设计模式?关于工作单位是a great MSDN的帖子。该文摘录:
在某种程度上,您可以将工作单元视为转储所有内容的地方 交易处理代码。工作单位的职责 是:
- 管理交易。
- 订购数据库插入,删除和更新。
- 防止重复更新。在单个使用工作单元对象内部,代码的不同部分可以标记相同的发票
对象已更改,但工作单元类只会发出一个
单个UPDATE命令到数据库。使用工作单元模式的价值在于释放你的其余部分 来自这些问题的代码,以便您可以专注于 商业逻辑。
有几篇关于此的博文,但我发现的最好的一篇是here。此网站here和here引用了其他一些内容。
最后,也许独立于上述三种方法,是 我应该用一个单独的,例如,LookupManager显式 GetAThings(),GetAThing(id),GetBThings(),GetBThing(id)等方法, 等等? (但那LookupManager需要几个 注入其中的存储库或新类型的存储库。)
工作单元将能够处理所有这些,特别是如果您能够为大多数数据库处理需求实现通用存储库。您的标记提到您正在使用Entity Framework 4.3吗?
希望这有帮助!
答案 1 :(得分:3)
使用command architecture是一个好主意,因为这会将所有业务逻辑移出控制器,并允许您在不更改代码的情况下添加cross-cutting concerns。但是,这不会解决您constructor over-injection的问题。标准解决方案是将相关的依赖项移动到aggregate service。但是,我同意Mark的观点,你应该看一下unit of work pattern。
答案 2 :(得分:0)
我认为你的主要问题是抽象层次太多。您正在使用Entity Framework,因此您已经拥有了一个围绕数据的抽象层,通过Repository添加了两个层(每个实体一个),而Manager接口导致了控制器所依赖的大量接口。它并没有增加很多价值,此外还有YAGNI。
我会重构,删除你的存储库和管理器层,并使用'环境上下文'。
然后,查看控制器询问管理器层的查询类型。在这些非常简单的地方,我发现在控制器中直接查询“环境上下文”没有问题 - 这就是我要做的。在它们更复杂的地方,将它重构为一个新的界面,逻辑分组(不一定是每个实体一个)并使用你的IOC。