如何通过依赖注入避免UI中疯狂的接口数量?


8

问题
我最近阅读了很多有关Singletons不好以及依赖注入(我理解为“使用接口”)如何更好的知识。当我使用callbacks / interfaces / DI并遵循接口隔离原则来实现其中的一部分时,我最终陷入了混乱。

UI父级的依赖关系基本上是其所有子级的依赖关系的组合,因此,UI元素的层次结构越深,其构造函数就越肿。

在UI层次结构之上一直是一个Application类,其中包含有关当前选择的信息以及对需要反映更改的3d模型的引用。该应用程序类实现了8个接口,而这仅仅是即将推出的产品(/接口)的五分之一!

我目前正在处理持有当前选择的单例,并且UI元素具有自我更新的功能。该函数滴入UI树和UI元素,然后根据需要访问当前选择单例。这种代码对我来说似乎更干净。

问题
单身人士可能适合该项目吗?
如果没有,那么我的DI思维和/或实施过程中是否存在根本的缺陷,从而使其变得如此繁琐?

有关项目的其他信息
类型:带铃铛的公寓用购物篮
大小:代码和UI
维护2个工作月:没有正在运行的更新,但以后可能是“版本2.0”
环境:在Unity中使用C#(使用实体)组件系统

在几乎所有情况下,用户交互都会触发多个操作。例如,当用户选择一个项目时

  • 显示该项目及其说明的UI部分需要更新。为此,它还需要从3D模型中获取一些信息才能计算价格。
  • 在使用者介面的上方,总价格需要更新
  • 为了显示那里的变化,需要调用3d模型上的类中的相应函数

DI不仅仅是使用接口,它还具有交换混凝土的能力,这在单元测试领域中尤其有用……
Robbie Dee 2016年

1
另外,我还没有看到一个问题,其中单例是首选解决方案。人们似乎总是说一个规范的例子是一个日志编写器,但是即使在这里,您也可能要写许多不同的日志(错误,调试等)。
罗比·迪

@RobbieDee是的,DI还有更多,但是我看不到使用接口不是DI的情况。如果单身人士不是首选解决方案-我也假设-那么为什么首选解决方案如此混乱?这是我的主要问题,但我想保持开放性,因为有时一般规则不适用。
R. Schmitz

接口创建安排也是模拟框架的功能。他们使用OO语言已有数十年了……
Robbie Dee

我不明白你的意思。
R. Schmitz

Answers:


4

我认为问题是一种症状,而不是解决方案。

最近,我读了很多有关Singletons不好以及依赖注入(我理解为“使用接口”)如何更好的知识。当我使用callbacks / interfaces / DI并遵循接口隔离原则来实现其中的一部分时,我最终陷入了混乱。

寻找问题的解决方案;并误解它可能会破坏您的设计。您是否阅读过有关DI与Singleton的 SO问题,是否有不同的概念?我读到它只是包装单例,因此客户端不必处理单例。这是很好的旧封装。我认为那是正确的。


UI元素的层次结构越深,其构造函数就越肿。

首先构建较小的位,然后将它们传递给它们所属的事物的构造函数,然后将较大的事物传递给下一个较大事物的构造函数...

如果您遇到复杂的施工问题,请使用工厂或建筑商模式。最重要的是,将复杂的结构引入了自己的班级,以使其他班级保持整洁,干净,易懂等。


该应用程序类实现了8个接口,而这仅仅是即将推出的产品(/接口)的五分之一!

这听起来像缺乏扩展能力。核心设计缺失,所有东西都从顶部塞满了。应该有更多的自下而上的构造,组合和继承。

我想知道您的设计是否“繁重”。听起来我们正在努力使一门课成为一切或可能的一切。它是UI类而不是业务域类的事实,确实使我对关注点分离感到好奇。

从一开始就重新设计,并确保可以建立坚实,基础的产品抽象,以进行更复杂或不同类别的产品。然后,最好对这些内容进行自定义集合,以便在某处放置“集合级别”功能-就像您提到的“第三模型”。


...需要反映变化的3D模型。

其中大部分可能适合自定义集合类。由于深度和复杂性,它本身也可能是独立的类结构。这两件事不是互相排斥的。

了解有关访客模式的信息。这是将整个功能块抽象地连接到不同类型的想法。


设计与DI

您将执行的所有依赖项注入中有90%是构造函数参数传递。写这本书的奎伊说。精心设计您的课程,避免用一些关于需要使用DI容器的模糊概念来污染该思维过程。如果需要的话,您的设计可以建议您。


专注于建模公寓购物领域。

避免使用Jessica Simpson的设计方法:“我完全不知道那意味着什么,但我想要它。”

以下是错误的:

  • 我应该使用接口
  • 我不应该使用单身人士
  • 我需要DI(无论是什么)
  • 我应该使用合成,而不是继承
  • 我应该避免继承
  • 我需要使用模式

我试图摆脱我曾经使用过的所有单例,并且您所说的某些事情或多或少自动发生了。其余的也很有意义,我将听取您的建议,并阅读有关访客模式的信息。总之,写得很好的答案,谢谢!
R. Schmitz

只是一点,我并不想在这里成为帮助吸血鬼,但这是原始问题一部分:普遍共识(并且基于有效理由)似乎是您确实不应该使用单例。您写下“'我不应该使用单例'是错误的”-那么在哪种情况下使用那个合适呢?
R. Schmitz

我要说的是,“取决于情况”。我经常看到格言是字面上的意思。
–radbobo

3

“类继承”有点危险。假设:一个包含5个小部件的网页。该页面不是任何小部件的祖先。它可能包含对这些小部件的引用。但这不是祖先。与其使用类继承,不如考虑使用合成。5个窗口小部件中的每个窗口小部件都可以独立构造,而无需参考其他窗口小部件或首页。然后使用足够的信息来构建首页,以构建基本页面并布局传递给它的小部件对象(集合)。该页面负责布局等,但不负责小部件的构造和逻辑。

一旦使用合成,DI是您最好的朋友。DI允许您将每个小部件交换为您在DI中定义的任何版本或小部件类型。小部件的构造在DI中捕获,并且与首页分开。也许甚至集合的组成也可以在您的DI中定义。首页将根据传递给它的小部件执行布局。无需更改首页构造函数。顶层只需要逻辑来执行小部件的布局,并根据定义的接口将信息传递到小部件/从小部件传递信息。

与其将侦听器上下传递到组成链中,不如将侦听器集合注入需要它们的那些小部件。将集合注入发布者,以便他们可以发布到集合。将集合注入侦听器中,以便他们可以将自己添加到集合中。该集合跨越了组成链中的所有对象。


抱歉,此处的“类层次结构”用词错误;它实际上不是类层次结构,而是UI层次结构。“小部件”不是应用程序类的子类,但是“页面”保留对它们的引用以发布UI更新。使用此结构可以很好地测试,但是特别是在构造函数中,也有很多开销,只是将大量侦听器传递给其(UI)子代。
R. Schmitz

@ R.Schmitz:开销有关系吗?用户界面呆滞吗?您描述的设计是否应归咎于此?
罗伯特·哈维

@ R.Schmitz您能否详细说明“传递大量听众”?也许我在C#中使用DI的经验很低,但是有一些事情告诉我,正确的设计并不需要(至少在构造函数中)。
Katana314 '16

@RobertHarvey完全没有性能损失,仅与可读性有关。
R. Schmitz

@ Katana314例如,当添加项目时,3dmodel需要更新,并且不属于任何产品类别,因此在应用程序类中引用了该3dmodel,该类侦听要添加/删除/更改的项目。最后,每种产品类别几乎都是相同的。其他UI部分也会做出反应(并监听),但是消息需要传递到顶部,因为这是3dmodel参考和实际数据(然后也进行更新)的位置。
R. Schmitz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.