开闭原则
开闭原则(Open/Closed Principle,OCP)是 SOLID 面向对象设计原则中的一个重要原则。它指的是软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。也就是说,可以在不修改现有代码的情况下,通过扩展来实现新功能。遵循开闭原则可以提高代码的灵活性和可维护性。下面我们来看一下哪些常见的设计模式遵循了开闭原则,并进行详细讲解。
设计模式
1. 策略模式(Strategy Pattern)
简介:
策略模式定义了一系列算法,将每一个算法封装起来,并且使它们可以相互替换。策略模式使得算法可以独立于使用它的客户端而变化。
如何遵循开闭原则:
- -对扩展开放:可以通过添加新的策略类来增加新的算法或行为,而无需修改现有的上下文类或其他策略类。
- -对修改关闭:原有的策略类和上下文类不需要修改,只需定义新的策略类并实现相应的策略接口即可。
示例:
支付系统中,可以使用不同的支付方式(如信用卡支付、支付宝支付、微信支付)。每种支付方式可以实现一个 `PaymentStrategy` 接口,当需要新增一种支付方式时,只需实现新的策略类,而不需要修改现有代码。
// 策略接口
interface PaymentStrategy {
void pay(int amount);
}
// 具体策略类
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
class PaypalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using PayPal.");
}
}
// 上下文类
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
2. 装饰器模式(Decorator Pattern)
简介:
装饰器模式动态地将责任附加到对象上。若要扩展功能,装饰器提供了比继承更有弹性的替代方案。
如何遵循开闭原则:
- 对扩展开放:可以创建新的装饰器来扩展对象的功能。
- 对修改关闭:无需修改现有类,可以通过组合来扩展功能。
示例:
为一个文本编辑器增加功能,比如可以为文本添加加粗、斜体等功能。每种功能都可以用一个装饰器类来实现,当需要新的功能时,只需添加新的装饰器类。
// 抽象组件
interface Text {
String getContent();
}
// 具体组件
class PlainText implements Text {
private String text;
public PlainText(String text) {
this.text = text;
}
public String getContent() {
return text;
}
}
// 装饰器
abstract class TextDecorator implements Text {
protected Text decoratedText;
public TextDecorator(Text decoratedText) {
this.decoratedText = decoratedText;
}
public String getContent() {
return decoratedText.getContent();
}
}
// 具体装饰器
class BoldTextDecorator extends TextDecorator {
public BoldTextDecorator(Text decoratedText) {
super(decoratedText);
}
public String getContent() {
return "<b>" + super.getContent() + "</b>";
}
}
class ItalicTextDecorator extends TextDecorator {
public ItalicTextDecorator(Text decoratedText) {
super(decoratedText);
}
public String getContent() {
return "<i>" + super.getContent() + "</i>";
}
}
3. 观察者模式(Observer Pattern)
简介:
观察者模式定义了对象间的一对多依赖关系,当一个对象的状态改变时,所有依赖于它的对象都得到通知并自动更新。
如何遵循开闭原则:
- 对扩展开放:可以增加新的观察者类型,而无需修改主题或其他观察者。
- 对修改关闭:主题(被观察者)无需修改,只需调用通知方法,具体观察者自行处理更新。
示例:
社交媒体系统中,用户(观察者)可以关注某些话题(主题)。当话题有更新时,所有关注这个话题的用户都会收到通知。
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 观察者接口
interface Observer {
void update(String message);
}
// 具体主题
class Topic implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void postMessage(String message) {
this.message = message;
notifyObservers();
}
}
// 具体观察者
class User implements Observer {
private String name;
public User(String name) {
this.name = name;
}
public void update(String message) {
System.out.println(name + " received: " + message);
}
}
4. 工厂方法模式(Factory Method Pattern)
简介:
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法使一个类的实例化延迟到其子类。
如何遵循开闭原则:
- 对扩展开放:可以通过创建新的子类来实现不同的产品类型。
- 对修改关闭:原有的工厂基类和产品类不需要修改,新增功能可以通过子类实现。
示例:
日志系统,可以通过不同的工厂方法生成不同类型的日志记录器,如文件日志记录器、数据库日志记录器等。
// 产品接口
interface Logger {
void log(String message);
}
// 具体产品
class FileLogger implements Logger {
public void log(String message) {
System.out.println("Log to file: " + message);
}
}
class DatabaseLogger implements Logger {
public void log(String message) {
System.out.println("Log to database: " + message);
}
}
// 工厂接口
abstract class LoggerFactory {
public abstract Logger createLogger();
}
// 具体工厂
class FileLoggerFactory extends LoggerFactory {
public Logger createLogger() {
return new FileLogger();
}
}
class DatabaseLoggerFactory extends LoggerFactory {
public Logger createLogger() {
return new DatabaseLogger();
}
}
5. 模板方法模式(Template Method Pattern)
简介:
模板方法模式在一个方法中定义一个操作的算法骨架,而将某些步骤延迟到子类中实现。模板方法使得子类可以不改变算法结构即可重定义算法的某些特定步骤。
如何遵循开闭原则:
- 对扩展开放:可以通过子类来重写特定步骤以改变算法的部分实现。
- 对修改关闭:模板方法在基类中定义,子类只需扩展必要的方法,而无需修改基类代码。
示例:
在文档生成系统中,可以有一个通用的生成算法,但具体的格式或输出(如 HTML、PDF)可以通过子类来实现。
// 抽象类
abstract class DocumentGenerator {
// 模板方法
public final void generateDocument() {
readData();
processData();
formatDocument();
printDocument();
}
abstract void readData();
abstract void processData();
abstract void formatDocument();
void printDocument() {
System.out.println("Document is printed.");
}
}
// 具体实现类
class PDFGenerator extends DocumentGenerator {
void readData() {
System.out.println("Reading data for PDF.");
}
void processData() {
System.out.println("Processing data for PDF.");
}
void formatDocument() {
System.out.println("Formatting document as PDF.");
}
}
class HTMLGenerator extends DocumentGenerator {
void readData() {
System.out.println("Reading data for HTML.");
}
void processData() {
System.out.println("Processing data for HTML.");
}
void formatDocument() {
System.out.println("Formatting document as HTML.");
}
}
6. 责任链模式(Chain of Responsibility Pattern)
简介:
责任链模式让多个对象都有机会处理请求,从而避免请求的发送者与接收者耦合在一起。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
如何遵循开闭原则:
- 对扩展开放:可以通过添加新的处理类来扩展处理链,而不需要修改现有的处理类。
- 对修改关闭:不需要修改现有的处理类,新的处理需求可以通过添加新的处理类来实现。
示例:
在一个消息处理系统中,可以有不同的消息处理器,如日志记录器、错误处理器、用户通知处理器等。新增加的处理器只需插入链中,不需要修改其他处理器。
// 抽象处理者
abstract class Handler {
protected Handler next;
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(String request);
}
// 具体处理者
class ErrorHandler extends Handler {
public void handleRequest(String request) {
if (request.equals("error")) {
System.out.println("Handling error request.");
} else if (next != null) {
next.handleRequest(request);
}
}
}
class LogHandler extends Handler {
public void handleRequest(String request) {
if (request.equals("log")) {
System.out.println("Handling log request.");
} else if (next != null) {
next.handleRequest(request);
}
}
}
// 使用示例
Handler errorHandler = new ErrorHandler();
Handler logHandler = new LogHandler();
errorHandler.setNext(logHandler);
// 处理请求
errorHandler.handleRequest("log"); // 输出: Handling log request.
总结
策略模式、装饰器模式、观察者模式、工厂方法模式、模板方法模式和责任链模式——都遵循开闭原则。它们通过接口或抽象类定义扩展点,使得新的功能或算法可以通过扩展类来实现,而无需修改现有的代码。这种设计提高了系统的灵活性和可维护性,使系统能够更轻松地适应变化。