您当前的位置: 首页 > 

Dongguo丶

暂无认证

  • 1浏览

    0关注

    472博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

开放封闭原则

Dongguo丶 发布时间:2018-08-12 16:31:17 ,浏览量:1

定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则

一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。在设计一个模块时,应当使得这个模块可以在不被修改的前提下被扩展。也就是说,应当可以在不必修改源代码的情况下修改这个模块的行为。设计的目的便在于面对需求的改变而保持系统的相对稳定,从而使得系统可以很容易的从一个版本升级到另一个版本。

编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。

问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。

解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

 实际上,变化或者可能的变化来的越早,抽象就越容易,相对的,代码的维护也就越容易。而当项目接近于完成而来的需求变化,则会使抽象变得很困难,这个困难,并不是抽象本身的困难,抽象本身并没有苦难,困难在于系统的架构已经完成,修改牵扯的方面太多而使得抽象的工作变得困难

 开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统。开闭原则可能是设计模式六项原则中定义最模糊的一个了,它只告诉我们对扩展开放,对修改关闭,可是到底如何才能做到对扩展开放,对修改关闭,并没有明确的告诉我们。以前,如果有人告诉我“你进行设计的时候一定要遵守开闭原则”,我会觉的他什么都没说,但貌似又什么都说了。因为开闭原则真的太虚了。

开闭原则无非就是想表达这样一层意思:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。

单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合;组合复用法则告诉我们尽量使用组合而非继承。而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。

看一个画图形的功能,我们可以选择画矩形,圆形和三角形。

类图设计,如下:

package com.dongguo.principle.ocp.ocp1;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:15
 * @description: 基类
 */
public class Shape {
    int m_type;
}
package com.dongguo.principle.ocp.ocp1;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:18
 * @description:
 */
public class Rectangle extends Shape {
    Rectangle() {
        super.m_type = 1;
    }
}

 

package com.dongguo.principle.ocp.ocp1;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:18
 * @description:
 */
public class Circle extends Shape {
    Circle() {
        super.m_type = 2;
    }
}

 

package com.dongguo.principle.ocp.ocp1;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:19
 * @description: 画三角形
 */
public class Triangle extends Shape {
    Triangle() {
        super.m_type = 3;
    }
}
package com.dongguo.principle.ocp.ocp1;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:21
 * @description: 这是一个用于绘图的类[使用方]
 */
public class GraphicEditor {
    //接收Shape 对象,然后根据type,来绘制不同的图形
    public void drawShape(Shape s) {
        if (s.m_type == 1)
            drawRectangle(s);
        else if (s.m_type == 2)
            drawCircle(s);
        else if (s.m_type == 3)
            drawTriangle(s);
    }

    //绘制矩形
    public void drawRectangle(Shape r) {
        System.out.println(" 绘制矩形");
    }

    //绘制圆形
    public void drawCircle(Shape r) {

        System.out.println(" 绘制圆形");
    }

    //绘制三角形
    public void drawTriangle(Shape r) {
        System.out.println(" 绘制三角形");
    }
}

 

package com.dongguo.principle.ocp.ocp1;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:23
 * @description:
 */
public class Ocp {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Triangle());
    }
}
运行结果:
 绘制矩形
 绘制圆形
 绘制三角形

1) 这中方法的优点是比较好理解,简单易操作。

2) 缺点是违反了设计模式的ocp 原则,即对扩展开放(提供方),对修改关闭(使用方)。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码.

3) 比如我们这时要新增加一个图形种类三角形,我们需要修改的地方较多。

思路:把创建Shape 类做成抽象类,并提供一个抽象的draw 方法,让子类去实现即可,这样我们有新的图形种类时,只需要让新的图形类继承Shape,并实现draw 方法即可,使用方的代码就不需要修-> 满足了开闭原则

package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:15
 * @description: 基类
 */
public abstract class Shape {
    int m_type;

    public abstract void draw();//提供抽象方法
}
package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:29
 * @description:
 */
public class Rectangle extends Shape {
    Rectangle() {
        super.m_type = 1;
    }

    @Override
    public void draw() {
        System.out.println(" 绘制矩形");
    }
}

 

package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:29
 * @description:
 */
public class Circle extends Shape {
    Circle() {
        super.m_type = 2;
    }

    @Override
    public void draw() {
        System.out.println(" 绘制圆形");
    }
}

 

package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:30
 * @description: 新增画三角形
 */
public class Triangle extends Shape {
    Triangle() {
        super.m_type = 3;
    }

    @Override
    public void draw() {
        System.out.println(" 绘制三角形");
    }
}
package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:30
 * @description: 新增一个图形
 */
public class OtherGraphic extends Shape {
    OtherGraphic() {
        super.m_type = 4;
    }

    @Override
    public void draw() {
        System.out.println(" 绘制其它图形");
    }
}

 

package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:31
 * @description: 这是一个用于绘图的类[使用方]
 */
public class GraphicEditor {
    //接收Shape 对象,调用draw 方法
    public void drawShape(Shape s) {
        s.draw();
    }
}
package com.dongguo.principle.ocp.ocp2;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-7:31
 * @description:
 */
public class Ocp {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Triangle());
        graphicEditor.drawShape(new OtherGraphic());
    }
}
运行结果:
 绘制矩形
 绘制圆形
 绘制三角形
 绘制其它图形

优点:

1 通过扩展已有的系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件有一定的适应性和灵活性。

2已有的软件模块,特别是最重要的抽象模块不能再修改,这就是变化中的软件系统有一定的稳定性和延续性。

实际上,绝对封闭的系统是不存在的,无论模块是怎么封闭,到最后,总还是有一些无法封闭的变化,而我们的思路就是:既然不能做到完全封闭,那我们就应该对那些变化封闭,那些变化隔离做出选择。我们做出选择,然后将那些无法封闭的变化抽象出来,进行隔离,允许扩展,尽可能的减少系统的开发。当系统变化来临时,我们要及时的做出反应。

当变化到来时,我们首先需要做的不是修改代码,而使尽可能的将变化抽象出来进行隔离,然后进行扩展。面对需求的变化,对程序修改应该是尽可能的通过添加代码来实现,而不是通过修改代码来实现

关注
打赏
1638062488
查看更多评论
立即登录/注册

微信扫码登录

0.0432s