Coupling and Cohesion in Java
Two questions tell you a lot about a design. How much does each class depend on the others? That's coupling, and you want it low: changing one class shouldn't force changes in many others. How focused is each class on one job? That's cohesion, and you want it high: everything inside a class should belong together. Nearly every design principle in the Object-Oriented Design chapter is a way of lowering coupling or raising cohesion.
Tight Coupling, Then Loose
public class Tight {
static class EmailSender {
void sendEmail(String to, String text) {
System.out.println("Email to " + to + ": " + text);
}
}
static class OrderService {
void placeOrder(String customer, long amount) {
// business logic ...
EmailSender sender = new EmailSender(); // welded in
sender.sendEmail(customer, "Order of Rs. " + amount + " placed");
}
}
}public class Loose {
interface Notifier {
void notify(String to, String text);
}
static class EmailNotifier implements Notifier {
public void notify(String to, String text) {
System.out.println("Email to " + to + ": " + text);
}
}
static class SmsNotifier implements Notifier {
public void notify(String to, String text) {
System.out.println("SMS to " + to + ": " + text);
}
}
static class OrderService {
private final Notifier notifier;
OrderService(Notifier notifier) { this.notifier = notifier; }
void placeOrder(String customer, long amount) {
notifier.notify(customer, "Order of Rs. " + amount + " placed");
}
}
public static void main(String[] args) {
new OrderService(new EmailNotifier()).placeOrder("Navika", 1299);
new OrderService(new SmsNotifier()).placeOrder("Advitha", 450);
}
}Email to Navika: Order of Rs. 1299 placed
SMS to Advitha: Order of Rs. 450 placedHow it works
- In the tightly coupled version,
OrderServicecreates anEmailSenderitself and calls its specific method. Switching to SMS, or testing without sending real emails, means editingOrderService. - In the loosely coupled version,
OrderServicedepends only on theNotifierinterface, and the actual notifier is passed in through the constructor. - The same
OrderServicecode sends an email for Navika and an SMS for Advitha. In a test, you could pass a fake notifier that just records messages.
Passing dependencies in from outside, instead of creating them inside, is called dependency injection. Frameworks like Spring automate it.
Coupling
| Tight coupling | Loose coupling |
|---|---|
Creates collaborators with new inside methods | Receives them through constructors |
| Depends on concrete classes | Depends on interfaces |
| Reaches into other objects' fields | Calls their public methods |
| One change ripples through many classes | Changes stay local |
| Hard to test in isolation | Easy to test with fakes |
Cohesion
A class with low cohesion does unrelated things. Imagine a Utility class with calculateGst, sendEmail, resizeImage and parseDate: every change to any feature touches it, and nobody can name what it's for. A highly cohesive class has one clear purpose and a name that says it: GstCalculator, EmailNotifier, InvoicePrinter.
| Low cohesion | High cohesion |
|---|---|
| "And" in the description: "saves orders and sends emails and prints PDFs" | One responsibility: "prices an order" |
| Methods share no fields | Methods work on the same data |
| Grows forever ("god class") | Stays small and stable |
| Hard to reuse or test | Easy to reuse and test |
Common Mistakes
new everywhere inside business logic. Each new ConcreteClass() is a hard-wired dependency; pass it in instead.
"Manager" and "Util" classes that collect everything. Split them by responsibility.
Interfaces for everything, even with one implementation that will never change. Loose coupling is a tool, not a rule; use it where change or testing is likely.
Interview Corner
What are coupling and cohesion?
Coupling is the degree to which one class depends on others; low coupling means classes interact through small, stable interfaces and can change independently. Cohesion is how closely the responsibilities inside one class are related; high cohesion means a class has a single, focused purpose. Good designs aim for low coupling and high cohesion, which makes code easier to change, test and reuse.
How do you reduce coupling in Java?
Program to interfaces rather than concrete classes, inject dependencies through constructors instead of creating them with new inside methods, keep fields private and expose behavior through methods, and keep each class's public surface small.
Practice
- Easy: Add a
WhatsAppNotifiertoLoose.javaand use it for Srihitha's order. Which classes did you have to change? - Harder: Write a
ReportServicethat loads data, formats it as text and saves it to a file, all in one class. Split it into three cohesive classes connected by interfaces.
Key Takeaways
Was this tutorial helpful?