Open/Closed Principle (OCP) — open for extension, closed for modification
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
The Open/Closed Principle means designing a stable part of the system so an expected variation can be added through an extension point rather than repeatedly editing the central logic. 'Closed' is relative to that chosen kind of change, not to every future requirement.
For example, a checkout service can depend on a PaymentGateway interface. Card and UPI adapters implement the contract, while the checkout flow continues to validate the cart, request payment, and record the result. A new provider mainly adds an adapter; configuration and tests may still be updated to register and verify it.
OCP does not mean never modifying working code, and it does not require an abstraction before variation exists. Bug fixes, refactoring, security changes, and a changed contract all require edits. The practical goal is to isolate a real variation so additions have a smaller, safer change surface.
Open/Closed Principle (OCP) — open for extension, closed for modification
Direct Answer
The Open/Closed Principle says a software element should provide stable extension points for expected kinds of change. New variants can often be added through an interface, strategy, handler, or configuration without rewriting the central algorithm. It is a design goal, not a ban on editing existing code.
Code Example
// Define the abstraction - closed for modification
interface PaymentProcessor {
void processPayment(double amount);
}
// First implementation
class CreditCardProcessor implements PaymentProcessor {
public void processPayment(double amount) {
System.out.println("Processing credit card payment: $" + amount);
// Credit card-specific logic
}
}
// Second implementation - extension without modifying existing code
class PayPalProcessor implements PaymentProcessor {
public void processPayment(double amount) {
System.out.println("Processing PayPal payment: $" + amount);
// PayPal-specific logic
}
}
@Service
class OrderService {
private final PaymentProcessor processor;
// Depends on abstraction, not concrete type
public OrderService(PaymentProcessor processor) {
this.processor = processor;
}
public void checkout(double total) {
processor.processPayment(total); // Works with any implementation
}
}
Common Mistakes & Pitfalls
- Over-engineering simple cases: Freshers see OCP and immediately create interfaces for everything, even a simple DateFormatter that will never have variants. Start simple, refactor to OCP when variation appears.
- Mixing abstraction levels: Creating an interface but then checking instanceof inside the consuming class defeats the purpose — that's still modification when you add types. Let polymorphism handle the branching.
- Ignoring legitimate modifications: Treating OCP as absolute law and refusing to fix bugs or refactor because it requires touching existing code. OCP applies to feature additions, not all code changes. Bug fixes always modify code, and that's fine.
Check your understanding
Answer these without looking back at the article.
- Which design patterns help implement OCP?
- How does polymorphism enable OCP?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.