编辑
在我看来,您基本上有这些选项来减少这里的构造函数依赖计数:
- 拆分控制器
- 在两个接口前面添加层
- 切换到属性注入
- 服务定位器
#3 和 #4 被包括在内是为了很好的衡量,但它们显然并没有真正减少依赖计数,它们只是将它们隐藏在构造函数中。它们也有几个缺点,我认为服务定位器在大多数情况下尤其邪恶。
对于#1,如果您觉得您的构造函数实际上是在做两个以上的工作,并且您可以拆分的地方有一个干净的分离,我会这样做。但是,我从您的回复中假设您已经考虑过这一点,并且不想这样做。
剩下的#2 - 添加另一层。在这种情况下,将为该特定视图模型引入工厂接口。天真地,我将此命名为 ICreateTestplanViewModelFactory,但如果您愿意,您可以将其命名为对您的应用程序更有意义的名称。其上的单个方法将构造一个 CreateTestplanViewModel。
这使得该视图的数据来自 2 个来源这一事实仅仅是实现细节。您将连接一个将 IReleaseDataProvider 和 ITemplateDataProvider 作为构造函数依赖项的实现。
这与我的建议一致:
public interface IProvideTestPlanSetupModel
{
CreateTestplanViewModel GetModel();
}
public class TestPlanSetupProvider : IProvideTestPlanSetupModel
{
private readonly IReleaseDataProvider _releaseDataProvider;
private readonly ITemplateDataProvider _templateDataProvider;
public TestPlanSetupProvider(IReleaseDataProvider releaseDataProvider, ITemplateDataProvider templateDataProvider)
{
_releaseDataProvider = releaseDataProvider;
_templateDataProvider = templateDataProvider;
}
public CreateTestplanViewModel GetModel()
{
var releases = _releaseDataProvider.GetReleases();
var templates = _templateDataProvider.GetTemplates();
return new CreateTestplanViewModel(releases, templates);
}
}
public class TestPlanController : Controller
{
private readonly IProvideTestPlanSetupModel _testPlanSetupProvider;
public TestPlanController(IProvideTestPlanSetupModel testPlanSetupProvider)
{
_testPlanSetupProvider = testPlanSetupProvider;
}
[HttpGet]
public ActionResult Create()
{
var createTestplanViewModel = _testPlanSetupProvider.GetModel();
return PartialView(createTestplanViewModel);
}
}
如果您不喜欢在控制器之外的任何地方构建视图模型,该接口可以提供一个中间对象,该对象具有您将复制到视图模型的相同属性。但这很愚蠢,因为这种数据组合仅与特定视图相关,而这正是视图模型应该表示的内容。
附带说明一下,您似乎在通过同一模型进行读/写时遇到了非常常见的烦恼。由于这些问题困扰着您,您可能会调查 CQRS,这可能会让您对直接与数据库进行这些类型的查询对话时感觉不那么脏,并且会帮助您绕过我们都非常喜欢的分层迷宫。这似乎很有希望,尽管我还没有在生产应用程序中试驾它的乐趣。