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

时间:2010-05-14 05:32:21

标签: oop object coupling

任何人都能描述面向对象范式中松散耦合和紧耦合之间的确切差异吗?

16 个答案:

答案 0 :(得分:300)

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

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

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

松散耦合的类可以独立于其他(具体)类进行消费和测试。

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

紧耦合的例子:

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)
    {
    }
}

松散耦合的例子:

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)
    {
    }
}

另一个例子here

答案 1 :(得分:138)

没有任何代码的简单说明

摘要示例:

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

The Hat is "loosely coupled" to the body. This means you can easily take then hat off without making any changes to the the person/body. Picture Attribution: https://pixabay.com/en/greeting-cylinder-chapeau-dignity-317250/

紧耦合(详细示例)

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

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

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

松散耦合(详细示例)

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

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

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

为什么这一切都很重要?

这一点非常重要,因为软件一直在变化。一般来说,您希望能够轻松修改代码。 (它与另一种编码最佳实践相关联:开放式原则。这基本上意味着您应该能够轻松地添加到您的代码中,而不会改变任何东西(这怎么可能=>通过使用接口)。但这是另一个另一天的话题。)

计算中耦合的实际例子

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

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

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

摘要

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

Picture Attribution

答案 2 :(得分:65)

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

您可能会发现this paper by Martin Fowler (PDF)有帮助。

答案 3 :(得分:13)

一般情况下,紧耦合在很多时候都很糟糕,因为它降低了代码的灵活性和可重用性,使得更改变得更加困难,阻碍了可测试性等。

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

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

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

答案 4 :(得分:9)

当两个物体松散耦合时,它们可以相互作用,但对它们知之甚少 彼此。

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

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

答案 5 :(得分:5)

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

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

答案 6 :(得分:4)

blog post关于耦合的摘录:

什么是紧耦合: -

如上所述,紧密耦合对象是一个需要了解其他对象的对象,并且通常高度依赖于彼此的接口。

当我们在紧密耦合的应用程序中更改一个对象时,通常需要更改许多其他对象。在小型应用程序中没有问题我们可以轻松识别变化。但是在大型应用程序的情况下,每个消费者或其他开发人员并不总是知道这些相互依赖性,或者未来有很多机会进行更改。

让我们拿一个购物车演示代码来理解紧耦合:

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);
        }
    }
}

以上示例的问题

紧耦合造成一些困难。

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

答案 7 :(得分:3)

某些工具通过其库提供依赖注入,例如在.net中我们有ninject Library

如果你在java中更进一步,那么spring提供了这种功能。

可以通过在代码中引入接口来实现松散耦合的对象,这就是这些来源的作用。

在你的代码中说你正在写

Myclass m = new Myclass();

现在你方法中的这句话说你依赖于myclass这被称为紧耦合。现在你提供一些构造函数注入,或属性注入和实例化对象,然后它将变得松散耦合。

答案 8 :(得分:3)

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

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

答案 9 :(得分:2)

松散耦合是对旧式硬编码依赖项和相关问题的回答,例如在任何更改和代码重用时频繁重新编译。它强调在组件中实现工作逻辑并避免解决方案特定的连线代码。

松散耦合= IoC 有关更简单的说明,请参阅this

答案 10 :(得分:2)

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

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

例如,我们有一个系统可以以两种或多种方式发送输出,如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();
    }
}

在上面的示例中,如果我们想要更改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();
    }
}

答案 11 :(得分:1)

松散耦合是在没有提供依赖关系的所有信息的情况下间接地给出类所需的依赖关系的过程(即在接口的from中),如果紧密耦合你直接给出依赖关系,这不是编码的好方法。

答案 12 :(得分:1)

它是关于依赖率的类到另一个松散耦合如此之低并且紧密耦合的如此之高。要明确 面向服务架构 ,服务将相互松散地耦合 对抗单片 哪些类依赖于彼此是有目的的

答案 13 :(得分:0)

如果一个对象的创建/存在依赖于另一个无法定制的对象,则其紧密耦合。并且,如果可以定制依赖项,则其松散耦合。考虑一下Java中的示例:

class Car {

    private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
    // Other parts

    public Car() { 
        // implemenation 
    }

}

Car类的客户端只能使用“ X_COMPANY”引擎创建一个客户端。

考虑通过改变这种能力来打破这种耦合:

class Car {

    private Engine engine;
    // Other members

    public Car( Engine engine ) { // this car can be created with any Engine type
        this.engine = engine;
    }

}

现在,Car不依赖于“ X_COMPANY”引擎,因为它可以使用类型创建。

Java特定说明:仅出于解耦目的而使用Java接口不是适当的设计方法。在Java中,接口的目的是-充当契约,本质上提供去耦行为/优势。

比尔·罗斯姆斯(Bill Rosmus)在接受的答案中的评论有很好的解释。

答案 14 :(得分:0)

这里使用类比有很多不错的答案,但是工作中的一位朋友给了我一个例子,我比这里提到的所有事物都更喜欢……眼睛和眼镜!

紧密耦合

紧密耦合将是眼睛。如果我想固定视力,则进行眼科手术的费用并不昂贵,并且存在相当大的风险。但是,如果设计师(人类)找到了更好的方法该怎么办。将loosely coupled的特征添加到主体,以便可以轻松更改它! (是。眼镜)

松散耦合

我可以轻松更换眼镜而不会破坏我的基本视力。我可以摘下眼镜,而我的眼光将是以前的样子(不分好坏)。使用不同的眼镜会改变我们通过眼睛观察世界的方式,风险很小且易于维护。

摘要

因此,下次有人问您“谁在乎我的代码是否紧密耦合?”答案全在于变革的努力,维护的努力和变革的风险。

那么如何在c#中完成呢? InterfacesDependency Injection

编辑

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

答案 15 :(得分:0)

紧密耦合意味着类和对象相互依赖。通常,紧密耦合通常不好,因为它会降低代码的灵活性和可重用性,而松散耦合则意味着减少直接使用不同类的类的依赖。

紧密联轴器 紧密耦合的对象是需要了解其他对象的对象,通常高度依赖于彼此的接口。 在紧密耦合的应用程序中更改一个对象通常需要更改许多其他对象。 在小型应用程序中,我们可以轻松识别更改,错过任何内容的机会都更少。但是在大型应用程序中,并不是每个程序员都知道这些相互依赖关系,因此有可能忽略更改。 示例:

    class A {
       public int a = 0;
       public int getA() {
          System.out.println("getA() method");
          return a;
       }
       public void setA(int aa) {
          if(!(aa > 10))
             a = aa;
       }
    }
    public class B {
       public static void main(String[] args) {
          A aObject = new A();
          aObject.a = 100; // Not suppose to happen as defined by class A, this causes tight coupling.
          System.out.println("aObject.a value is: " + aObject.a);
       }
    }

In the above example, the code that is defined by this kind of implementation uses tight coupling and is very bad since class B knows about the detail of class A, if class A changes the variable 'a' to private then class B breaks, also class A's implementation states that variable 'a' should not be more than 10 but as we can see there is no way to enforce such a rule as we can go directly to the variable and change its state to whatever value we decide.

    Output
    aObject.a value is: 100

Loose Coupling
Loose coupling is a design goal to reduce the inter-dependencies between components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Loose coupling is a much more generic concept intended to increase the flexibility of the system, make it more maintainable and makes the entire framework more stable.
Example:

class A {
   private int a = 0;
   public int getA() {
      System.out.println("getA() method");
      return a;
   }
   public void setA(int aa) {
      if(!(aa > 10))
         a = aa;
   }
}
public class B {
   public static void main(String[] args) {
      A aObject = new A();
      aObject.setA(100); // No way to set 'a' to such value as this method call will
                         // fail due to its enforced rule.
      System.out.println("aObject value is: " + aObject.getA());
   }
}

在上面的示例中,由这种实现定义的代码使用松耦合,因此建议使用该代码,因为类B必须经过类A才能获得其强制执行规则的状态。如果在内部更改A类,则B类不会中断,因为它仅使用A类作为通信方式。

Output
getA() method
aObject value is: 0