我经常发现自己需要引用一个远离几个物体的物体,或者看起来如此。我看到的选项是通过中间人传递引用或者只是静态地提供某些东西。我理解全局范围的危险,但通过一个什么都不做的对象传递引用感觉很荒谬。我想,我可以稍稍路过一下。我怀疑在某个地方有一条线。
有没有人知道在哪里画这条线?
或者处理在依赖对象之间分配引用的问题的好方法?
答案 0 :(得分:3)
使用Law of Demeter(适度和品味,而非教条)。如果您正在对a.b.c.d.e
进行编码,那么就会出现问题 - 您已经永久地确定a
的实施,以使b
具有c
... {EEP} ! - )一个或最多两个点是您应该使用的最大值。但另一种方法是不要将内容填充到全局中(并确保线程不安全,错误,难以维护的代码!),它是让每个对象“表面”设计为维护其作为其接口的一部分的特性。客户向前发展,而不仅仅是让贫穷的客户经历这些无休止的嵌套参考链!
答案 1 :(得分:1)
这种抽象的气味可能需要一些改进。您似乎违反了Law of Demeter.
答案 2 :(得分:1)
在某些情况下,全球性并不算太差。
考虑一下,您可能正在针对操作系统的API进行编程。这是全局的,您可以访问文件或注册表,写入控制台。查看窗口句柄。您可以执行大量操作来访问整个计算机或整个Internet上的全局状态...并且您不必将单个引用传递给您的类来访问它。如果您访问操作系统的API,所有这些都是全局的。
所以,当你考虑经常存在的全球事物的数量时,你自己的程序中的全局事件可能没有许多人尝试制造和尖叫的那么糟糕。
但是,如果你想拥有非常好的OO代码,它们都是可单元测试的,我想你应该围绕对全局变量的任何访问编写包装类,无论它们来自操作系统,还是声明自己封装它们。这意味着使用此全局状态的类可以获取对包装器的引用,并且可以用伪造替换它们。
无论如何,嗯。我不太确定我在这里给出的建议是什么,除了说,构造代码是一个平衡!而且,如何针对您的特定问题进行操作取决于您的偏好,使用代码的人的偏好,您在学术上对实用规模的感受,代码库的大小,安全性的关键性如何系统是完成的截止日期还有多远。答案 3 :(得分:1)
我相信你的问题揭示了你的课程。也许责任可以改善?也许移动一些代码可以解决问题?
告诉,不要问。
这是向我解释的原因。有一种自然倾向于调用类来获取一些数据。太过分了,要求太多,通常会导致沉重的“吸气序列”。但还有另一种方式。我必须承认这不容易找到,但在特定代码和编码人员的习惯中逐渐改进。
A类想要进行计算,并询问B的数据。有时候,A告诉B做这项工作是合适的,可能会传递一些参数。这可以替换B的“getName()”,由A用来检查名称的有效性,通过B上的“isValid()”方法。 “询问”已经被“告诉”所取代(调用执行计算的方法)。
对我来说,当我发现太多的getter来电时,这是我问自己的问题。渐渐地,这些方法在正确的对象中遇到了它们的位置,并且一切都变得更简单,我吸引力更少,对它们的呼叫也更少。我的代码较少,它提供了更多的语义,更好地与功能需求保持一致。
移动数据
还有其他情况我会移动一些数据。例如,如果一个字段向上移动两个对象,则“吸气剂链”的长度减少两个。
我相信一开始没有人能找到正确的模型。 我首先考虑它(使用手写的图表快速而且有很大的帮助),然后对其进行编码,然后再次面对真实的事情...然后我编写其余的代码,以及我在代码中感觉到的任何气味,我认为再次...
拆分和合并对象
如果A上的方法需要来自C的数据,而B作为中间人,我可以尝试A和C会有一些共同点。可能A或A的一部分可能成为C(可能分裂A,合并A和C)......
但是,有些情况下我会保留吸气剂。 但是,创建长链的可能性较小。 长链可能会被上述某种技术破坏。
答案 4 :(得分:0)
我有三种模式:
将必要的引用传递给对象的构造函数 - 然后可以将引用存储为对象的数据成员,而不需要再次传递;这意味着对象的工厂具有必要的参考。例如,当我创建DOM时,我在构造DOM节点时将元素名称传递给DOM节点。
让事情记住他们的父母,并通过他们的父母获得对财产的引用;这意味着父母或祖先拥有必要的财产。例如,当我创建一个DOM时,有各种各样的东西存储为顶级DomDocument祖先的属性,并且它的子节点可以通过引用访问这些属性,每个属性都有其父对象。
将作为引用传递的所有不同内容放入单个类中,然后只传递一个类实例作为传递的唯一内容。例如,渲染DOM需要许多属性(例如GDI图形句柄,视口坐标,回调事件等)......我将所有这些东西放入一个单独的'Context'实例中,该实例作为只有要渲染的DOM节点方法的参数,每个方法都可以从该上下文参数中获取所需的任何属性。