设计模式七大原则之开闭原则 (Open Close Principle)

开闭原则 (OCP:Open Close Principle)是编程中最基础、最重要的设计原则。它指出,一个软件中的对象(类,模块,函数等等)应该对于扩展是开放的(对提供方),但是对于修改是封闭的(对使用方)。

举一个计算几何形状周长的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* @author sunys
*/
public class Openclose {
public static void main(String[] args) {
CalculatePerimeter calculatePerimeter = new CalculatePerimeter();
calculatePerimeter.rectanglePerimeter(8,4);
}

/**
* 计算几何图形周长的工具类,提供了一个计算矩形周长的方法
* 这个种方式扩展性不好,如果新增一个计算圆形的周长,
* 需要改动类,增加新的方法(违背开闭原则)
*/
private static class CalculatePerimeter{
/**
* 计算矩形周长
* @param length
* @param width
* @return
*/
public double rectanglePerimeter(double length,double width){
return (length + width) * 2;
}
}
}

在上面的例子中,CalculatePerimeter类用于计算几何图形周长,并提供了一个计算矩形周长的方法,这种设计方式违反了设计模式的ocp原则,假如我们需要计算其他图形的周长,需要改动原有的类,增加新的方法,如果业务复杂需要改动的地方会更多,扩展性不好很差。改进方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* @author sunys
*/
public class Openclose1 {

public static void main(String[] args) {
CalculatePerimeter calculatePerimeter = new CalculatePerimeter();
Rectangle rectangle = new Rectangle(8,4);
calculatePerimeter.calculatePerimeter(rectangle);
//如果需要增加计算圆周长,只需自行扩展圆类型
Circle circle = new Circle(4);
calculatePerimeter.calculatePerimeter(circle);
}
/**
* 计算几何图形周长的工具类
*/
private static class CalculatePerimeter{
public double calculatePerimeter(Shape shape){
return shape.shapePerimeter();
}
}

/**
* 抽象出几何图形基类
*/
private static abstract class Shape{
public abstract double shapePerimeter();
}

/**
* 在矩形中实现计算周长的细节
*/
private static class Rectangle extends Shape{
private double length;
private double width;

public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}

@Override
public double shapePerimeter() {
return (length + width) * 2;
}
}

/**
* 扩展计算圆形周长
*/
private static class Circle extends Shape{
private final double π = 3.14;
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public double shapePerimeter() {
return 2 * π * radius;
}
}
}

开闭原则体现出来的思想就是用抽象构建框架,用实现扩展细节。抽象的灵活性好,适应性广,易扩展,在框架设计时,我们要设计合理的抽象基类,在抽象派生的实现类中实现细节部分,这样当软件需要变化时,可以通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现,这种方式从一定程度上保证了软件架构的稳定性。

附:本次演示的项目地址
https://github.com/syshlang/java-design-principle