Java Omnibus
OOAD & Architecture / Design principles / Single Responsibility Principle in Java
Design Principles Java Order Management
Design Principles

The Single Responsibility Principle is really about cohesive responsibility, not just small class size.

SRP is often summarized as “a class should have one reason to change.” That wording becomes useful when you interpret it through business responsibility instead of line count. A class can be small and still contain mixed concerns. It can be fairly large and still be cohesive if all of its behavior serves one clear purpose.

Why This Topic Matters

Why it matters in real Java systems

In order-management systems, one workflow often drifts into pricing, payment, shipment, fraud, notification, persistence, and metrics. SRP helps you stop asking “is this class too long?” and start asking “does this behavior belong to the same responsibility boundary?”

Core Explanation

The design idea behind this topic

SRP is a cohesion principle. It asks whether a unit of code answers one main design question. In OOAD work, that usually means one business concern, one coordination concern, or one focused policy concern.

In Java, SRP often leads to cleaner use-case classes, focused domain policies, and better package boundaries. It does not mean every helper becomes a new class. Splitting behavior only helps if the new boundaries make the model easier to explain and evolve.

The best SRP test is often conversational: can you explain why this class exists in one sentence without using “and” three times?

Concept Breakdown

Key ideas to hold onto

Concept

One reason to change

A change in payment policy should not force a shipment-specific class to change with it.

Concept

Cohesion over size

The question is whether the behavior belongs together, not whether the class fits an arbitrary length rule.

Concept

Useful seams

SRP creates seams for testing, extension, and ownership when responsibilities are truly distinct.

Java Example

Java example in the Order Management domain

Java example: removing mixed responsibilities from checkout
package org.javaomnibus.ecommerce.principles;

public final class CheckoutCoordinator {
    private final OrderPricingService orderPricingService;
    private final PaymentAuthorizer paymentAuthorizer;
    private final ShipmentStarter shipmentStarter;

    public CheckoutCoordinator(
        OrderPricingService orderPricingService,
        PaymentAuthorizer paymentAuthorizer,
        ShipmentStarter shipmentStarter
    ) {
        this.orderPricingService = orderPricingService;
        this.paymentAuthorizer = paymentAuthorizer;
        this.shipmentStarter = shipmentStarter;
    }

    public void checkout(Order order) {
        orderPricingService.calculate(order);
        paymentAuthorizer.authorize(order);
        shipmentStarter.start(order);
    }
}

interface OrderPricingService { void calculate(Order order); }
interface PaymentAuthorizer { void authorize(Order order); }
interface ShipmentStarter { void start(Order order); }
record Order(String orderId) {}
Code Walkthrough

Step by step

  1. CheckoutCoordinator owns the coordination responsibility only.
  2. Pricing, payment, and shipment each sit behind one clearer reason to change.
  3. If shipment rules change, pricing behavior does not need to be edited in the same place.
  4. The result is not just smaller code. It is more honest design ownership.
Real-World Usage

Where this shows up in practice

  • Breaking apart God services that have become default homes for new rules
  • Clarifying package ownership in systems where every team touches the same service layer
  • Reducing change amplification during business rule updates
Trade-Offs

When not to over-apply it

Taken too literally, SRP can fragment a design into dozens of tiny types with weak conceptual separation. The principle works best when you use it to improve cohesion, not to maximize the number of classes.

Common Mistakes

Frequent mistakes to watch for

  • Measuring SRP by class length alone
  • Splitting code without clarifying who owns the overall use case
  • Ignoring package and module responsibility while focusing only on single classes
  • Creating helper classes that are still really mixed in purpose
Related Pages

Related concepts


What To Read Next