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?
Many integrated products (especially by Apple) such as iPods, iPads are a good example of tight coupling: once the battery dies you might as well buy a new device because the battery is soldered fixed and won't come loose, thus making replacing very expensive. A loosely coupled player would allow effortlessly changing the battery.
The same goes for software development: it is generally (much) better to have loosely coupled code to facilitate extension and replacement (and to make individual parts easier to understand). But, very rarely, under special circumstances tight coupling can be advantageous because the tight integration of several modules allows for better optimisation.
Tightly coupled code relies on a concrete implementation. If I need a list of strings in my code and I declare it like this (in Java)
then I'm dependent on the ArrayList implementation.
If I want to change that to loosely coupled code, I make my reference an interface (or other abstract) type.
This prevents me from calling any method on
myList
that's specific to the ArrayList implementation. I'm limited to only those methods defined in the List interface. If I decide later that I really need a LinkedList, I only need to change my code in one place, where I created the new List, and not in 100 places where I made calls to ArrayList methods.Of course, you can instantiate an ArrayList using the first declaration and restrain yourself from not using any methods that aren't part of the List interface, but using the second declaration makes the compiler keep you honest.
Consider a simple shopping cart application that uses a CartContents class to keep track of the items in the shopping cart and an Order class for processing a purchase. The Order needs to determine the total value of the contents in the cart, it might do that like so:
Tightly Coupled Example:
Notice how the OrderTotal method (and thus the Order class) depends on the implementation details of the CartContents and the CartEntry classes. If we were to try to change this logic to allow for discounts, we'd likely have to change all 3 classes. Also, if we change to using a List collection to keep track of the items we'd have to change the Order class as well.
Now here's a slightly better way to do the same thing:
Less Coupled Example:
The logic that is specific to the implementation of the cart line item or the cart collection or the order is restricted to just that class. So we could change the implementation of any of these classes without having to change the other classes. We could take this decoupling yet further by improving the design, introducing interfaces, etc, but I think you see the point.
Definition
Essentially, coupling is how much a given object or set of object relies on another object or another set of objects in order to accomplish its task.
High Coupling
Think of a car. In order for the engine to start, a key must be inserted into the ignition, turned, gasoline must be present, a spark must occur, pistons must fire, and the engine must come alive. You could say that a car engine is highly coupled to several other objects. This is high coupling, but it's not really a bad thing.
Loose Coupling
Think of a user control for a web page that is responsible for allowing users to post, edit, and view some type of information. The single control could be used to let a user post a new piece of information or edit a new piece of information. The control should be able to be shared between two different paths - new and edit. If the control is written in such a way that it needs some type of data from the pages that will contain it, then you could say it's too highly coupled. The control should not need anything from its container page.
Consider a Windows app with FormA and FormB. FormA is the primary form and it displays FormB. Imagine FormB needing to pass data back to its parent.
If you did this:
FormB is tightly coupled to FormA. FormB can have no other parent than that of type FormA.
If, on the other hand, you had FormB publish an event and have FormA subscribe to that event, then FormB could push data back through that event to whatever subscriber that event has. In this case then, FormB doesn't even know its talking back to its parent; through the loose coupling the event provides it's simply talking to subscribers. Any type can now be a parent to FormA.
rp
Loose coupling, in general, is 2 actors working independently of each other on the same workload. So if you had 2 web servers using the same back-end database, then you would say that those web servers are loosely coupled. Tight coupling would be exemplified by having 2 processors on one web server... those processors are tightly coupled.
Hope that's somewhat helpful.