What is “loose coupling?” Please provide examples

2019-01-03 04:10发布

I can't seem to grok the concept of "loose coupling." I suppose it doesn't help that the word "loose" usually has a negative connotation, so I always forget that loose coupling is a good thing.

Will somebody please show some "before" and "after" code (or pseudocode) that illustrates this concept?

20条回答
成全新的幸福
2楼-- · 2019-01-03 04:27

The degree of difference between answers here shows why it would be a difficult concept to grasp but to put it as simply as I can describe it:

In order for me to know that if I throw a ball to you, then you can catch it I really dont need to know how old you are. I dont need to know what you ate for breakfast, and I really dont care who your first crush was. All I need to know is that you can catch. If I know this, then I dont care if its you I am throwing a ball to you or your brother.

With non-dynamic languages like c# or Java etc, we accomplish this via Interfaces. So lets say we have the following interface:

public ICatcher
{
   public void Catch();
}

And now lets say we have the following classes:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

Now both CatcherA and CatcherB implement the Catch method, so the service that requires a Catcher can use either of these and not really give a damn which one it is. So a tightly coupled service might directly instanciate a catched i.e.

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

So the CatchService may do exactly what it has set out to do, but it uses CatcherA and will always user CatcherA. Its hard coded in, so its staying there until someone comes along and refactors it.

Now lets take another option, called dependency injection:

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

So the calss that instansiates CatchService may do the following:

CatchService catchService = new CatchService(new CatcherA());

or

CatchService catchService = new CatchService(new CatcherB());

This means that the Catch service is not tightly coupled to either CatcherA or CatcherB.

There are several other stratergies for loosly coupling services like this such as the use of an IoC framework etc.

查看更多
贪生不怕死
3楼-- · 2019-01-03 04:27

In computer science there is another meaning for "loose coupling" that no one else has posted about here, so... Here goes - hopefully you'll give me some votes up so this isn't lost at the bottom of the heap! SURELY the subject of my answer belongs in any comprehensive answer to the question... To wit:

The term "Loose Coupling" first entered computing as a term used as an adjective regarding CPU architecture in a multi-CPU configuration. Its counterpart term is "tight coupling". Loose Coupling is when CPUs do not share many resources in common and Tight Coupling is when they do.

The term "system" can be confusing here so please parse the situation carefully.

Usually, but not always, multiple CPUs in a hardware configuration in which they exist within one system (as in individual "PC" boxes) would be tightly coupled. With the exception of some super-high-performance systems that have subsystems that actually share main memory across "systems", all divisible systems are loosely coupled.

The terms Tightly Coupled and Loosely Coupled were introduced before multi-threaded and multi-core CPUs were invented, so these terms may need some companions to fully articulate the situation today. And, indeed, today one may very well have a system that encompases both types in one overall system. Regarding current software systems, there are two common architectures, one of each variety, that are common enough these should be familliar.

First, since it was what the question was about, some examples of Loosely Coupled systems:

  • VaxClusters
  • Linux Clusters

In contrast, some Tightly Coupled examples:

  • Semetrical-Multi-Processing (SMP) Operating systems - e.g. Fedora 9
  • Multi-threaded CPUs
  • Multi-Core CPUs

In today's computing, examples of both operating in a single overall system is not uncommon. For example, take modern Pentium dual or quad core CPUs running Fedora 9 - these are tightly-coupled computing systems. Then, combine several of them in a loosely coupled Linux Cluster and you now have both loosely and tightly coupled computing going on! Oh, isn't modern hardware wonderful!

查看更多
\"骚年 ilove
4楼-- · 2019-01-03 04:30

You can read more about the generic concept of "loose coupling".

In short, it's a description of a relationship between two classes, where each class knows the very least about the other and each class could potentially continue to work just fine whether the other is present or not and without dependency on the particular implementation of the other class.

查看更多
疯言疯语
5楼-- · 2019-01-03 04:32

Sorry, but "loose coupling" is not a coding issue, it's a design issue. The term "loose coupling" is intimately related to the desirable state of "high cohesion", being opposite but complementary.

Loose coupling simply means that individual design elements should be constructed so the amount of unnecessary information they need to know about other design elements are reduced.

High cohesion is sort of like "tight coupling", but high cohesion is a state where design elements that really need to know about each other are designed so that they work together cleanly and elegantly.

The point is, some design elements should know details about other design elements, so they should be designed that way, and not accidentally. Other design elements should not know details about other design elements, so they should be designed that way, purposefully, instead of randomly.

Implementing this is left as an exercise for the reader :) .

查看更多
看我几分像从前
6楼-- · 2019-01-03 04:33

Coupling has to do with dependencies between systems, which could be modules of code (functions, files, or classes), tools in a pipeline, server-client processes, and so forth. The less general the dependencies are, the more "tightly coupled" they become, since changing one system required changing the other systems that rely on it. The ideal situation is "loose coupling" where one system can be changed and the systems depending on it will continue to work without modification.

The general way to achieve loose coupling is through well defined interfaces. If the interaction between two systems is well defined and adhered to on both sides, then it becomes easier to modify one system while ensuring that the conventions are not broken. It commonly occurs in practice that no well-defined interface is established, resulting in a sloppy design and tight coupling.

Some examples:

  • Application depends on a library. Under tight coupling, app breaks on newer versions of the lib. Google for "DLL Hell".

  • Client app reads data from a server. Under tight coupling, changes to the server require fixes on the client side.

  • Two classes interact in an Object-Oriented hierarchy. Under tight coupling, changes to one class require the other class to be updated to match.

  • Multiple command-line tools communicate in a pipe. If they are tightly coupled, changes to the version of one command-line tool will cause errors in the tools that read its output.

查看更多
乱世女痞
7楼-- · 2019-01-03 04:34

Two components are higly coupled when they depend on concrete implementation of each other.

Suppose I have this code somewhere in a method in my class:

this.some_object = new SomeObject();

Now my class depends on SomeObject, and they're highly coupled. On the other hand, let's say I have a method InjectSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

Then the first example can just use injected SomeObject. This is useful during testing. With normal operation you can use heavy, database-using, network-using classes etc. while for tests passing a lightweight, mock implementation. With tightly coupled code you can't do that.

You can make some parts of this work easer by using dependency injection containers. You can read more about DI at Wikipedia: http://en.wikipedia.org/wiki/Dependency_injection.

It is sometimes easy to take this too far. At some point you have to make things concrete, or your program will be less readable and understandable. So use this techniques mainly at components boundary, and know what you are doing. Make sure you are taking advantage of loose coupling. If not, you probably don't need it in that place. DI may make your program more complex. Make sure you make a good tradeoff. In other words, maintain good balance. As always when designing systems. Good luck!

查看更多
登录 后发表回答