面向对象范式中的松耦合和紧耦合有什么区别?

Jim*_*Jim 256 oop coupling object

在面向对象的范例中,任何人都可以描述松散耦合和紧耦合之间的确切区别吗?

Jon*_*han 321

紧耦合是指一组类高度依赖彼此的情况.

当一个类承担太多责任,或者当一个问题分散在许多类而不是拥有自己的类时,就会出现这种情况.

通过促进单一责任和关注点分离的设计实现松耦合.

松散耦合的类可以独立于其他(具体)类来使用和测试.

接口是用于解耦的强大工具.类可以通过接口而不是其他具体类进行通信,只需通过实现接口,任何类都可以在该通信的另一端.

紧耦合的例子:

class CustomerRepository
{
    private readonly Database database;

    public CustomerRepository(Database database)
    {
        this.database = database;
    }

    public void Add(string CustomerName)
    {
        database.AddRow("Customer", CustomerName);
    }
}

class Database
{
    public void AddRow(string Table, string Value)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

松耦合示例:

class CustomerRepository
{
    private readonly IDatabase database;

    public CustomerRepository(IDatabase database)
    {
        this.database = database;
    }

    public void Add(string CustomerName)
    {
        database.AddRow("Customer", CustomerName);
    }
}

interface IDatabase
{
    void AddRow(string Table, string Value);
}

class Database : IDatabase
{
    public void AddRow(string Table, string Value)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

另一个例子在这里.

  • Java接口是可以帮助它的工具.但是它们不是必需的.接口的程序概念而不是实现意味着对公共方法/属性的程序(或者当语言不支持访问修饰符时,外部调用者要使用的方法/属性,如C).该接口应该通过不改变来兑现这个隐含的合同.在没有访问修饰符(如C)的语言中,它意味着仅使用已发布的接口/函数而不是那些内部使用的接口/函数,因为这些可能会根据需要进行更改以支持已发布的函数. (4认同)
  • 我有点困惑为什么这个答案被接受并且有这么多的赞成票。总体解释是基本和抽象的,就像维基百科的摘要一样。这些例子没有说明任何事情。“紧耦合”示例似乎没有任何问题,而“松耦合”示例似乎没有解决任何问题。换句话说,除了增加复杂性之外,添加接口还有什么作用? (4认同)
  • @jonathanconway谢谢先生,但两段代码都做同样的事情:那么它们之间的区别是什么?那松散耦合有什么优势? (3认同)
  • 观察者模式描述如下:http://en.wikipedia.org/wiki/Observer_pattern。由于Subject 类可以维护一个从'Observer' 继承的类的列表,而实际上并不知道这些类的具体类型,这是松耦合的一个实例。主体不依赖于任何观察者或其内部关注点。观察者不依赖于主题或其任何关注点。 (2认同)

BKS*_*eon 157

没有任何代码的简单说明

摘要示例:

帽子与身体"松散耦合".这意味着您可以轻松取下帽子,而无需对人/身体进行任何更改.当你可以做到这一点,那么你有"松耦合".请参阅下面的详细说明.

帽子与身体

紧耦合(详细示例)

想想你的皮肤.它贴在你的身上.它像手套一样适合.但是如果你想改变肤色从白色到黑色怎么办?你能想象剥掉你的皮肤,染上它然后把它贴回去等会有多痛苦吗?改变你的皮肤是很困难的,因为它与你的身体紧密相连.你不能轻易做出改变.你必须从根本上重新设计一个人,以使这成为可能.

  • 关键点#1:换句话说,如果你想改变皮肤,你也必须改变你的身体设计,因为两者是连在一起的 - 它们是紧密耦合的.

上帝不是一个好的面向对象的程序员.

松耦合(详细示例)

现在想想早上穿衣服.你不喜欢蓝色吗?没问题:你可以换上红色衬衫.你可以轻松,轻松地做到这一点,因为衬衫并没有像你的皮肤一样真正地连接到你的身体.衬衫不知道或不关心它正在发生什么样的身体.换句话说,你可以换衣服,而不用改变你的身体.

  • 这是关键点#2.如果你更换你的衬衫,那么你就不会被迫改变你的身体 - 当你能做到这一点时,你就会松耦合.如果你不能这样做,那么你有紧耦合.

简而言之,这就是基本概念.

为什么这一切都很重要?

这很重要,因为软件一直在变化.一般来说,您希望能够轻松修改代码.

计算中耦合的实例

  • 如果有人想要他们的输出是CSV文件而不是JSON等,或者如果你想从MySQL切换到PostGreSQL,你应该能够在你的代码中非常容易地进行这些更改,而不必重写整个类等.换句话说,您不希望将应用程序与特定数据库实现(例如Mysql)或特定输出(例如CSV文件)紧密耦合.因为,正如软件中不可避免的那样,变化将会到来.当他们来的时候,如果你的代码部分松散耦合,那就容易多了.

另一个例子:汽车和备件类似于耦合

  • 如果有人想要他们的车黑色的,你不应该为了这样做而重新设计整辆车.汽车及其备件将是松散耦合架构的完美示例(根据@ mnmopazem的评论).如果你想用更好的发动机更换你的发动机,你应该可以简单地拆下你的发动机而不需要太多努力,并将它换成更好的发动机.如果您的车只适用于劳斯莱斯1234发动机而没有其他发动机 - 那么您的车将紧密连接到该发动机(劳斯莱斯1234).如果你改变你的汽车的设计以便它可以与任何引擎一起工作会更好,这样它就会更松散地与它的组件结合.更好的是,如果你的车可以在不需要引擎的情况下工作!一定程度的耦合会发生,但你应该尽可能地减少它.为什么?因为当需求发生变化时,我们仍然应该能够非常快速地提供高质量的软件,并通过松散耦合帮助实现这一目标.

摘要

简而言之,松散耦合使代码更容易更改.上面的答案提供了一些值得阅读的代码.

图片归因.

  • 对于新程序员来说,这是一个被低估的解释.很难通过我们推出的其他一些大词,一旦你理解了基础,那么它更容易去大词lol (8认同)
  • 非常有创意地解释。我与这个答案紧密相连。 (4认同)
  • 有些事物必须与环境紧密耦合,而有些则必须与其环境松散耦合。使用皮肤不是紧密耦合的适当类比。如果认为皮肤与身体紧密结合,那么其他部分也是如此。身体(作为一个整体)必须具有零件(紧密集成)才能正常运行(可能是自然界的想法-一个出色的建筑师)。如果将这些零件设计成可更换的(就像更换帽子一样简单),那么“人体”的含义就失去了其定义。评论1/2。 (3认同)
  • 举个例子,如果皮肤是可更换的,那么头部也必须重新更换。如果发生这种情况,那么从一次见面到另一次见面可能就无法认清人们。一个很好的紧密/松散耦合比喻是-汽车及其零件,计算机及其零件等...如果计算机的鼠标/键盘有问题,可以将其替换为另一零件,而不是使整个计算机失效扔掉 评论2/2。 (3认同)

Don*_*kby 69

在面向对象的设计中,耦合量是指一个类的设计取决于另一个类的设计.换句话说,A类的变化多长时间与B类的变化相关?紧耦合意味着两个类通常一起变化,松散耦合意味着它们大多是独立的.通常,建议使用松耦合,因为它更容易测试和维护.

您可能会发现Martin Fowler撰写的这篇论文(PDF)很有帮助.


Jom*_*rge 14

一般情况下,Tight Coupling很糟糕,但大部分时间都是如此,因为它降低了代码的灵活性和可重用性,使得更改变得更加困难,阻碍了可测试性等.

紧密耦合对象是一个需要彼此了解很多的对象,并且通常高度依赖于彼此的接口.在紧密耦合的应用程序中更改一个对象通常需要更改许多其他对象.在小型应用程序中,我们可以轻松识别更改,并且错过任何内容的机会较少.但是在大型应用程序中,每个程序员并不总是知道这些相互依赖关系,或者有机会错过更改.但是每组松散耦合的对象都不依赖于其他对象.

简而言之,我们可以说松散耦合是一个设计目标,旨在减少系统组件之间的相互依赖性,目的是降低一个组件中的更改需要更改任何其他组件的风险.松散耦合是一个更通用的概念,旨在提高系统的灵活性,使其更易于维护,并使整个框架更"稳定".

耦合指的是一个元素与另一个元素的直接知识的程度.我们可以说例如:A和B,只有当A改变其行为时,B才会改变它的行为.松散耦合的系统可以很容易地分解成可定义的元素.


小智 10

当两个物体松散耦合时,它们可以相互作用但彼此之间的知识很少.

松散耦合的设计使我们能够构建可以处理变化的灵活OO系统.

观察者设计模式是使类松散耦合的一个很好的例子,您可以在维基百科中查看它.


小智 10

紧耦合意味着一个类依赖于另一个类。
松耦合意味着一个类依赖于接口而不是类。

紧耦合中,方法中声明了硬编码的依赖项。
松散耦合中,我们必须在运行时从外部传递依赖而不是硬编码。(松散耦合系统使用接口来减少对类的依赖。)

例如,我们有一个系统可以以两种或多种方式发送输出,如 JSON 输出、CSV 输出等。

紧耦合

public interface OutputGenerator {
    public void generateOutput();
}

public class CSVOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("CSV Output Generator");
    }
}

public class JSONOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("JSON Output Generator");
    }
}

// In Other Code, we write Output Generator like...
public class Class1 {
    public void generateOutput() {
        // Here Output will be in CSV-Format, because of hard-coded code.
        // This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
        // Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
        OutputGenerator outputGenerator = new CSVOutputGenerator();
        output.generateOutput();
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,如果我们想改变 JSON 中的输出,那么我们需要在整个代码中查找和改变,因为 Class1 与 CSVOutputGenerator 类紧密耦合。

松耦合

public interface OutputGenerator {
    public void generateOutput();
}

public class CSVOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("CSV Output Generator");
    }
}

public class JSONOutputGenerator implements OutputGenerator {
    public void generateOutput() {
        System.out.println("JSON Output Generator");
    }
}

// In Other Code, we write Output Generator like...
public class Class1 {
    public void generateOutput(OutputGenerator outputGenerator) {
        // if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
        // if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)

        // Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
        // Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
        OutputGenerator outputGenerator = outputGenerator;
        output.generateOutput();
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

松耦合意味着两个组件之间的依赖程度非常低。
示例:GSM SIM

紧耦合意味着两个组件之间的依赖程度非常高。
示例:CDMA 移动


小智 5

我理解的是,与松耦合架构相比,紧耦合架构不能提供很大的变更灵活性.

但是在松散耦合的体系结构的情况下,消息格式或操作平台或改进业务逻辑不会影响另一端.如果系统被拆除进行改造,当然另一端将无法访问服务一段时间,但除此之外,未改变的一端可以恢复与改造之前的消息交换.


小智 5

我关于耦合的博客文章的摘录:

什么是紧耦合

如上定义,紧密耦合对象是需要了解其他对象的对象,通常高度依赖于彼此的接口。

当我们在紧密耦合的应用程序中更改一个对象时,通常需要更改许多其他对象。在小型应用程序中没有问题,我们可以轻松识别更改。但是,在大型应用程序中,并非每个消费者或其他开发人员都总是知道这些相互依存关系,否则将来更改的可能性很大。

让我们以购物车演示代码来了解紧密耦合:

namespace DNSLooseCoupling
{
    public class ShoppingCart
    {
        public float Price;
        public int Quantity;

        public float GetRowItemTotal()
        {
            return Price * Quantity;
        }
    }

    public class ShoppingCartContents
    {
        public ShoppingCart[] items;

        public float GetCartItemsTotal()
        {
            float cartTotal = 0;
            foreach (ShoppingCart item in items)
            {
                cartTotal += item.GetRowItemTotal();
            }
            return cartTotal;
        }
    }

    public class Order
    {
        private ShoppingCartContents cart;
        private float salesTax;

        public Order(ShoppingCartContents cart, float salesTax)
        {
            this.cart = cart;
            this.salesTax = salesTax;
        }

        public float OrderTotal()
        {
            return cart.GetCartItemsTotal() * (2.0f + salesTax);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的例子有问题

紧密耦合会产生一些困难。

在这里,OrderTotal()方法为我们提供了购物车中当前物品的完整金额。如果我们要在此购物车系统中添加折扣功能。在上面的代码中很难做到这一点,因为我们必须在每个类上进行更改,因为它们之间紧密耦合。


Joh*_*ris 5

这里使用类比有很多很好的答案,但工作中的一个朋友给了我一个例子,我比这里提到的所有那些都更喜欢......眼睛和眼镜!

紧耦合

紧耦合将是眼睛。如果我想修复我的视力,我进行眼部移植手术并不昂贵,而且风险相当大。但是,如果设计师(作为人类)找到了更好的方法呢?添加与主体松散耦合的功能,以便轻松更改!(是的……眼镜)

松耦合

我可以轻松更换眼镜而不会破坏我的基本视力。我可以摘下眼镜,我的视力会和以前一样(不会更好或更糟)。使用不同的眼镜改变了我们通过眼睛看世界的方式,风险很小,易于维护。

概括

所以下次有人问你“谁在乎我的代码是否紧密耦合?” 答案是关于改变的努力、维持的努力和改变的风险。

那么这是如何在 C# 中完成的呢?接口和依赖注入!

编辑

这也是装饰者模式的一个很好的例子,其中眼睛是我们通过满足界面要求但提供不同功能(例如太阳镜、老花镜、珠宝商放大镜等)来装饰的类