winforms 在Windows窗体中可以避免构造函数过度注入吗?

gpnt7bae  于 2023-08-07  发布在  Windows
关注(0)|答案(2)|浏览(89)

我有一个Windows窗体。它包含许多控制器:网格,按钮,甚至是TreeView。事件是在其中的大多数上定义的。例如,有多个独立的事件以独立的方式查询或命令我的SQL Server。对于几乎所有的情况,接口分离原则都迫使我不合并这些接口。
因为我正在进行依赖项注入,所以Windows窗体的构造函数被大量过度注入。我在窗体的构造函数中有四个参数,用于一个网格。示例包括:网格的初始填充、查询一个单元格中组合框的值列表、当一个其他类型改变时重新填充某些类型的单元格等。我估计用不了多久,我的构造函数就会有一些荒谬的东西,比如20个参数,所有的接口都查询服务器。
在Windows窗体中可以避免这种情况吗?我猜想,如果我能以某种方式构建每个组件,然后将它们提供给我的构造函数,而不是让我的表单知道每个组件的依赖关系,我会更好。也就是说,我想我宁愿换掉

MyForm(IQueryGridTimes TimeQueryRepo, ICommandGridTimeCells TimeCommandRepo, IQueryTheWholeGrid GridInitialPopulator, ..., IQueryForTheTreeView TreeViewPopulator)

字符串

var grid = new WhateverGrid(IQueryGridTimes TimeQueryRepo, ICommandGridTimeCells TimeCommandRepo, IQueryTheWholeGrid GridInitialPopulator)
var tress = new WhateverTreeview(QueryForTheTreeView TreeViewPopulator)
MyForm(grid, ..., trees,)


这是明智和可能的吗?我对其他方法持开放态度,不需要假设任何依赖注入容器(我宁愿不使用任何)。

eulz3vhy

eulz3vhy1#

Mark Seemann在他的blog中描述了一些处理构造函数过度注入的可能方法:

  • 如果构造函数参数形成自然的行为集群,则可以将它们refactored to Facade Services以创建更粗粒度的接口。
  • 如果依赖项表示cross-cutting concerns,最好使用Decorators(也在@Steven的博客文章中描述)或Chain of Responsibility pattern来解决它们,而不是将它们单独注入到需要它们的所有消费者中。
  • 如果上面的建议不能充分减少构造函数参数的数量,这通常是一个类做得太多并违反Single Responsibility Principle的症状。在这一点上,值得考虑将表单拆分为更小的组件(user controls),正如Steven所建议的那样,尽管所需的默认构造函数可能很难处理,正如他的评论中所解释的那样。

Seemann还指出,可能有一些有效的情况,让构造函数具有大量的依赖项,这只是最可维护的解决方案,或者真的不是问题。
Steven还建议使用Mediator-like patterns作为替代解决方案,详见他的blog post。有一些库可以帮助实现这种模式,比如MediatR(使用反射)和Mediator(使用源代码生成器)。但是,这将增加间接性,并使跟踪表单正在使用哪些依赖项变得更加困难。因此,单元测试可能会变得更加脆弱,您需要验证自己是否注册了所有必需的处理程序。
注意switching to Property Injection does not reduce the number of dependencies, but only implies they are optional instead of mandatory

63lcw9qa

63lcw9qa2#

有许多不同的方法来实现类似于你想要的东西。
最小化依赖项数量的一个快速方法是聚合其中的一些。四个或更多的依赖项只填充一个网格似乎太多了。相反,您可以拥有某种类型的存储库依赖关系,它公开来自缓存或永久存储的所有必要数据。一个接口可以包含多个函数。
或者,您也可以不使用建构函式。大多数DI框架都不按惯例使用它们,但仅此而已。您可以轻松地编写一个注入到属性中的DI框架,然后只需为引擎提供要填充的属性。
作为对前面建议的跟进,编写一个源生成器来处理DI对象的创建是相对简单的,而不需要求助于反射。当你一开始只有几十个对象时,反射并不是那么糟糕,但是source genning它们肯定更好。

相关问题