开放-封闭原则(开闭原则)
当谈到软件设计的可维护性、可扩展性和稳定性时,**开放-关闭原则(Open/Closed Principle,OCP)**是一个关键的设计原则。
定义
开放-封闭原则在文中的定义是:软件实体(类、模块、函数等),应该可以扩展,但是不可以修改
。按照他名称的意思来理解就是:对扩展“开”、对修改“闭”。
- 对扩展开放(Open for Extension):我们应该能够通过添加新的代码来扩展软件实体的功能,而不需要修改已有的代码。
- 对修改封闭(Closed for Modification):已存在且运行良好的代码不应该被修改。这意味着我们不应该频繁地改动已有的代码。
总结一句话就是:在我们做程序出现新的需求的时候,最好不要去修改以前的代码,而是通过增加代码的方式来实现新的需求。
优点
遵循开放-关闭原则有几个关键的优点:
- 可维护性:通过保持对已有代码的封闭性,我们可以避免频繁修改已存在的代码。这降低了引入新错误的风险,使系统更易于维护。
- 可扩展性:通过扩展而不修改现有代码,我们可以轻松地引入新功能,适应不断变化的需求。这有助于快速开发和部署新功能。
- 稳定性:不修改已有代码有助于保持系统的稳定性。我们可以通过扩展来引入新功能,而不会影响已有功能的正常运行。
举例
同样,无论是我们前面简单工厂模式中的计算器程序,还是策略模式中的商场收费程序,都遵循了开放-关闭原则。在计算器程序的例子中,如果我们需要新增求对数,开根号等计算规则,那么只需要新建两个子类来继承Operation父类即可,对于已经存在的加减乘除子类无需进行修改;而在商场收费程序中也是如此,如果新增了购物返积分的优惠策略,只需要创建一个子类继承CashSuper父类即可,对于之前制定好的优惠策略的子类无需进行任何的修改。这都是开放-封闭原则的体现。
为了加深我们对开闭原则的理解,下面我们举一个新的例子,假设我们正在开发一个图形绘制工具,我们希望能够绘制不同形状的图形,例如矩形和圆形。我们要遵循开放-关闭原则,以便在添加新的形状时不需要修改现有代码。
- 首先,我们定义一个抽象基础类
Shape
,它描述了所有形状的共同行为——绘制:
abstract class Shape {
public abstract void draw();
}
- 接下来,我们创建具体的形状类,例如
Rectangle
和Circle
,它们继承自Shape
并实现了draw
方法:
class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("这是一个矩形");
}
}
class Circle extends Shape {
@Override
public void draw() {
System.out.println("这是一个圆形");
}
}
- 现在,我们编写一个绘图工具类
DrawingTool
,它接受一个包含多种形状的列表,并能够对每一种形状进行绘制操作:
import java.util.List;
import java.util.ArrayList;
class DrawingTool {
public static void drawShapes(List<Shape> shapes) {
for (Shape shape : shapes) {
shape.draw();
}
}
}
public class Client {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Rectangle());
shapes.add(new Circle());
DrawingTool.drawShapes(shapes);
}
}
- 在客户端代码中,我们创建了一个包含矩形和圆形的形状列表,并将其传递给 DrawingTool,从而实现对多种形状进行绘制的功能。如果我们需要添加新的形状,只需创建一个新的类并继承 Shape,而不需要修改已有的代码。这样,我们遵循了开放-关闭原则,保持了代码的稳定性和可靠性,同时能够轻松地扩展新的功能。
import java.util.List;
import java.util.ArrayList;
class DrawingTool {
public static void drawShapes(List<Shape> shapes) {
for (Shape shape : shapes) {
shape.draw();
}
}
}
public class Client {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Rectangle());
shapes.add(new Circle());
DrawingTool.drawShapes(shapes);
}
}
总结
总之,开放-关闭原则的核心思想就是:在编写程序的过程中,对于扩展是开放的,对于修改是关闭的。我们最好在不修改原来代码的基础上,而是通过增加模块的方式来实现新的需求,这样才能满足开放-关闭原则。