开放-封闭原则,是说软件实体(类、模块、函数等)应该可以扩展,但是不可修改,一旦软件实体发布,其源代码就不应该被修改来改变其行为。这有助于减少因修改既有功能而引入新错误的风险。
举一个简单的例子,假设有一个绘图程序,它可以绘制不同种类的形状。如果遵循开放封闭原则,我们应该设计一个基本的形状类(如Shape
),然后为每种具体的形状创建继承自Shape
的子类(如Circle
、Square
等)。当需要添加新形状时,我们只需添加一个新的子类而不需要修改现有的类。这样,绘图程序对新形状的扩展是开放的,但对现有代码的修改是封闭的。
主要为了下面的目的
提高软件系统的可维护性:当需要改变或添加新功能时,可以通过添加新代码而不是修改现有代码,从而减少对现有系统的影响。
增强软件系统的可扩展性:系统设计为易于扩展(新增新功能往往只需要新增子类就可以不需要修改代码逻辑),可以适应未来的变化和需求。
促进代码的重用:设计灵活、可扩展的组件可以在不同的环境中重用(比如新增一个圆形别的地方也能使用)。
假设我们正在开发一个简单的支付系统,可以处理不同类型的支付方式,如信用卡支付、PayPal支付等。为了遵守开放封闭原则,我们将设计系统的方式使得它可以轻松添加新的支付方式,而无需修改现有代码。
首先,我们定义一个支付接口(Payment
),所有的支付方式都必须实现这个接口。
public interface Payment {
void processPayment(double amount);
}
然后,我们为每种支付方式实现一个类,这些类都实现了Payment
接口。
public class CreditCardPayment implements Payment {
@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}
public class PayPalPayment implements Payment {
@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}
接下来,我们创建一个支付处理类,它接受Payment
接口的实例。这个类不需要知道具体的支付细节,只需要调用processPayment
方法。
public class PaymentProcessor {
public void process(double amount, Payment paymentMethod) {
paymentMethod.processPayment(amount);
}
}
现在,如果我们想要添加一种新的支付方式,比如比特币支付,我们只需要添加一个新的类实现Payment
接口。这样,我们就扩展了功能而不需要修改现有的PaymentProcessor
类或其他支付类。
public class BitcoinPayment implements Payment {
@Override
public void processPayment(double amount) {
System.out.println("Processing Bitcoin payment of $" + amount);
}
}
现在,我们可以在系统中使用不同的支付方式,而无需修改现有代码。
public class Main {
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor();
Payment creditCardPayment = new CreditCardPayment();
processor.process(100.0, creditCardPayment);
Payment payPalPayment = new PayPalPayment();
processor.process(200.0, payPalPayment);
Payment bitcoinPayment = new BitcoinPayment();
processor.process(300.0, bitcoinPayment);
}
}
通过定义一个共同的接口Payment
并让所有支付方式实现这个支付处理类(PaymentProcessor
)对于添加新的支付方式是开放的,但对于修改是封闭的。这样的设计遵循了开放封闭原则,提高了代码的可维护性和扩展性。
同样是支付处理类PaymentProcessor
public class PaymentProcessor {
public void processPayment(String type, double amount) {
if (type.equals("CreditCard")) {
// 信用卡支付逻辑
System.out.println("Processing credit card payment of $" + amount);
} else if (type.equals("PayPal")) {
// PayPal支付逻辑
System.out.println("Processing PayPal payment of $" + amount);
}
// 对于每种新的支付方式,我们需要在这里添加新的else if块
}
}
这里将支付逻辑放在一个单一的类中,而不是使用接口和多态,
如果我们想要添加比特币支付,我们必须修改PaymentProcessor
类:
public void processPayment(String type, double amount) {
if (type.equals("CreditCard")) {
// 信用卡支付逻辑
System.out.println("Processing credit card payment of $" + amount);
} else if (type.equals("PayPal")) {
// PayPal支付逻辑
System.out.println("Processing PayPal payment of $" + amount);
} else if (type.equals("Bitcoin")) {
// 比特币支付逻辑
System.out.println("Processing Bitcoin payment of $" + amount);
}
}
对比之前的
public class PaymentProcessor {
public void process(double amount, Payment paymentMethod) {
paymentMethod.processPayment(amount);
}
}
这里的缺点显而易见
不易扩展:如果我们想添加一种新的支付方式,比如比特币支付,我们必须修改PaymentProcessor
类,添加新的else if
块。这违反了开放封闭原则,因为我们需要修改现有的代码来扩展功能。
不易维护:随着支付方式的增加,PaymentProcessor
类将变得越来越复杂,越来越难以维护。每次添加或修改支付逻辑时,都有引入错误的风险。
违反单一责任原则:PaymentProcessor
类处理了所有类型的支付逻辑,这违反了单一责任原则。一个类应该只负责一个功能领域内的责任。