Java – Coupling Theory vs Reality in Design Patterns

couplingdesign-patternsjava

Coupling is defined as the knowledge one object has about another one, which describes how dependent they are. The more dependent, the worse, since changes in one would impact in the second. High coupling is bad, low coupling good. There are different coupling types.

Let's assume we talk about call coupling.

In Java, when A creates an object B and calls one of its methods it's said to be tightly coupled. But if we create an interface IB, used from A where B implements IB it's said to be loosely coupled. I don't see why since one change in the interface would have an impact in A and B. And one change in B would have an impact in IB and A. They still seem to be call coupled.

The same rationale applies to the Facade GoF design pattern. It's said it promotes low coupling, since we put an intermediary between a subsystem and the client code. In this case, it looks like we transferred the problem from the client code to the Facade. Since a change in the subsystem would have an impact on the Facade instead of the client code. The client code is no longer coupled to the subsystem but the Facade is.

I don't see how coupling is reduced.

This has been asked in: How is loose coupling achieved using interfaces in Java when an implementation class is mandatory and bound to interface contract?

But the answers are not specific enough. First, since encapsulation is also about treating objects as black boxes, the first answer does not specify any gain by using interfaces compared to regular classes (= tight coupling, in case it's all about black boxes). Therefore the answer is invalid. What interfaces provide is decoupling between the interface and the implementation when multiple implementations exist. But doesn't solve anything related to call coupling. May be the link provided above should add a new category called "implementation coupling". Regardless of this, the solution is still call coupled. In the second answer it mentions data coupling, but as far as I know the issue is about call coupling.

The rest of the answers are irrelevant.

Regarding "Design Patterns – Understanding Facade Pattern", I understand the Facade pattern. I'm only asking about the coupling reduced by the pattern. Which based on my reasoning is not reduced but transferred.

This subject has been treated but no proper answer has been given.

Best Answer

High coupling is bad, low coupling good.

I won't put it so black and white. Some coupling is necessary. Plus some roundabout ways to get rid of coupling can introduce too much overhead. In particular for applications that need to respond in real time. It is trade-offs.

Yes, you want to avoid high coupling. However, if introducing patterns in an attempt to lower coupling is preventing you from meeting your requirements first (which might include response time, time budgets, etc…) then it is not worth it.


In Java, when A creates an object B and calls one of its methods it's said to be tightly coupled. But if we create an interface IB, used from A where B implements IB it's said to be loosely coupled. I don't see why since one change in the interface would have an impact in A and B. And one change in B would have an impact in IB and A. They still seem to be call coupled.

Yes, they are still call coupled. Well, depends on how you define the metric. However, interfaces are not the right tool if you want to deal with that.

Regardless, with the interfaces, the classes would be loosely coupled in that A is not coupled directly to B. You could have other implementations of the interface.

A common anti-pattern is making an interface that matches what the consumed class offers. You should make an interface that matches what the consumer class needs. See interface segregation. The interface becomes a requirement for consumed class.

If you conceptualize the interface that way, the interface would change only when it is necesary for its consumers. When changing A, you can decide to change the interface or use a new one.

If we decide to change the interface when changing A, the change would propagate from A to B. Instead of it propagating from B to A. However, we do not have to decide to change the interface, or we can introduce an adapter that implement the interface and wraps B. That is, we have opportunities to stop the change from propagating. That is what we want. And that is what loose coupling (which is still coupling) buys us. We design to have more options, not less.

Again, that is not solving call coupling.


The same rationale applies to the Facade GoF design pattern. It's said it promotes low coupling, since we put an intermediary between a subsystem and the client code. In this case, it looks like we transferred the problem from the client code to the Facade. Since a change in the subsystem would have an impact on the Facade instead of the client code. The client code is no longer coupled to the subsystem but the Facade is.

The facade hides whatever you do behind it. It is similar to how an object encapsulates its state. The facade encapsulates a (sub)system. The consumer code only needs to talk to the facade and it is unaware of the details behind it.

Of course, it is still coupled. And yes, you have moved the problem to the Facade. However, thanks to the Facade, the consumer code does not have to change because of the changes of what is behind the facade.


But the answers are not specific enough. First, since encapsulation is also about treating objects as black boxes, the first answer does not specify any gain by using interfaces compared to regular classes (= tight coupling, in case it's all about black boxes)

If you use the class directly, then whatever the consumer code needs must be implemented by the class. If the consumer code uses an interface instead, then it does not have to be implemented by any particular class. You can change the class without the consumer code being aware of it. The consumer code has less knowledge, thus it is less coupled.


What interfaces provide is decoupling between the interface and the implementation when multiple implementations exist. But doesn't solve anything related to call coupling.

Correct, this is not about call coupling. You are the one narrowing the discussion to call coupling between two classes and an interface. And then wondering why they provide nothing.

Interfaces are not the right tool to deal with call coupling. Instead you want an event driven architecture, a consumer subscriber pattern, or similar. That way, there might not even be an implementation on the other side. Of course, some infrastructure might be required, if not provided by the language and runtime. Oh, this is Java, yeah, some infrastructure required.

Related Topic