Skip to content
Part IA Michaelmas Term

Cohesion

What Cohesion Measures

Cohesion measures how strongly the responsibilities within a single class belong together. It is a measure of internal consistency — do all the fields and methods of the class work toward a single, well-defined purpose?

  • High cohesion (good): every field and every method contributes to the same goal
  • Low cohesion (bad): the class is a random grab-bag of unrelated functionality, thrown together by convenience rather than by design

High Cohesion: An Example

public class BankAccount {
    private String accountNumber;
    private double balance;
    private String holderName;

    public void deposit(double amount) { ... }
    public boolean withdraw(double amount) { ... }
    public double getBalance() { ... }
    public String getSummary() { ... }
}

Every field is directly used by every method. deposit and withdraw manipulate balance. getSummary uses all three fields to produce a description. All members orbit around the single concept of “bank account.” This is high cohesion.

Low Cohesion: An Example

public class Miscellaneous {
    private String accountNumber;    // used by banking methods
    private double balance;
    private int portNumber;          // used by networking methods
    private String hostName;
    private File logFile;            // used by logging methods

    public void deposit(double amount) { ... }
    public boolean withdraw(double amount) { ... }
    public void connect() { ... }
    public void disconnect() { ... }
    public void writeLog(String message) { ... }
    public String formatCurrency(double value) { ... }
}

The fields and methods form three distinct clusters that do not interact with each other. deposit and withdraw use accountNumber and balance but never touch portNumber or logFile. connect uses portNumber and hostName but never touches accountNumber. writeLog uses logFile but nothing else.

This is low cohesion — the members do not belong together. The class should be split into BankAccount, NetworkConnector, and Logger.

Levels of Cohesion (from Strongest to Weakest)

The course draws on a classic taxonomy of cohesion types:

Functional Cohesion (Strongest — Best)

All parts of the class contribute to a single, well-defined function. Every field and method is necessary for the class’s purpose. Removing any member would break the class.

public class EmailValidator {
    public boolean isValid(String email) {
        return hasAtSymbol(email)
            && hasValidDomain(email)
            && hasNoInvalidCharacters(email);
    }

    private boolean hasAtSymbol(String email) { ... }
    private boolean hasValidDomain(String email) { ... }
    private boolean hasNoInvalidCharacters(String email) { ... }
}

Every private helper is directly used by isValid. There are no stray fields or methods. This is the gold standard.

Informational Cohesion (Strong)

The class operates on the same data structure or resource. All methods access the same set of fields.

public class Rectangle {
    private double width;
    private double height;

    public double area() { return width * height; }
    public double perimeter() { return 2 * (width + height); }
    public boolean isSquare() { return width == height; }
}

All methods use width and height. The class is bound together by its shared state — informational cohesion.

Sequential Cohesion (Moderate)

Methods are grouped because the output of one is the input of the next. Together they form a processing pipeline.

public class ReportGenerator {
    public List<String> readLines(File file) { ... }
    public List<Record> parseRecords(List<String> lines) { ... }
    public String formatReport(List<Record> records) { ... }
}

The methods form a chain, but they do not operate on shared instance state — each takes input and produces output. Sequential cohesion is acceptable but weaker than informational.

Temporal Cohesion (Weak)

Methods are grouped because they are all called at the same time — for example, during initialisation or cleanup.

public class Initializer {
    public void initDatabase() { ... }
    public void initLogger() { ... }
    public void initNetwork() { ... }
    public void initCache() { ... }
}

These methods share no data and perform unrelated tasks. They happen to be called together (at startup), but they belong in different classes (Database, Logger, NetworkManager, Cache). Temporal cohesion is a warning sign.

Logical Cohesion (Weak)

Methods are grouped because they seem to fall under the same category, even though they do different things:

public class IOHandler {
    public void readFile(String path) { ... }
    public void writeFile(String path, String content) { ... }
    public void sendHttpRequest(String url) { ... }
    public void queryDatabase(String sql) { ... }
}

“Yes, these are all I/O” — but file I/O, HTTP, and database access have nothing in common in terms of code, state, or error handling. This is a God class in the making.

Coincidental Cohesion (Worst)

The class is a dumping ground for unrelated utilities with no thematic connection:

public class Utils {
    public static int stringToInt(String s) { ... }
    public static double celsiusToFahrenheit(double c) { ... }
    public static String formatDate(Date d) { ... }
    public static boolean isPrime(int n) { ... }
}

These methods share nothing — no state, no purpose, no relationship. The only thing binding them is the filename Utils.java. This is the lowest form of cohesion.

SRP vs Cohesion

Single Responsibility PrincipleCohesion
FocusExternal: why might this class need to change?Internal: how well do the members fit together?
Question”How many different stakeholders care about this class?""Do these methods share the same state and purpose?”
Violation symptomA class is modified for unrelated reasonsA class has clusters of members that never interact

A class can have low cohesion (methods that do not share state) while technically having one responsibility (if the responsibility is defined broadly enough). Conversely, a class can have high cohesion (all methods work on the same data) while violating SRP (if that data serves multiple unrelated stakeholders).

In practice, they are deeply correlated: low-cohesion classes almost always violate SRP, and SRP violations almost always manifest as low cohesion. The distinction matters primarily for the Tripos, which may ask you to define each separately.

Achieving High Cohesion

Practical strategies:

  1. Define one clear concept per class: if you cannot name the class with a single noun phrase, it is doing too much
  2. Keep methods operating on the same core state: every method should read or write at least one of the class’s fields
  3. Avoid convenience grouping: the fact that methods are called from the same place or at the same time is not a reason to put them in the same class
  4. Extract classes when clusters emerge: if you notice that certain fields are only used by a subset of methods, those members are a candidate for a new class