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

简介: 开闭原则(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.搞笑总结

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

    目录
    相关文章
    软件设计原则-迪米特原则讲解以及代码示例
    迪米特原则(Law of Demeter,简称LoD)也被称为最少知识原则(Least Knowledge Principle,LKP),是面向对象设计的一种重要原则。迪米特原则的核心思想是尽量减少对象之间的交互,使得系统中的模块能够相对独立地变化。
    123 0
    软件设计原则-迪米特原则讲解以及代码示例
    |
    测试技术
    软件设计原则-里氏替换原则讲解以及代码示例
    里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一条重要原则,它由Barbara Liskov在1987年提出。 里氏替换原则的核心思想是:父类的对象可以被子类的对象替换,而程序的行为不会发生变化。也就是说,如果一个类型A是另一个类型B的子类型,那么在任何使用B的地方都可以使用A,而不会引起错误或异常。
    512 0
    软件设计原则-接口隔离原则讲解以及代码示例
    接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的一个原则,提倡使用多个专门的接口,而不使用单一的大接口。它最早由Robert C. Martin在其《敏捷软件开发:原则、模式与实践》一书中提出。 接口隔离原则的核心思想是:客户端不应该依赖于它不需要的接口。也就是说,一个类或模块不应该强迫它的用户去依赖无用的接口。相反,应该将大接口拆分成多个小接口,符合客户端的需求,使客户端只依赖于它真正需要的接口。 接口隔离原则的目标是降低类或模块之间的耦合度,提高代码的可维护性、可扩展性和可测试性。通过使用多个专门的接口,我们可以避免类或模块之间出现不
    114 0
    |
    测试技术 数据库
    软件设计原则-依赖倒置原则讲解以及代码示例
    依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一个重要原则,由Robert C. Martin提出。 依赖倒置原则的核心思想是:高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现细节,而具体实现细节应该依赖于抽象。这意味着我们在进行系统设计时,应该尽量使用抽象类或接口来定义对象之间的依赖关系,而不是直接依赖于具体的实现类
    434 0
    软件设计原则-合成复用原则讲解以及代码示例
    合成复用原则(Composition/Aggregation Reuse Principle,CARP)是面向对象设计的一种重要原则,也被称为组合/聚合复用原则。它强调通过组合(Composition)或聚合(Aggregation)关系来达到代码复用的目的,而不是通过继承关系。
    190 0
    |
    程序员 测试技术
    面向对象设计五个基本原则
    只有聪明人才能看见的简介~( ̄▽ ̄~)~
    102 0
    |
    设计模式 Java 程序员
    代码设计原则
    代码设计原则
    384 0
    代码设计原则
    |
    设计模式
    【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
    【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
    113 0
    【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
    |
    设计模式 Oracle 关系型数据库
    【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )
    【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )
    291 0
    【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )
    |
    算法 关系型数据库 数据库
    面向对象基本原则(3)- 最少知道原则与开闭原则
    面向对象基本原则(1)- 单一职责原则与接口隔离原则 面向对象基本原则(2)- 里式代换原则与依赖倒置原则 面向对象基本原则(3)- 最少知道原则与开闭原则