一文搞懂开放封闭原则

开放封闭原则(Open-Closed Principle, OCP)是面向对象设计(Object-Oriented Design)的基本原则之一,最早由 Bertrand Meyer 在其1988年的著作《Object-Oriented Software Construction》中提出。该原则的主要内容如下:

开放封闭原则定义

开放封闭原则表明:

软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭。这意味着当需求发生变化时,我们应该能够在不修改原有代码的基础上,通过新增代码的方式来满足新的需求。

主要要点

  1. 扩展性: 软件实体应该容易扩展,以便在不触及原有结构和功能的基础上增加新的功能。设计时应预见到未来可能的变化,并创建抽象层和扩展点,使新功能可以通过扩展这些点来实现。
  2. 稳定性: 已经部署并经过验证的软件实体(尤其是稳定的底层组件和基础架构)应该尽可能避免修改。频繁修改既有的代码不仅增加了出错的风险,还可能引发连锁反应,影响到依赖于该代码的其他部分。

实现方式

  • 抽象类与接口:定义抽象类或接口来描述共同行为,然后通过创建新的派生类或实现接口来增加功能,而不是修改原有类。
  • 策略模式:定义一组算法族,分别封装在不同的类中,使得它们之间可以互相替换。策略模式允许算法独立于使用它的客户代码变化。
  • 装饰者模式:动态地给对象添加职责,提供了比继承更为灵活的替代方案,允许在运行时改变对象的行为。
  • 工厂方法模式:创建对象的接口,但让子类决定实例化哪一个类。这样,系统就能在不修改自身的情况下扩展产品类系列。

示例说明

下面我将以JavaScript为例,展示如何运用开放封闭原则(OCP)设计一个简单的计费系统。假设我们开始时有一个处理普通订单的计费服务,之后又需要支持VIP用户的折扣计费。

初始版本:普通订单计费服务
javascript 复制代码
// 假设有一个基础的订单类
class Order {
  constructor(totalPrice) {
    this.totalPrice = totalPrice;
  }
}

// 普通订单计费服务
class BillingService {
  calculateOrderCost(order) {
    if (!(order instanceof Order)) {
      throw new Error('Invalid order');
    }
    
    return order.totalPrice;
  }
}

// 创建一个普通订单
const regularOrder = new Order(100);

// 创建并使用计费服务
const billing = new BillingService();
console.log(billing.calculateOrderCost(regularOrder)); // 输出:100
扩展版本:支持VIP订单
javascript 复制代码
// 新增VIP订单类,它继承自Order
class VIPOrder extends Order {
  constructor(totalPrice, vipDiscount) {
    super(totalPrice);
    this.vipDiscount = vipDiscount;
  }

  applyVipDiscount() {
    return this.totalPrice * (1 - this.vipDiscount);
  }
}

// 创建一个VIP订单计费策略类,遵循策略模式
class VipBillingStrategy {
  calculateOrderCost(order) {
    if (order instanceof VIPOrder) {
      return order.applyVipDiscount();
    } else {
      throw new Error('This is not a VIP order');
    }
  }
}

// 修改BillingService,使其支持不同的计费策略
class BillingService {
  constructor(strategy = new DefaultBillingStrategy()) {
    this.strategy = strategy;
  }

  setStrategy(strategy) {
    this.strategy = strategy;
  }

  calculateOrderCost(order) {
    return this.strategy.calculateOrderCost(order);
  }
}

// 创建一个默认计费策略,用于处理普通订单
class DefaultBillingStrategy {
  calculateOrderCost(order) {
    if (order instanceof Order) {
      return order.totalPrice;
    } else {
      throw new Error('Invalid order');
    }
  }
}

// 使用VIP订单并切换计费策略
const vipOrder = new VIPOrder(200, 0.2); // 假设VIP有20%的折扣

const billing = new BillingService(new DefaultBillingStrategy());
billing.setStrategy(new VipBillingStrategy());

console.log(billing.calculateOrderCost(vipOrder)); // 输出:160

// 对于普通订单,仍然可以使用同样的计费服务
console.log(billing.calculateOrderCost(regularOrder)); // 输出:100

在这个例子中,我们遵循开放封闭原则:

  • 对扩展开放 :我们通过创建VIPOrder类以及VipBillingStrategy类,对VIP订单的处理进行了扩展,没有修改原有的Order类或BillingService的基础功能。
  • 对修改封闭 :原有的Order类和最初版本的BillingService在面对新的需求时没有被直接修改,而是通过添加新的类和策略来实现功能扩展。

为何重要

遵循开放封闭原则有助于:

  • 提高复用性:已经测试过的、稳定的代码更容易重复利用。
  • 降低耦合度:减少各个模块之间的相互依赖,使得系统更具灵活性。
  • 维护性提升:变更时只需关注新增代码,大大降低了潜在的bug引入风险。
  • 遵循开闭原则是实现软件系统持续演进的关键手段,它使得系统能够应对不断变化的需求,同时保持系统整体的稳定和可控性。
相关推荐
MiyueFE22 分钟前
bpmn-js 源码篇7:Featrues 体验优化与功能扩展(二)
前端
好_快36 分钟前
Lodash源码阅读-isPrototype
前端·javascript·源码阅读
31535669131 小时前
manus邀请码申请手把手教程
前端·后端·面试
知行021 小时前
23中设计模式之观察者模式
java·观察者模式·设计模式
迷路的小犀牛1 小时前
JAVA编程【设计模式之工厂模式】
java·开发语言·设计模式
烂蜻蜓2 小时前
HTML 编辑器推荐与 VS Code 使用教程
前端·python·编辑器·html
大丈夫在世当日食一鲲2 小时前
mybaties中使用的设计模式
设计模式
木心操作2 小时前
nodejs使用WebSocket实现聊天效果
javascript·网络·websocket·网络协议·node.js
小画家~2 小时前
第五十九:子传父 defineEmits
前端·javascript·vue.js
html组态2 小时前
组态软件在物联网中的应用概述
前端·物联网·编辑器·html·iot