This article is more than 1 year old

Coupling and the power of accidental relationships

Emergent Design: break point

I reasoned that they did it because there was already a sensor on the brake pedal, for the brake light, and since there is no accelerate light, they would have had to add something to sense that the gas pedal was depressed.

This is bad coupling. The brake system and the transmission do not, logically, interconnect. My expectation did not include this as a possibility, and the reason the dealer forgets to tell people about this is that it is no more logical to him that it is to me. He does not remember.

I routinely forget to tell people about this rule when they are going to drive my car. It is not a rule that is explicitly part of braking or getting into gear. It was a kluge that was designed this way for the manufacturer's convenience. I imagine that someday, if my transmission needs to be fixed, the repairman will forget to hook up the line from the transmission to the brake pedal, and he too will think the thing is broken.

He will forget to hook it up because it is not expected, not intuitive, not logical that he should have to - even the dealer forgot, after all.

And this poor repairman will chase his tail for hours, trying to figure out why the car will not go into gear any more. And I will sympathize. I have had to maintain code.

Types of coupling

For emergent design, class coupling is going to be our primary concern. It can be broken down into four types.

  • Identity coupling. This is when one entity knows about the existence of another entity. It does not know how to use the other entity (does not access its public members), but simply knows that the entity, the type, exists. If a class A is designed to hold a collection of instances of class B, and needs to type check them when they are added to make sure they are indeed instances of B, then we have identity coupling from class A to class B.
  • Representational coupling. This is when one entity calls public methods or accesses public data members on another entity to fulfill part of its own responsibility. This is also coupling because if the public interface of the second entity changes, then the first entity needs to change too.
  • Subclass coupling. When a base type (usually class) has a number of derived types that extend it, other types should ideally only know about the base type. If all the subtypes share the same public interface (the public members inherited from the base type, overwritten for different behavior in each subclass), then outside "client" types can treat them all the same, as if they were the base class. If this is not so, if a client type knows specifics about the subtypes that exist, then this is subclass coupling to the polymorphic structure in question.
  • Inheritance coupling. A subclass is inherently coupled to its superclass, because changes in the superclass will cause changes to the subclass due to inheritance. This is usually a good and powerful kind of coupling, because it helps to eliminate redundancy in the subclasses. However, it needs to be kept under conscious control, and can certainly be overused.

Avoiding subclass coupling and making proper use of inheritance coupling is the subject of many of the design patterns we are going to explore a bit later, so we will leave that discussion for those chapters. However, identity and representational coupling are easy to illustrate. See the following code:

import java.util.*;
public class WidgetContainer {
  ArrayList myWidgetList = new ArrayList();

  public void addWidget(Widget aWidget) {
    myWidgetList.add(aWidget); 
  }

  public Iterator getWidgets() {
    return myWidgetList.iterator();
  }

}

public class Widget {
  public void widgetyBehavior() {
    System.out.println("Just being a Widget...");
  }

  public void storeSelf(WidgetContainer wc) {
    wc.addWidget(this);
  }
}

public class WidgetClient{
  public static void main(String[] args) {
    WidgetContainer myWidgetContainer = new WidgetContainer();
    for(int i=0; i<10; i++) {
      // Make a new widget, and have it store itself in the
      // container
      new Widget().storeSelf(myWidgetContainer);
    }
  }
}

Here we have WidgetClient creating 10 shiny new widgets, and then telling them to store themselves in a WidgetContainer. WidgetContainer has identity coupling to Widget. You can see this because of the following method references the type Widget:

 public void addWidget(Widget aWidget)

The parameter aWidget is declared to be of type Widget. But none of the methods on any aWidget are ever called, so there is no representational coupling here. Change Widget all you want, and WidgetContainer does not mind, but remove Widget entirely and WidgetContainer breaks. This is why it is called identity coupling, because WidgetContainer is coupled to the existence of Widget. It comes to us from the mathematical principle of identity (a = a). This coupling is good, logical, explicit; I like to call it intentional, because it makes perfect sense for a type-safe container of something to know that the something exists, and what its type is.

More about

TIP US OFF

Send us news


Other stories you might like