背景
当我们想要拓展一个已有功能/模块/系统时,如果原功能/模块/系统设计的不够好,那么我们拓展起来就会很麻烦,甚至无法拓展。
所以,我们需要设计一个足够好的功能/模块/系统,使得我们能够很方便的进行拓展,它需要具备以下条件
- 能很方便的进行拓展
- 进行拓展时,对现有代码的改动尽可能小
这两点就是开闭原则的核心思想。
开闭原则(Open/Closed Principle, OCP)
开闭原则是面向对象编程中的一个重要原则,由 Bertrand Meyer 提出,并被 SOLID 原则所采纳。开闭原则的核心思想是:
- 对扩展开放:软件实体应该易于扩展。这意味着设计时应该允许在不修改现有代码的基础上增加新功能。
- 对修改封闭:软件实体不应该通过修改现有代码来获得扩展。这意味着当需要改变软件行为时,应该通过新增代码而不是修改现有代码来实现。
举例说明:
假设我们有一个简单的计算系统,需要根据不同的运算类型(比如加法、减法)来执行不同的计算逻辑。
违反开闭原则的实现(使用 switch 语句)
function calculate(
operand1: number,
operand2: number,
operation: string
): number {
switch (operation) {
case "add":
return operand1 + operand2;
case "subtract":
return operand1 - operand2;
default:
throw new Error("Unsupported operation");
}
}
在这个例子中,如果我们需要添加一个新的运算类型(比如乘法),我们就需要修改 calculate 函数,这就违反了开闭原则。
遵循开闭原则的实现(使用策略模式):
interface CalculationStrategy {
execute(operand1: number, operand2: number): number;
}
class AddStrategy implements CalculationStrategy {
execute(operand1: number, operand2: number): number {
return operand1 + operand2;
}
}
class SubtractStrategy implements CalculationStrategy {
execute(operand1: number, operand2: number): number {
return operand1 - operand2;
}
}
// 可以继续添加更多的策略类,如 MultiplyStrategy,DivideStrategy 等
class Calculator {
private strategy: CalculationStrategy;
constructor(strategy: CalculationStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: CalculationStrategy) {
this.strategy = strategy;
}
calculate(operand1: number, operand2: number): number {
return this.strategy.execute(operand1, operand2);
}
}
// 使用
const calculator = new Calculator(new AddStrategy());
console.log(calculator.calculate(5, 3)); // 输出 8
calculator.setStrategy(new SubtractStrategy());
console.log(calculator.calculate(5, 3)); // 输出 2
// 添加新运算类型时,只需添加新的策略类,无需修改 Calculator 或现有策略类
在这个遵循开闭原则的例子中,我们定义了一个 CalculationStrategy 接口和几个实现了该接口的策略类。Calculator 类使用这些策略来执行计算。当我们需要添加新的运算类型时,我们只需要添加一个新的策略类,而不需要修改 Calculator 类或现有的策略类,这样就满足了开闭原则的要求。
总结
策略模式就是开闭原则的一种实现方式。
各位看官,麻烦点个赞赞,谢谢!