如何让设计“松耦合”?
我正在制作一个简单的 3D CAD 软件。在类图中,许多对象需要通过(x,y,z)来与其他对象区分。我创建了一个所谓的“Position”类,但问题是它看起来高度耦合,因为许多类都与位置一起工作。 有什么想法吗?
I'm making a simple 3D CAD software. in the class diagram, many objects need to distinguish with others by (x,y,z). I create a class so-called "Position", but the problem is it looks highly-coupling because many classese work with position.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果一个类型被许多其他类型使用,那么它本身并不是问题。在您的情况下,图形对象显然(通常)有一个位置,因此从域模型的角度来看,耦合看起来自然且合理。
此外,Position 类可能是一个相当低级的类,从长远来看,其接口(也可能是实现)不会经常更改。因此,此类更改破坏客户端代码的可能性不大。
It is not a problem per se if a type is used by many other types. In your case, graphical objects obviously (usually) have a position so the coupling looks natural and reasonable from the perspective of the domain model.
Also, the Position class is probably going to be a fairly low-level class whose interface (and probably implementation too) is not going to change very often in the long run. So there is not much chance of such changes breaking client code.
首先我想说,12年后你的设计还不错。假设您的类的定位逻辑应从外部调用,那么您的所有类都需要拥有并提供此逻辑。所以它是接口的一部分,你必须引入功能。这意味着,你必须依赖它并且存在耦合。耦合不在您的对象之间。所以情况并没有那么糟糕。
但总有其他选择。众所周知,继承建立了非常紧密的耦合。例如,考虑定位逻辑仅在类内部调用。那么你在继承方面就没有任何好处。你也可以再上一门课(我们称之为位置)。您不是从此类派生,而是集成此类的对象。每当你想对这个位置做一些事情时,你就调用这个对象的相应方法。
这个替代方案看起来像是一个无意义的改变。你为什么要这样做?但让我们看看后果。假设你有一个 Circle 类。 Circle 有一个如上所述的位置对象。 (顺便说一句,请参阅“有一个位置”而不是“是一个位置”的措辞。“对象和组合”解决方案似乎很自然。)在代码文件 X 的某个位置,您可能已经创建了这样的一个圆圈。现在你决定改变定位逻辑。在X中你不必担心这有副作用,因为Circle的界面没有改变。这只是 Circle 内部的一个对象发生了变化。这只是一个实现细节。相反,如果您使用继承,则不能只更改基类而不考虑这是否对 X 产生负面影响。因此,这种“对象与组合”解决方案实际上减少了 X 与定位逻辑之间的耦合。
您甚至可以进一步减少耦合。使用对象和组合解决方案,每当您更改定位逻辑时,您都必须检查所有类是否有影响。但是使用 Position 接口怎么样?您的类看不到 Position 类型的对象,而是一个实现 Position 接口的对象。而实际的定位逻辑就是实现这个接口。这样,大多数类的代码就不再依赖于定位逻辑的实现。
这还不是游戏的结束。仍然存在耦合,因为您的类必须以某种方式创建位置对象。因此,至少构造函数必须详细说明,例如传递 x、y、z。但是,如果您为此目的使用工厂之类的东西,这样您的对象就可以获得位置,甚至不知道它们是如何创建的。那么你就绝对灵活了。您可以在完全不同的情况下使用您的课程。例如在二维坐标系中。您的定位逻辑和类之间不再存在耦合。
我希望您看到所有这些选项都存在。我想在你的例子中这有点过度设计了。但你的问题是如何减少耦合。而且总有办法。组合当然是可能的。例如,您可以拥有对象和组合,并将位置对象在基类中公开。但我会问,继承是否是更好的选择?
First let me say after 12 years that your design is not bad. Assuming that the positioning logic of your classes shall be called from outside, all your classes need to have and offer this logic. So it is part of the interface and you must bring the functionalities in. And this means, you must depend on it and there is a coupling. The coupling is not between your objects. So it is not as bad.
But there are always alternatives. It is known that inheritance establishes a very tight coupling. Consider for example that the positioning logic is only called internally in your class. Then you don't have any benefit in inheritance. You could as well have another class (let us call it Position). And instead of deriving from this class, you integrate an object of this class. And whenever you want to do something with the position, you call the corresponding methods of this object.
This alternative looks like a nonsense change. Why should you do this? But let us have a look at the consequences. Assume you have a class Circle. Circle has such a position object as proposed above. (By the way, see the wording "has a position" instead of "is a position". The "object-and-composition" solution seems to be quite natural.) Somewhere in a file X of your code you may have created such a Circle. And now you decide you change the positioning logic. In X you don't have to worry that this has a side effect, because the interface of Circle has not changed. It is just one object inside of Circle that has changed. That is just an implementation detail. In contrast if you would have used inheritance, you cannot just change the base class without looking if this has a negative effect to X. So this "object-and-composition" solution has actually reduced the coupling between X and the positioning logic.
You can even reduce the coupling further. With the object-and-composition solution, whenever you change the positioning logic, you have to check all your classes if this has an effect. But what about using an interface for Position. Your classes don't see an object of a type Position, but an object that fullfils an interface Position. And the actual positioning logic implements this interface. This way most of your classes' code has no dependency to the implementation of the positioning logic.
That is not the end of the game. There is still a coupling, because your classes must somehow create the position objects. So at least the constructor must go into detail and for example pass x,y,z. But what if you use something like a factory for this purpose, so that your objects just get the position without even knowing how these have been created. Then you are absolutely flexible. You can use your classes in completely different situations. For example in a two dimensional coordinate system. There is no coupling between your positioning logic and your classes any more.
I hope you see that all these options exist. I suppose in your example this is a bit over-engineered. But your question was how to reduce the coupling. And there are always ways. Combinations are of course possible. For example you can have the object-and-composition and make the position object public in your base class. But then I would ask if not inheritance would have been the better option?