软件设计原则-开闭原则讲解以及代码示例

简介: 开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一条重要原则,它由Bertrand Meyer在其著作《面向对象软件构造》中提出,并成为SOLID原则之一。开闭原则的核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。简单来说,就是在不修改已有代码的情况下,通过扩展来实现新的功能或变化。

开闭原则

一,介绍

1.前言

开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一条重要原则,它由Bertrand Meyer在其著作《面向对象软件构造》中提出,并成为SOLID原则之一。

开闭原则的核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。简单来说,就是在不修改已有代码的情况下,通过扩展来实现新的功能或变化。

2.何时使用开闭原则

    1. 当需要添加新功能时:如果你需要在已有的代码基础上添加新功能,你应该通过扩展现有代码,而不是直接修改已有代码。这样做的好处是不会对原有的功能产生影响,同时也保证了代码的可维护性和稳定性。
    2. 当需要修改已有功能时:尽管开闭原则主张对已有代码进行关闭,但有时我们仍然需要修改一些已有功能。这种情况下,可以考虑通过使用抽象层、接口或者设计模式来隔离修改的影响范围,从而保持已有功能的稳定性,而不必修改大量的代码。
    3. 当需要适应变化:在软件开发过程中,需求和业务环境可能会发生变化。为了应对这种变化,我们需要让系统具备良好的扩展性。通过遵循开闭原则,我们可以更容易地添加、调整或替换组件,以适应变化的需求。

    二,代码示例

    为了更详细地介绍开闭原则,我们可以通过一个例子来说明:

    假设有一个图形绘制程序,程序需要能够绘制不同形状的图形,比如矩形、圆形和三角形。最初的设计可能会像这样:

     

    class Shape {
        private String type;
        public Shape(String type) {
            this.type = type;
        }
        public void draw() {
            if (type.equals("rectangle")) {
                System.out.println("绘制矩形");
            } else if (type.equals("circle")) {
                System.out.println("绘制圆形");
            } else if (type.equals("triangle")) {
                System.out.println("绘制三角形");
            }
        }
    }

    image.gif

    这个设计看起来似乎没有问题,但问题在于当我们需要添加新的图形类型时,需要修改`Shape`类的源代码,违背了开闭原则。

    为了符合开闭原则,我们可以进行重构。首先,我们定义一个抽象类`Shape`:

     

    abstract class Shape {
        public abstract void draw();
    }

    image.gif

    然后,对每种具体的图形类型,创建一个子类并实现`draw()`方法:

     

    class Rectangle extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制矩形");
        }
    }
    class Circle extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制圆形");
        }
    }
    class Triangle extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制三角形");
        }
    }

    image.gif

    现在,我们可以通过扩展子类来添加新的图形类型,而无需修改`Shape`类的源代码。例如,如果需要添加椭圆形,只需创建一个`Ellipse`类,并实现`draw()`方法即可。

    这个重构后的设计符合开闭原则,因为我们通过扩展子类来实现新的功能,而不需要修改父类的代码。这样做的好处是,已有的代码保持不变,不会引入新的错误,同时也增加了系统的可扩展性和可维护性。

    总结起来,开闭原则鼓励我们在设计软件时,采用抽象、封装和多态等方式,使得系统能够以最小的修改来适应变化。这种设计思想能够提高代码的可复用性、可扩展性和可维护性,是良好的软件设计实践之一。

    三,优缺点

    开闭原则的优点:

    1. 提高了代码的可维护性与复用性:遵循开闭原则可以让代码更加稳定和可维护,同时也使得代码更容易被复用。如果我们需要修改某个模块的行为,只需要扩展该模块而不需要直接修改源代码,这样就不会影响到其他的模块。

    2. 提高了代码的可扩展性:开闭原则还可以提高代码的可扩展性。通过扩展已有的代码,我们可以很容易地添加新的功能或改进现有功能,从而适应业务需求的更改。

    3. 提高了代码的可测试性:遵循开闭原则可以降低代码的耦合度,使得测试更加容易。因为我们只需要测试新增的代码,而不必验证已有代码的正确性。

    开闭原则的缺点:

    1. 对代码的设计要求高:遵循开闭原则需要对代码进行良好的抽象和封装,这对程序员的设计能力和经验要求较高。如果设计不好,可能会导致代码过于复杂难以维护。

    2. 可能会增加代码量:通过扩展已有的代码来实现新功能,可能会增加代码量,使得系统变得更加复杂。这需要我们在平衡可维护性和代码量之间做出权衡。

    3. 可能会带来设计上的限制:在某些情况下,为了遵循开闭原则,我们可能需要引入更多的抽象层或接口。这可能会带来一定的设计上的限制,限制了代码的表达能力和灵活性。

    总之,开闭原则是一条非常重要的设计原则,可以提高代码的可维护性、可复用性和可扩展性,但也需要平衡代码的表达能力和灵活性,避免过度设计。

    四,Java那里用到了开闭原则

    在Java中,开闭原则(Open-Closed Principle)是面向对象设计原则之一,它强调软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。在Java的各个层面都可以应用开闭原则,下面是几个常见的应用场景:

    1. 接口和抽象类:通过定义接口和抽象类,可以为系统定义一组稳定的抽象层,对扩展开放。其他具体的实现类可以继承或实现这些抽象层,通过扩展的方式增加新的功能,而无需修改已有的代码。

    2. 使用多态性:Java的多态性机制支持开闭原则的实现。通过基类或接口引用指向子类对象,程序可以在不修改原有代码的情况下,动态地添加新的子类,扩展系统的功能。

    3. 设计模式:许多设计模式都是基于开闭原则的思想,通过封装变化和抽象稳定部分,实现对扩展开放,对修改关闭。例如,策略模式、观察者模式、装饰器模式等都可以帮助实现开闭原则。

    4. 使用反射机制:Java的反射机制可以动态地获取和操作类、方法、属性等信息,提供了一种在运行时操作类结构的能力。通过反射,可以在不修改代码的情况下,动态地实例化对象、调用方法等,实现对系统的扩展。

    5. 使用依赖注入(Dependency Injection):依赖注入是一种实现开闭原则的常见方式。通过将依赖关系的创建和管理交由框架来完成,可以在不修改源代码的情况下,通过配置文件或注解改变依赖的实现,从而扩展系统的功能。

    总的来说,Java作为一门面向对象的编程语言,提供了许多机制和设计模式来支持开闭原则的实现。合理运用接口和抽象类、多态性、设计模式、反射机制以及依赖注入等技术手段,可以使Java程序更具可扩展性和可维护性,符合开闭原则的设计原则。

    五,总结

    1.常规总结

    本文介绍了开闭原则(Open-Closed Principle,OCP)的基本概念和作用,即软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。通过一个图形绘制程序的例子,说明如何遵循开闭原则使得代码更加稳定、可维护、可扩展和可测试。同时,本文也分析了开闭原则的优缺点,需要平衡代码的可维护性、可复用性和可扩展性,避免过度设计。

    2.幽默总结

    开闭原则就是让你的代码像女朋友一样,对改进开放,对修改关闭。要保持稳定,可扩展和可维护,但是也要注意不要设计过度,否则就像约会时穿太多衣服一样僵硬。

    3.搞笑总结

    开闭原则是指软件实体应该对扩展开放,对修改关闭。这意味着我们应该通过扩展来实现新的功能,而不是直接修改已有代码。这样做的好处是可以提高代码的可维护性、复用性和可扩展性。虽然遵循开闭原则需要对代码进行良好的抽象和封装,而且可能会增加代码量和带来设计上的限制,但是这条原则仍然是非常重要的。如果你违反了开闭原则,那么你就是在自找麻烦!

    目录
    相关文章
    |
    API Apache 数据库
    Flink CDC 3.0 正式发布,详细解读新一代实时数据集成框架
    Flink CDC 于 2023 年 12 月 7 日重磅推出了其全新的 3.0 版本 ~
    109672 8
     Flink CDC 3.0 正式发布,详细解读新一代实时数据集成框架
    |
    存储 Java
    Java设计一个简单的计算器程序
    Java设计一个简单的计算器程序
    |
    10月前
    |
    设计模式 存储 关系型数据库
    「全网最细 + 实战源码案例」设计模式——六大设计原则
    本文介绍了面向对象设计中的六大原则,旨在提高软件系统的可维护性、可复用性和可拓展性。这些原则包括:开闭原则(OCP)、里氏代换原则(LSP)、依赖倒转原则(DIP)、接口隔离原则(ISP)、迪米特法则(LoD)和合成复用原则(CARP)。每项原则通过具体示例展示了如何通过抽象、多态、组合等方式降低耦合度,增强系统的灵活性与稳定性,从而提升开发效率并降低成本。
    265 10
    |
    前端开发 应用服务中间件 定位技术
    Nginx 如何代理转发传递真实 ip 地址?
    【10月更文挑战第32天】
    2618 5
    Nginx 如何代理转发传递真实 ip 地址?
    |
    消息中间件 JSON Java
    Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
    Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
    27793 0
    |
    算法 Java C语言
    【数据结构】后缀(逆波兰)表达式的计算以及中缀转后缀的方法
    【数据结构】后缀(逆波兰)表达式的计算以及中缀转后缀的方法
    2751 1
    |
    Kubernetes 监控 Java
    发布策略:蓝绿部署、金丝雀发布(灰度发布)、AB测试、滚动发布、红黑部署的概念与区别
    发布策略:蓝绿部署、金丝雀发布(灰度发布)、AB测试、滚动发布、红黑部署的概念与区别
    2953 1
    |
    监控 数据可视化 安全
    软件生命周期是什么?包括哪些阶段?各阶段的目标和任务是什么?
    在数字化时代,软件如同空气般无处不在,其生命周期涵盖从需求分析到退役的多个阶段,如同生物的成长过程。本文详细介绍了软件生命周期各阶段的目标与任务,并探讨了瀑布模型、迭代模型和敏捷模型等常见生命周期模型。未来,随着技术和业务的不断演变,软件生命周期管理将面临更多挑战与机遇,需不断学习先进方法和技术,以满足用户需求。
    6366 0
    |
    关系型数据库 MySQL 数据库
    MySQL 什么是意向锁?为什么要有意向锁?
    【8月更文挑战第24天】MySQL 什么是意向锁?为什么要有意向锁?
    1460 0