Coupling and Cohesion

exercises
tutorial
java
coupling
cohesion

Applied class for Week 10 (no lecture this week). More practice applying java-cohesion-and-coupling (Week 6).

Coupling

Class coupling: the strength of the connection or dependence between classes — to what extent does this class depend on other classes? How many methods are called on how many other classes? Can another object influence the flow of control in this object?

Assume the following classes are all in separate files in the same package:

public class X {
    public int num = 5;
    protected Z z;

    public X(Z z) { this.z = z; }

    public void doThis() { sayHello(); }

    public void sayHello() { System.out.println("Hello"); }
}
public class Y extends X {
    public Y(Z z) { super(z); }

    public void doThat() { this.z.sayHello(); }

    @Override
    public void sayHello() { super.sayHello(); }
}
public class Z {
    private X x = new X();

    public void setNum(int num) { x.num = num; }

    public void sayHello() { System.out.println("Hello"); }
}

These classes are (unrealistically) tightly coupled. Identify the points of coupling between: (0) X and Y; (1) X and Z; (2) Y and Z — you don’t need to name the type/level of coupling, just where it occurs.

Class Coupling Implication
X stores a Z object X is coupled to Z
X constructor takes a Z X is coupled to Z
X doThis() just calls sayHello(), which is overridden in Y forwarding behaviour
Y constructor takes a Z Y is coupled to Z
Y constructor calls super(z) Y is coupled to X
Y doThat() accesses the protected this.z Y is coupled to Z and X
Y sayHello() calls X.sayHello() via super Y is coupled to X
Z stores an X object Z is coupled to X
Z setNum() accesses the public X.num Z is coupled to X

Cohesion — Customer

Class cohesion: how well components support a central purpose — how focused the components of a unit are. How well do the parts of the class (state and methods) fit together? Do they all contribute to a single, clear purpose?

public class Customer {
    private String name;
    private String streetAddress;
    private String suburb;
    private String postCode;
    private List<Item> orders; // the products that have been ordered

    public Customer(String name, String streetAddress, String suburb, String postCode) {
        this.name = name;
        this.streetAddress = streetAddress;
        this.suburb = suburb;
        this.postCode = postCode;
        this.orders = new ArrayList<>();
    }

    public String getName() { return name; }
    public String getMailingAddress() { return streetAddress + suburb + postCode; }
    public void newOrder(List<Item> order) { orders.addAll(order); }
    public List<Item> getAllOrder() { return orders; }
}

Does Customer exhibit high or low cohesion? Justify your answer.

Low cohesion:

  • name is only used once, in a single getter.
  • streetAddress/suburb/postCode are only used once, in a single getter — and these aren’t unique to a Customer, so belong in a separate class.
  • orders (with its getter and add method) isn’t cohesive with the rest of Customer’s representation, and could live in a dedicated Order-related class.

The grouping of member variables looks coincidental, and the methods have no clear relationship to each other’s functionality — the state and methods don’t contribute to a single, clear purpose.

If Customer doesn’t have high cohesion, design replacement classes with higher cohesion.

Customer is really trying to be at least three concepts at once: a customer, a mailing address, and a customer’s order history. Extract a postal-address abstraction (that Customer stores an instance of), and an order-history abstraction (stored by Customer, or managed separately).

Cohesion — Employee

public class Employee {
    private String firstName;
    private String surname;
    private String homeAddress;
    private String suburb;
    private String postCode;
    private String currentRole;
    private int currentRoleSecurityLevel;
    private int hourlyWage;

    public Employee(String fName, String lName, String homeAddress,
                     String suburb, String postCode, int hourlyWage) {
        this.firstName = fName;
        this.surname = lName;
        this.homeAddress = homeAddress;
        this.suburb = suburb;
        this.postCode = postCode;
        this.hourlyWage = hourlyWage;
    }

    public String getName() { return surname + ", " + firstName; }
    public String getMailingAddress() {
        return String.format("%s%n%s%n%s", homeAddress, suburb, postCode);
    }
    public void setRole(String newRole, int securityLevel) {
        currentRole = newRole;
        currentRoleSecurityLevel = securityLevel;
    }
    public String getCurrentRole() { return currentRole; }
    public boolean accessAllowed(int requiredSecurityLevel) {
        return currentRoleSecurityLevel >= requiredSecurityLevel;
    }
    public int getPay(int hoursWorked) { return hourlyWage * hoursWorked; }
    public void setHourlyWage(int newWage) { hourlyWage = newWage; }
}

Does Employee exhibit high or low cohesion? Justify your answer.

Low cohesion:

  • firstName/surname are only set in the constructor and returned by a single getter — better as a dedicated personal-details class, or simply a single name string.
  • The address fields are assigned once and used in a single getter — they appear arbitrarily grouped in this class and could live in a separate object.
  • The role fields (currentRole, currentRoleSecurityLevel) are used across several methods, but never interact with the name or address fields — this functionality could move to a Role class, shrinking Employee’s constructor and letting other objects reuse Role.

Employee is really trying to wrap the functionality of at least two other objects (address, role) inside itself; since the grouping of state appears coincidental rather than purposeful, Employee has low cohesion.