什么是去耦?它适用于哪些发展领域?[关闭]


21

我最近注意到去耦是问题中的一个话题,并且想知道它是什么以及它可以在哪里应用。

“在哪里可以适用”,我的意思是:

它仅与涉及C和Java之类的编译语言有关吗?

我应该作为Web开发人员了解/研究它吗?


如果您进行了一些研究并根据定义的任何不明确部分提出问题,这将有所帮助。
JeffO 2014年

2
@JeffO-我认为整个世界可以从完整的概念问题中受益,也可以从特定的细微差别中受益。“为什么天空是蓝色的?” 允许答案覆盖概念本身,而无需在细节上进行极端详细的介绍。这就是为什么我没有进行研究就问我的问题的原因。

您遇到的具体问题是什么?目前的情况是,你的问题太多太广。以目前的形式,答案基本上是结构化设计的全文: Edward Yourdon和Larry Constantine撰写的《计算机程序和系统设计学科的基础》
约尔格W¯¯米塔格

我认为这里的答案可以很好地描述这个概念。这就像在问“与编程相关的单词的定义是什么?”-那么它的范围太广了吗?@ GlenH7

1
@ jt0dd我必须同意。仅仅因为您可以用书来解释某些内容,并不意味着更简洁的答案没有价值。有了编程文献,人们通常会在为您提供详尽的更高层次的概述之前,向您详细介绍各种细节。“什么是面向对象?” 太宽泛了。但这是IMO的一个特定主题。
Erik Reppen 2014年

Answers:


57

“耦合”是一个术语,描述了软件系统中两个实体(通常是类)之间的关系。

当一个类使用另一个类或与其通信时,据说它“依赖”该另一个类,因此这些类是“耦合的”。他们中至少有一个“知道”另一个。

我们的想法是,我们应尽量使系统中各类之间的耦合尽可能“松散”:因此,“松散耦合”或有时是“解耦”(尽管英语中的“解耦”意味着“根本没有耦合”,人们通常用它来暗示实体之间的“松散耦合”)。

那么:在实践中什么是松散耦合与强耦合?为什么要使实体松散耦合?


耦合描述了一个实体与另一实体之间的依赖程度。通常是类或对象。

当ClassA严重依赖ClassB时,更改ClassB时ClassA受到影响的机会很高。这是强耦合。

但是,如果ClassA轻微依赖ClassB,则ClassA代码更改以任何方式影响ClassA的机会就很小。这是松散耦合,或“解耦”关系。

松散耦合是好的,因为我们不希望我们系统的组件彼此严重依赖。我们希望保持系统模块化,在这里我们可以安全地更改一个零件而又不影响另一个零件。

当两个部分松散耦合时,它们彼此之间更独立,并且在其他部分更改时不太可能破裂。

例如,建造汽车时,您不希望引擎的内部变化会破坏方向盘上的东西。

尽管这在制造汽车时绝不会偶然发生,但程序员始终会遇到类似的情况。松散耦合的目的是减少此类情况发生的风险。

强耦合通常在实体A知道太多关于实体B发生如果实体A做出有关如何实体B操作或者它是如何建成,比有一个高风险,在实体B的变化将影响到实体A.太多的假设这这是因为关于实体B的假设之一现在不正确。

例如,想象一下,作为一名驾驶员,您将对汽车发动机的工作原理做出某些假设。

当您购买的新汽车的发动机工作原理不同(或由于某种原因而更换了发动机)时,您以前的假设是错误的。如果您使用的是计算机中的代码,那么您现在将是无法正常工作的不正确代码。

但是,如果您作为驾驶员对汽车所做的所有假设都是:A-他们有方向盘,B-他们有刹车和油门踏板,那么只要您的一些假设,汽车的变化不会影响您保持正确。这是松耦合。


实现松散耦合的一项重要技术是封装。这个想法是,一个类对其他类隐藏其内部细节,并提供一个严格定义的接口供其他类与其通信。

因此,举例来说,如果你定义一个类车,它的接口(公共方法)可能会是drive()stop()steerLeft()steerRight()getSpeed()。这些是其他对象可以在Car对象上调用的方法。

Car类的所有其他详细信息:发动机的工作方式,其使用的燃料种类等对其他类都是隐藏的,以防止他们对Car过多了解。

当A类对B类了解太多时:我们之间存在紧密耦合的关系,其中A类过于依赖B类,而B类的更改很可能会影响A类。这使得系统难以扩展和维护。

两个实体之间的关系(它们彼此之间很少了解(仅需要知道))是松散耦合或分离的关系。


3

去耦通常是查看两个事物是否需要紧密协作或可以进一步独立。独立之所以伟大,是因为它使这些事情易于更改或在其他地方使用。去耦不仅可以应用于发展,还可以应用于很多领域,对于时间上的去耦尤其如此,它甚至可以应用到您的日常生活中(一定程度上)。还应注意,在软件开发中要考虑多种类型的耦合,并且答案中不会涵盖所有耦合。您将必须进行研究。

如果两者之间存在依赖关系,则将AB两件事结合在一起。如果A依赖于B,则可以在不考虑A的情况下使用B。如果要使用A,则还必须随身携带B,因为A取决于它。

通常,在软件开发中,您无法完全消除组件之间的耦合。在这种情况下,去耦通常意味着放松现有的耦合。也就是说,请确保每个组件对周围的其他组件了解得尽可能少。

这可能是在野外发现的最常见的耦合类型:

//Inside a class meant to display info for a particular Facebook user.
void DisplayFriends(FacebookUser user, FacebookClient client)
{
     Friend[] = (Friend[])client.GetConnection().ExecuteCommandForResult("getFriends:" + user.Name);
     ...
}

在这里,DisplayFriends无需手动操作Facebook客户端背后的连接即可获得所需的内容。DisplayFriends的类被耦合至两个FacebookClientConnection。如果FacebookClient突然更改其使用的连接类型,则该应用将无法再与Facebook好友取得联系。通过要求FacebookClient提供我们所需的内容,我们可以消除DisplayFriends类和Connection之间的耦合。

//Inside a class meant to display info for a particular Facebook user.
void DisplayFriends(FacebookUser user, FacebookClient client)
{
     Friend[] = client.GetFriends(user);
     ...
}

现在,我们实际上并不在乎FacebookClient如何获得我们的朋友。我们真正关心的只是事实,它得到了他们。内部行为的任何改变都不会损害我们自己的班级。

通过遵循功能的德米特定律,可以很容易地实现这种解耦(引用维基百科):

函数的Demeter定律要求对象O的方法m只能调用以下类型的对象的方法:

  • O本身
  • m的参数
  • 在m内创建/实例化的任何对象
  • O的直接组成对象
  • 全局变量,在m范围内可由O访问

由于我在答案的开头提到了时间耦合,因此我将简要介绍一下。

在设计并行执行算法的应用程序时,通常考虑时间耦合。考虑两个可执行单元(它们是实际的指令,方法,或您希望将其视为单元的任何内容),A和B。如果B必须在执行A之前执行,则A暂时耦合到B。如果A在时间上没有与B耦合,则A和B可以同时执行。为此建立一个自己的例子:考虑一下您日常生活中的平常工作。您有一件一件一件一件接一件的事情,但是您可以同时做吗?

最后,回答您的最后一点:

我应该作为Web开发人员了解/研究它吗?

是。例如,最流行的Web开发设计模式(MVC)之一就是解耦。


1

其他答案很好地描述了去耦。我想讨论你的最后一个问题。

我应该作为Web开发人员了解/研究它吗?

答案是肯定的。您是哪种类型的开发人员都没有关系。您可能是Web开发人员或嵌入式系统开发人员。

假设您有一个类,该类生成放置在您的网页上的自定义URL。您可能很想让该类将URL直接写到页面上,然后将它们放在标记的href中。起初,这似乎更简单。但是,当您需要进行更改以将链接放入电子邮件并将其发送给用户时,会发生什么情况呢?您当前的代码无法使用,因为您的URL生成器与您使用的Web框架紧密相关。

更好的选择是拥有一个URL生成器类,该类将URL作为字符串返回。您的网络代码可以使用它,电子邮件代码也可以使用它。解耦代码似乎需要更多的前期工作,但是随着时间的推移,付出的努力是值得的。

不管您在哪个编程领域中工作,模块化和分离的代码都将使您的代码更易于理解,可测试和可维护性更高。


在回答完这两个问题之后,我真的得到了它,看看如何使用它。
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.