12

我很难看到松散耦合代码在现实世界中的好处。为什么要花这么多精力让一些东西灵活地与各种其他对象一起工作?如果你知道你需要实现什么,为什么不专门为此目的编写代码呢?

对我来说,这类似于创建无类型变量:它使其非常灵活,但可能会遇到问题,因为可能传入了一个意外的值。这也使得它更难阅读,因为你不明确知道传入的是什么.

然而,我觉得鼓励强类型化,但松散耦合是不好的。

编辑:我觉得要么我对松散耦合的解释不正确,要么其他人读错了。对我来说,强耦合是当一个类引用另一个类的具体实例时。松耦合是指一个类引用另一个类可以实现的接口。

那么我的问题是为什么不专门调用一个类的具体实例/定义?我将其类比为专门定义您需要的变量类型。我一直在阅读有关 Dependency Injection 的文章,他们似乎认为松耦合更好的设计是事实。

4

9 回答 9

15

首先,您将苹果与橙子进行比较,所以让我尝试从两个角度来解释这一点。键入是指如何执行对值/变量的操作以及它们是否被允许。与内聚相反,耦合是指一个(或多个)软件的架构。两者根本没有直接关系。

强类型与弱类型

强类型语言(通常)是一件好事,因为行为是明确定义的。以维基百科的这两个例子为例:

弱打字

a = 2
b = '2'

concatenate(a, b) # Returns '22'
add(a, b)         # Returns 4

上面的内容可能会有点混乱,而且定义不太明确,因为某些语言可能使用 ASCII(可能是十六进制,可能是八进制等)数值来进行加法或连接,因此存在很大的错误空间。此外,很难看出a最初是integera 还是 a string(这可能很重要,但语言并不关心)。

强类型

a = 2
b = '2'

#concatenate(a, b)     # Type Error
#add(a, b)             # Type Error
concatenate(str(a), b) # Returns '22'
add(a, int(b))         # Returns 4

正如您在此处看到的,一切都更加明确,您知道什么是变量以及何时更改任何变量的类型。

维基百科说:

弱类型所声称的优势在于,它比程序员需要更少的努力,因为编译器或解释器隐式地执行某些类型的转换。然而,一个声称的缺点是弱类型编程系统在编译时捕获的错误较少,其中一些可能在测试完成后仍然存在。支持多种隐式转换的两种常用语言是 C 和 C++,有时会声称它们是弱类型语言。然而,其他人认为这些语言对如何混合不同类型的操作数施加了足够的限制,因此这两种语言应该被视为强类型语言。

强类型和弱类型都有其优点和缺点,没有好坏之分。了解差异和相似之处很重要。

松耦合与紧耦合

直接来自维基百科

在计算机科学中,耦合或依赖是每个程序模块依赖于其他模块的程度。

耦合通常与内聚形成对比。低耦合通常与高内聚相关,反之亦然。耦合和内聚的软件质量度量是由结构化设计的原始开发者 Larry Constantine 发明的,他也是这些概念的早期支持者(另见 SSADM)。低耦合通常是结构良好的计算机系统和良好设计的标志,当与高内聚相结合时,支持高可读性和可维护性的总体目标。

简而言之,低耦合是代码非常紧凑、可读和可维护的标志。在处理大量 API 或不同部分交互形成整体的大型项目时,首选高耦合。既不好也不坏。有些项目应该是紧密耦合的,即嵌入式操作系统。其他应该是松耦合的,即网站CMS。

希望我在这里有所启发:)

于 2010-10-30T05:54:11.683 回答
7

问题是正确的指出,弱/动态类型确实是松耦合概念的逻辑扩展,程序员偏爱一个而不是另一个是不一致的。

松耦合已经成为一个流行词,许多程序员不必要地实现接口和依赖注入模式——或者,通常情况下,他们自己的这些模式的乱码版本——基于未来需求中一些无定形的变化的可能性。没有隐藏这样一个事实,即这会带来额外的复杂性,并使代码对未来的开发人员来说更难维护。唯一的好处是,如果这种预期的松散耦合恰好使未来的需求变更更容易实现,或者促进代码重用。然而,需求更改通常涉及系统的足够多的层,从 UI 到存储,松散耦合根本不会提高设计的健壮性,并且会使某些类型的琐碎更改变得更加乏味。

于 2014-05-15T18:28:40.860 回答
5

没错,松散耦合在编程中几乎被普遍认为是“好”的。为了理解为什么,让我们看一下紧耦合的一个定义:

如果A必须因为B改变而改变,那么你说AB紧密耦合。

这是一个从“完全解耦”(即使B消失,A会保持不变)到“松散耦合”(对B的某些更改可能会影响A,但大多数进化变化不会影响)到“非常紧密”的尺度耦合”(对B的大多数更改都会深深影响A)。

在 OOP 中,我们使用了很多技术来减少耦合——例如,封装有助于将客户端代码与类的内部细节分离。此外,如果您依赖于一个接口,那么您通常不必担心对实现该接口的具体类的更改。

在旁注中,你说得对,打字和耦合是相关的。特别是,更强和更静态的类型往往会增加耦合。例如,在动态语言中,有时可以将字符串替换为数组,基于字符串可以被视为字符数组的概念。在 Java 中你不能,因为数组和字符串是不相关的。这意味着如果 B 过去返回一个数组,而现在返回一个字符串,那么它肯定会破坏它的客户端(只是一个简单的人为示例,但您可以想出更多更复杂和更引人注目的示例)。因此,更强的类型和更多的静态类型都是权衡取舍。虽然通常认为更强的类型是好的,但更喜欢静态类型还是动态类型在很大程度上取决于上下文和个人喜好:

所以最后我们可以回到你原来的问题:为什么松散耦合通常被认为是好的?因为无法预料的变化。当你编写系统时,你不可能知道它最终会在两个月,或者两个小时内发展到哪个方向。发生这种情况既是因为需求会随着时间而变化,也是因为您通常直到之后才完全了解系统你已经写好了。如果您的整个系统非常紧密耦合(这种情况有时被称为“大泥球”),那么系统每个部分的任何变化最终都会波及系统的所有其他部分(“非常紧耦合”)。这使得系统非常不灵活,最终结晶成一个僵硬的、不可维护的团块。如果您在开始构建系统的那一刻就具有 100% 的远见,那么您就不需要解耦。

另一方面,正如您所观察到的,解耦是有代价的,因为它增加了复杂性。更简单的系统更容易更改,因此程序员面临的挑战是在简单和灵活之间取得平衡。紧密耦合通常(并非总是)使系统更简单,但代价是使其更加刚性。大多数开发人员低估了未来对更改的需求,因此常见的启发式方法是使系统的耦合程度低于您想要的程度,只要这不会使其过于复杂。

于 2013-05-14T10:22:32.460 回答
2

强类型是好的,因为它通过抛出编译时错误而不是运行时错误来防止难以找到错误。

紧耦合代码是不好的,因为当你认为你“知道你需要实现什么”时,你经常错了,或者你还不知道你需要知道的一切。

即,您稍后可能会发现您已经完成的某些事情可以在您的代码的另一部分中使用。然后,也许您决定将相同代码的 2 个不同版本紧密结合。然后稍后您必须对业务规则进行轻微更改,并且您必须更改 2 组不同的紧耦合代码,也许您会让它们都正确,这充其量会花费您两倍的时间......或者最坏的情况你会在一个中引入一个错误,但不会在另一个中引入一个错误,并且它会在一段时间内未被发现,然后你会发现自己陷入了真正的泡菜中。

或者您的业务增长速度可能比您预期的要快得多,您需要将一些数据库组件卸载到负载平衡系统,因此现在您必须重新设计与现有数据库系统紧密耦合的所有内容以使用新系统.

简而言之,松散耦合使软件更容易扩展、维护和适应不断变化的条件和要求。

编辑:我觉得要么我对松散耦合的解释不正确,要么其他人读错了。对我来说,强耦合是当一个类引用另一个类的具体实例时。松耦合是指一个类引用另一个类可以实现的接口。

那么我的问题是为什么不专门调用一个类的具体实例/定义?我将其类比为专门定义您需要的变量类型。我一直在阅读有关 Dependency Injection 的文章,他们似乎认为松耦合更好的设计是事实。

我不确定你的困惑是什么。例如,假设您有一个大量使用数据库的应用程序。您的应用程序有 100 个不同的部分需要进行数据库查询。现在,您可以在 100 个不同的位置使用 MySQL++,或者您可以创建一个单独的接口来调用 MySQL++,并在 100 个不同的位置引用该接口。

现在您的客户说他想使用 SQL Server 而不是 MySQL。

您认为哪种情况更容易适应?在 100 个不同的地方重写代码,还是在 1 个地方重写代码?

好吧......现在你说也许在 100 个不同的地方重写它并不是那么糟糕。

所以...现在您的客户说他需要在某些位置使用 MySQL,在其他位置使用 SQL Server,在其他位置使用 Oracle。

现在你做什么?

在松散耦合的世界中,您可以拥有 3 个独立的数据库组件,它们都与不同的实现共享相同的接口。在紧密耦合的世界中,您将拥有 100 组 switch 语句,其中散布着 3 个不同级别的复杂性。

于 2010-10-30T05:43:33.733 回答
1

然而,我觉得鼓励强类型化,但松散耦合是不好的。

我认为说强类型是好的或鼓励的并不公平。当然,很多人更喜欢强类型语言,因为它带有编译时检查。但是很多人会说弱打字很好。好像听过“强”好,“松”怎么也好。一种语言的打字系统的优点甚至不在与类设计类似的概念范围内。

旁注:不要混淆强类型和静态类型

于 2010-10-30T05:55:07.337 回答
1

如果你知道你需要实现什么,为什么不专门为此目的编写代码。

简短的回答:你几乎永远不知道你需要实现什么需求变化,如果你的代码一开始是松耦合的,那么适应它就不是一场噩梦。

于 2010-10-30T05:37:04.907 回答
1

强类型将有助于减少错误,同时通常有助于提高性能。代码生成工具收集的有关变量可接受值范围的信息越多,这些工具在生成快速代码方面的作用就越大。

当与类型推断和特性(perl6 等)或类型类(haskell)结合使用时,强类型代码可以继续保持紧凑和优雅。

于 2010-10-30T06:19:37.443 回答
0

我认为紧/松耦合(对我来说:接口声明和对象实例的分配)与Liskov 原则有关。使用松散耦合可以实现 Liskov 原则的一些优点。

但是,一旦执行了 instanceof、cast 或 copy 操作,松耦合的使用就开始受到质疑。此外,对于带有方法或块的局部变量,这是无意义的。

于 2012-09-02T12:28:17.557 回答
0

如果在派生类中的函数中进行的任何修改都会更改基抽象类中的代码,那么这将显示完全依赖关系,这意味着这是紧耦合的。

如果我们不再次编写或重新编译代码,那么它会显示出较少的依赖关系,因此它是松耦合的。

于 2012-04-10T05:17:55.090 回答