1. Overview
1.概述
In this tutorial, we’ll discuss the Open/Closed Principle (OCP) as one of the SOLID principles of object-oriented programming.
在本教程中,我们将讨论开放/封闭原则(OCP),作为面向对象编程的SOLID原则之一。
Overall, we’ll go into detail on what this principle is and how to implement it when designing our software.
总的来说,我们将详细介绍这个原则是什么,以及在设计我们的软件时如何实现它。
2. Open/Closed Principle
2.开放/封闭原则
As the name suggests, this principle states that software entities should be open for extension, but closed for modification. As a result, when the business requirements change then the entity can be extended, but not modified.
顾名思义,这一原则指出,软件实体应该是开放的,可以扩展,但不可以修改。因此,当业务需求发生变化时,实体可以被扩展,但不能修改。
For the illustration below, we’ll focus on how interfaces are one way to follow OCP.
在下面的说明中,我们将重点讨论接口是如何遵循OCP的一种方式。
2.1. Non-Compliant
2.1.不符合规定
Let’s consider we’re building a calculator app that might have several operations, such as addition and subtraction.
让我们考虑一下,我们正在构建一个可能有几种操作的计算器应用程序,例如加法和减法。
First of all, we’ll define a top-level interface – CalculatorOperation:
首先,我们将定义一个顶级接口–CalculatorOperation。
public interface CalculatorOperation {}
Let’s define an Addition class, which would add two numbers and implement the CalculatorOperation:
让我们定义一个Addition类,它将把两个数字相加并实现CalculatorOperation:。
public class Addition implements CalculatorOperation {
private double left;
private double right;
private double result = 0.0;
public Addition(double left, double right) {
this.left = left;
this.right = right;
}
// getters and setters
}
As of now, we only have one class Addition, so we need to define another class named Subtraction:
到现在为止,我们只有一个加法类,所以我们需要定义另一个名为减法的类。
public class Subtraction implements CalculatorOperation {
private double left;
private double right;
private double result = 0.0;
public Subtraction(double left, double right) {
this.left = left;
this.right = right;
}
// getters and setters
}
Let’s now define our main class, which will perform our calculator operations:
现在我们来定义我们的主类,它将执行我们的计算器操作。
public class Calculator {
public void calculate(CalculatorOperation operation) {
if (operation == null) {
throw new InvalidParameterException("Can not perform operation");
}
if (operation instanceof Addition) {
Addition addition = (Addition) operation;
addition.setResult(addition.getLeft() + addition.getRight());
} else if (operation instanceof Subtraction) {
Subtraction subtraction = (Subtraction) operation;
subtraction.setResult(subtraction.getLeft() - subtraction.getRight());
}
}
}
Although this may seem fine, it’s not a good example of the OCP. When a new requirement of adding multiplication or divide functionality comes in, we’ve no way besides changing the calculate method of the Calculator class.
尽管这看起来不错,但它并不是 OCP 的一个好例子。当增加乘法或除法功能的新要求出现时,除了改变Calculator类的calculate方法外,我们没有其他办法。
Hence, we can say this code is not OCP compliant.
因此,我们可以说这段代码不符合OCP标准。
2.2. OCP Compliant
2.2.符合OCP标准
As we’ve seen our calculator app is not yet OCP compliant. The code in the calculate method will change with every incoming new operation support request. So, we need to extract this code and put it in an abstraction layer.
正如我们所见,我们的计算器应用还不符合OCP标准。calculate方法中的代码将随着每个传入的新操作支持请求而改变。因此,我们需要提取这段代码并将其放在一个抽象层中。
One solution is to delegate each operation into their respective class:
一个解决方案是将每个操作委托给它们各自的类。
public interface CalculatorOperation {
void perform();
}
As a result, the Addition class could implement the logic of adding two numbers:
因此,Addition类可以实现两个数字相加的逻辑:。
public class Addition implements CalculatorOperation {
private double left;
private double right;
private double result;
// constructor, getters and setters
@Override
public void perform() {
result = left + right;
}
}
Likewise, an updated Subtraction class would have similar logic. And similarly to Addition and Subtraction, as a new change request, we could implement the division logic:
同样地,一个更新的减法类将有类似的逻辑。与加法和减法类似,作为一个新的变更请求,我们可以实现分割逻辑。
public class Division implements CalculatorOperation {
private double left;
private double right;
private double result;
// constructor, getters and setters
@Override
public void perform() {
if (right != 0) {
result = left / right;
}
}
}
And finally, our Calculator class doesn’t need to implement new logic as we introduce new operators:
最后,我们的Calculator类不需要实现新的逻辑,因为我们引入了新的操作符:。
public class Calculator {
public void calculate(CalculatorOperation operation) {
if (operation == null) {
throw new InvalidParameterException("Cannot perform operation");
}
operation.perform();
}
}
That way the class is closed for modification but open for an extension.
这样一来,该类对于修改来说是封闭的,但对于扩展来说是开放的。
3. Conclusion
3.总结
In this tutorial, we’ve learned what is OCP by definition, then elaborated on that definition. We then saw an example of a simple calculator application that was flawed in its design. Lastly, we made the design good by making it adhere to the OCP.
在本教程中,我们已经了解了什么是OCP的定义,然后对该定义进行了阐述。然后,我们看到了一个简单的计算器应用的例子,它的设计有缺陷。最后,我们通过使其遵守OCP而使其设计变得良好。
As always, the code is available over on GitHub.
一如既往,代码可在GitHub上获得。