上一篇,我们聊了S.O.L.I.D原则中的S:Single Responsibility Principle(SRP),也就是我们说的单一职责原则。
今天我们来说说O:Open Closed Principle(OCP),开闭原则。

开闭原则,是面向对象设计中的重要原则之一,其核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。

也就是说,当一个实体需要添加新功能或修改现有功能时,不应该对原有的代码进行修改,而通过扩展来实现新的功能或行为。
一句话:不能改!。
PS:话又说回来,谁写代码能保证总是一次写对,不再修改呢?😓~ 因此,这个原则是让我们在实践过程中要多为代码的扩展性考虑。即使我们不能一口气完成最优的版本,也能基于这个原则去对代码做优化!
要做到“不修改原有的代码添加或修改功能”,那就需要将新功能或修改现有功能的代码与原有代码进行解耦。
这可以降低修改已有代码带来的风险和代价,同时提高软件的可维护性和可扩展性。这也符合“开闭原则”的字面意义,即对扩展开放,对修改关闭。
对此,我们可以采用以下的设计技巧和方法:
抽象和多态的技巧,对于熟悉继承和实现的小伙伴来说,比较简单。PS:不懂“抽象”和“多态”的小伙伴可先自行百度一下。后续如果有需要,小二哥可以把这些简单的知识点也串一串~
相对不好理解的,应该是设计模式中使用OCP的情况。鼓励大家看看这两篇文章简单工厂模式(Simple Factory)和工厂方法模式(Factory Method Pattern)。这两篇文章把如何使用 OCP 进行优化 体现得相对清晰。
之后,就可以看下策略模式、观察者模式等其他模式。PS:一种设计模式中,可能包含了多个设计原则!这也是有些设计模式理解起来比较难的原因。小伙伴们可以尝试慢慢的去理解。实在不行,就先把上面的简单工厂和工厂方法模式看了,把OCP理解清楚~
前面简单工厂模式(Simple Factory)和工厂方法模式(Factory Method Pattern)中已经有例子了。
本文这里再举个例子:假设我们正在开发一个图形绘制应用程序,其中包含多种形状,例如圆形、矩形和三角形。最初的设计可能如下。
public class Shape {
private String type;
public void draw() {
if (type.equals("Circle")) {
drawCircle();
} else if (type.equals("Rectangle")) {
drawRectangle();
} else if (type.equals("Triangle")) {
drawTriangle();
}
}
private void drawCircle() {
System.out.println("Drawing a circle");
}
private void drawRectangle() {
System.out.println("Drawing a rectangle");
}
private void drawTriangle() {
System.out.println("Drawing a triangle");
}
}
现在,我们要添加画五角星的功能,怎么办?按照上面的代码,我们只能修改原代码,再弄出个else if(type.equal("star")),再添加一个drawStar()的方法。这违反了开闭原则,因为我们应该对扩展是开放的,对修改是关闭的。
为了符合开闭原则,我们可以使用多态来解决这个问题。首先,我们定义一个抽象基类Shape:
public abstract class Shape {
public abstract void draw();
}
然后,我们为每种具体的形状创建一个子类,并在子类中实现draw()方法:
public class Circle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
public class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}
}
public class Triangle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a triangle");
}
}
我们可以通过使用这些子类来绘制不同的形状,而无需修改Shape类的代码:
Shape circle = new Circle();
circle.draw();
// 输出:Drawing a circle
Shape rectangle = new Rectangle();
rectangle.draw();
// 输出:Drawing a rectangle
Shape triangle = new Triangle();
triangle.draw();
// 输出:Drawing a triangle
如果要添加星形的图案,再来个类就好了。
public class Star extends Shape {
@Override
public void draw() {
System.out.println("Drawing a star");
}
}
画个星形图案。
Shape star = new Star();
star.draw();
// 输出:Drawing a star
我们可以轻松地扩展应用程序,添加新的形状,又没有修改现有的代码。这提高了代码的可维护性和扩展性。
开闭原则是面向对象编程的基石之一。核心是:对扩展开放,对修改关闭。
带来的好处如下:
它鼓励我们设计具有良好封装和扩展性的代码。通过将可变的部分进行抽象,并通过多态来处理变化,我们可以实现对扩展开放、对修改关闭的设计。这有助于降低代码的耦合度并提高系统的可拓展性。