Open‑Closed Principle Explained with a Hospital Billing Example
This article explains the Open‑Closed Principle of design patterns, illustrates it with Java code that models a hospital’s medicine‑selling process, compares naive and extensible implementations, and shows how to keep software open for extension while closed for modification.
The Open‑Closed Principle (OCP) states that software entities should be open for extension but closed for modification. The article introduces this principle with a real‑world analogy of buying medicine in a hospital.
First, a simple implementation shows a Hospital class selling a fixed‑price Medicine to a patient:
public class OcpTest {
public static void main(String[] args) {
Hospital hospital = new Hospital();
IPatient xiaoMing = new Patient("小明");
hospital.sellMedicine(xiaoMing);
}
}
class Medicine {
private String name;
private BigDecimal price;
public Medicine(String name, BigDecimal price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public BigDecimal getPrice() { return price; }
public void setPrice(BigDecimal price) { this.price = price; }
}
class Hospital {
private Medicine medicine = new Medicine("阿司匹林", new BigDecimal(20));
public void sellMedicine(IPatient patient) {
BigDecimal money = patient.pay(medicine);
System.out.println(patient.getName() + " 花了 " + money.setScale(2, BigDecimal.ROUND_UP) + " 块钱买了药:" + medicine.getName());
}
}
interface IPatient {
String getName();
BigDecimal pay(Medicine medicine);
}
class Patient implements IPatient {
private String name;
public Patient(String name) { this.name = name; }
@Override
public BigDecimal pay(Medicine medicines) { return medicines.getPrice(); }
@Override
public String getName() { return name; }
}This version works but hard‑codes the price, violating OCP when new discount rules appear.
Next, the article shows a version that adjusts the price based on social‑security levels using conditional logic inside the Patient class, which still requires modifying existing code for each new level.
class Patient implements IPatient {
private String name;
private int level;
public Patient(String name) { this.name = name; }
@Override
public BigDecimal pay(Medicine medicines) {
if (level == 1) {
return medicines.getPrice().multiply(new BigDecimal(0.7));
} else if (level == 2) {
return medicines.getPrice().multiply(new BigDecimal(0.8));
} else if (level == 3) {
return medicines.getPrice().multiply(new BigDecimal(0.9));
}
return medicines.getPrice();
}
@Override
public String getName() { return name; }
}Finally, an OCP‑compliant solution introduces separate classes for each social‑security tier, each implementing IPatient and providing its own pay method. Adding a new tier now only requires creating a new class, leaving existing code untouched.
class OneLevelSocialSecurityPatient implements IPatient {
private String name;
public OneLevelSocialSecurityPatient(String name) { this.name = name; }
@Override
public BigDecimal pay(Medicine medicine) { return medicine.getPrice().multiply(new BigDecimal(0.7)); }
@Override
public String getName() { return name; }
}
class TwoLevelSocialSecurityPatient implements IPatient {
private String name;
public TwoLevelSocialSecurityPatient(String name) { this.name = name; }
@Override
public BigDecimal pay(Medicine medicine) { return medicine.getPrice().multiply(new BigDecimal("0.8")); }
@Override
public String getName() { return name; }
}
class ThreeLevelSocialSecurityPatient implements IPatient {
private String name;
public ThreeLevelSocialSecurityPatient(String name) { this.name = name; }
@Override
public BigDecimal pay(Medicine medicine) { return medicine.getPrice().multiply(new BigDecimal("0.9")); }
@Override
public String getName() { return name; }
}
public static void main(String[] args) {
Hospital hospital = new Hospital();
IPatient xiaoMing = new Patient("小明");
hospital.sellMedicine(xiaoMing);
IPatient xiaoHong = new OneLevelSocialSecurityPatient("小红");
hospital.sellMedicine(xiaoHong);
IPatient xiaoHua = new TwoLevelSocialSecurityPatient("小花");
hospital.sellMedicine(xiaoHua);
IPPatient xiaoJie = new ThreeLevelSocialSecurityPatient("小杰");
hospital.sellMedicine(xiaoJie);
}The article concludes that the third approach respects the Open‑Closed Principle: future extensions (e.g., a fourth social‑security level) can be added without altering existing classes, demonstrating why many frameworks rely heavily on abstractions and interfaces.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.