1.背景
伯特兰·迈耶一般被认为是最早提出开闭原则这一术语的人,在他1988年发行的《面向对象软件构造》中给出。这一想法认为一旦完成,一个类的实现只应该因错误而修改,新的或者改变的特性应该通过新建不同的类实现。新建的类可以通过继承的方式来重用原类的代码。衍生的子类可以或不可以拥有和原类相同的接口。
梅耶的定义提倡实现继承。具体实现可以通过继承方式来重用,但是接口规格不必如此。已存在的实现对于修改是封闭的,但是新的实现不必实现原有的接口。
2.概念
开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为;它是最基础的设计原则,指导我们建立稳定、灵活的系统。
通俗的讲:
1.对扩展开放,对修改关闭;
2.使程序更易于扩展、维护和升级;
3.开发中如何遵守
系统中的模块、类、方法对他们的提供者应该是开放的,提供者可以对系统进行扩展新的功能。
系统中的模块、类、方法对他们的使用者应该是关闭的,使用者使用这些功能时,不会因为提供方新增了功能而导致使用者也进行相关的修改。
想要达到遵守开闭原则的效果,我们在程序开发时需要使用接口和抽象类。
因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
4.案例
我们通过一个绘图的功能来演示如何遵守开闭原则;
不遵守开闭原则的代码:
public class DrawShape {
// TODO 不好的代码
public void drawView(int type){
if (1== type){
System.out.println("圆形");
}else if (2==type){
System.out.println("矩形");
}
}
}
public class Draw {
public static void main(String[] args) {
DrawShape drawShape = new DrawShape();
// TODO 不好的代码
// 绘制圆形
drawShape.drawView(1);
// 绘制矩形
drawShape.drawView(2);
}
}
遵守开闭原则的代码:
/**
* 画图基础类
*/
public abstract class BaseShape {
// 画图
public abstract void drawView();
}
/**
* 圆形
*/
public class Circle extends BaseShape {
public void drawView() {
System.out.println("圆形");
}
}
/**
* 矩形
*/
public class Rectangle extends BaseShape {
public void drawView() {
System.out.println("矩形");
}
}
/**
* 绘制
*/
public class DrawShape {
public void drawView(BaseShape draw){
// ... 其他处理
draw.drawView();
}
}
public class Draw {
public static void main(String[] args) {
DrawShape drawShape = new DrawShape();
// 绘制圆形
drawShape.drawView(new Circle());
// 绘制矩形
drawShape.drawView(new Rectangle());
}
}