松耦合

在電腦運算和系统设计中，松耦合的系统是指：
 组件之間的關聯性不強（彼此之間的關係可以切斷），若有松耦合的話，會使得一個組件的變更對其他組件的影響降到最低。
 每一个组件对其他独立组件的定义所知甚少或一无所知。子范围包括类、接口、数据和服务之间的耦合。Loosely Coupled: The Missing Pieces of Web Services by Doug Kaye。

松耦合是紧耦合的对立面。

 优点和缺点 
松耦合系统中的组件可以用提供相同服务的替代实现所替换。松耦合系统中的组件比較不會限制使用相同平台、相同语言、相同操作系统或相同构建环境。

如果系统在时间上是解耦的，那么也很难提供事务完整性（transactional integrity）；需要额外的协调协议。跨系统滿足了松耦合性（可用性），但是在维护（数据同步）上會出現問題。

 集成 
松耦合在更广泛的分布式系统设计中是透過使用事务，提供的队列和互操作性标准来达成的。Pautasso C., Wilde E., Why is the Web Loosely Coupled? , Proc. of WWW 2009

促进松耦合的四类自主性是：引用自主性，时间自主性，格式自主性和平台自主性。F. Leymann Loose Coupling and Architectural Implications , ESOCC 2016 keynote

松耦合是一种架构原则，设计目标是面向服务架构；以下列出了松耦合和对应的紧耦合的11种形式：N. Josuttis, SOA in Practice. O'Reilly, 2007, .
 透過中介的物理连接，
 异步通信方式，
 只在数据模型中的简单常见类型，
 弱类型系统，
 以数据为中心并且自包含的消息，
 过程逻辑的分布式控制，
 （服务的消费者和提供者的），
 平台独立性，
 业务级补偿而不是系统级的事务，
 不同的时间的部署，
 版本中的隐式升级。

企业服务总线(Enterprise Service Bus,ESB)中间件诞生在实现松散耦合的多个维度；然而，过于机械化和错误安置的ESB还可以产生相反的效果，产生非预期的紧耦合和中心架构热点。M. Keen et al, Patterns: Implementing an SOA using an Enterprise Service Bus , IBM, 2004

也旨在促进松散耦合。How EDA extends SOA and why it is important  Jack van Hoof

 降低耦合的方法 
接口的松耦合可以透過发布标准格式的数据（如XML或JSON）来增强。

程序组件之间的松耦合可以透過使用标准数据类型参数来增强。传递自定义数据类型或对象需要组件双方了解自定义数据的定义。

服务的松耦合可以透過减少给服务传入的关键数据的信息来增强。例如，当只有客户标识传入并且客户地址在服务内获取，服务发送一个字母是最可重用的。这将解耦服务，因为服务不需要按特定的顺序调用（如：GetCustomerAddress，SendLetter）

 编程 
耦合是指一个组件直接了解其他组件的程度。运算中的松耦合解释为封装与无封装。

紧耦合的一个例子发生在依赖类直接包含一个提供所需行为的具体类的指针。在不改变依赖类的情况下，无法替换依赖，或改变“签名”。松耦合发生在依赖类只包含接口的指针，接口可以由一个或多个具体类实现。依赖类只依赖接口指定的“契约”：实现类必须提供的方法和/或属性的定义列表。任何实现了接口的类就可以满足依赖类的依赖而无需修改类。这使得软件设计具有可扩展性；无需改变依赖类，可以编写一个新类实现接口来取代当前的依赖在部分或全部的情况下；新老类可以自由交换。强耦合不允许这样做。

这个UML图说明依赖类和一组提供所需行为的具体类之间的松耦合的例子：

File:Loose_Coupling_Example.JPG

相比之下,这个图表显示了强的替代设计相关类之间的耦合和提供者:

File:Strong_Coupling_Example.JPG

 松耦合的其他形式 
拥有作为核心模块的函数（参见函数式编程）或函数对象的计算机编程语言提供了松耦合编程的极好的例子。函数式语言拥有续体、闭包或生成器等模式。函数式编程语言的例子参见Clojure和Lisp。Smalltalk和Ruby等面向对象的语言拥有代码块，而Eiffel拥有agent。基本思想是具象化(封装为对象)独立于任何其他封闭概念的函数(例如将对象函数与封闭对象的任何直接知识解耦)。作为头等函数的一种形式，函数作为对象的更进一步知识参见头等函数。

例如，在面向对象的语言中，当对象的一个函数被引用为一个对象（无需了解包含他的宿主对象）时，新的函数对象可以传递，存储，稍后调用。（功能对象交给的）接收对象可以在自己方便的时候安全地执行(调用)所包含的函数，无需了解包含他的宿主对象。透過这种方式，一个程序可以执行功能对象的链或组，而安全地脱离拥有任何包含他们的宿主对象的直接引用。

电话号码是一个极好的类比，很容易说明这种分离的程度。

例如：一些实体为他人提供电话号码来完成一个特定的工作。当号码被呼叫时，呼叫者实体实际上说,“请帮我做这项工作。”解耦或松耦合是显而易见的。拿到号码的实体呼叫时可能并不了解号码从哪儿来的(例如号码提供者的引用)。另一方面，呼叫者和被呼叫者之间解耦了，无需知道他们是谁，他们在哪里，呼叫接收者内部是如何操作的。

将例子更进一步，呼叫者可能会对接收者说“请为我做这个工作。干完了用这个号码打电话回复我。”提供给接收者的“号码”称为“回调”。同样,这个函数对象的松耦合或分离性质是明显的。回调的接收者不知道调用的是谁。只知道它可以调用，并决定何时调用。在现实中，回调的可能都不是最初的提供者。这种级别的间接使函数对象成为实现松耦合程序的一个优秀技术。

 衡量数据元素耦合 
松耦合的程度可以透過记录发送或接收系统中可能发生的数据元素的变化数量来度量，并确定计算机是否仍然能够正确地进行通信。这些变化包括的项目如：
 添加新的数据元素到消息
 改变数据元素的顺序
 改变数据元素的名称
 改变数据元素的结构
 省略数据元素

 参阅 
 耦合性 (計算機科學)
 內聚性 (計算機科學)

 接口 (计算机科学)
 企业服务总线
 面向服务的架构
  (SBA)
 关注点分离
 得墨忒耳定律

 參考資料 

Category:服務導向
Category:企业应用集成
Category:编程原则