首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >还不理解 OCP 的开放程度?赶紧了解下

还不理解 OCP 的开放程度?赶紧了解下

作者头像
程序视点
发布2023-09-13 12:39:30
发布2023-09-13 12:39:30
3840
举报
文章被收录于专栏:程序小小事程序小小事

上一篇,我们聊了S.O.L.I.D原则中的S:Single Responsibility Principle(SRP),也就是我们说的单一职责原则

今天我们来说说O:Open Closed Principle(OCP),开闭原则。

OCP 简介

开闭原则,是面向对象设计中的重要原则之一,其核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。

也就是说,当一个实体需要添加新功能或修改现有功能时,不应该对原有的代码进行修改,而通过扩展来实现新的功能或行为。

一句话:不能改!

PS:话又说回来,谁写代码能保证总是一次写对,不再修改呢?😓~ 因此,这个原则是让我们在实践过程中要多为代码的扩展性考虑。即使我们不能一口气完成最优的版本,也能基于这个原则去对代码做优化!

实践 OCP 的方法和技巧

要做到“不修改原有的代码添加或修改功能”,那就需要将新功能或修改现有功能的代码与原有代码进行解耦

这可以降低修改已有代码带来的风险和代价,同时提高软件的可维护性和可扩展性。这也符合“开闭原则”的字面意义,即对扩展开放,对修改关闭。

对此,我们可以采用以下的设计技巧和方法:

  • 抽象化 通过定义抽象类或接口来描述公共的行为,并且让具体的实现类去继承或实现这些抽象定义。这样,当需求变化时,我们只需要增加新的实现类即可,而无需修改已有的代码。
  • 多态 利用多态性质,通过父类或接口的引用来调用子类的方法。这样做可以在不改变原有代码的情况下,对系统行为进行扩展和定制。
  • 设计模式 使用设计模式,如策略模式、观察者模式、工厂模式等,来封装变化和抽象变化的部分。这些设计模式都是根据开闭原则的思想而产生的,可以帮助我们构建灵活、可扩展的软件系统。

抽象和多态的技巧,对于熟悉继承和实现的小伙伴来说,比较简单。PS:不懂“抽象”和“多态”的小伙伴可先自行百度一下。后续如果有需要,小二哥可以把这些简单的知识点也串一串~

相对不好理解的,应该是设计模式中使用OCP的情况。鼓励大家看看这两篇文章简单工厂模式(Simple Factory)工厂方法模式(Factory Method Pattern)。这两篇文章把如何使用 OCP 进行优化 体现得相对清晰。

之后,就可以看下策略模式、观察者模式等其他模式。PS:一种设计模式中,可能包含了多个设计原则!这也是有些设计模式理解起来比较难的原因。小伙伴们可以尝试慢慢的去理解。实在不行,就先把上面的简单工厂和工厂方法模式看了,把OCP理解清楚~

实践 OCP 的例子

前面简单工厂模式(Simple Factory)工厂方法模式(Factory Method Pattern)中已经有例子了。

本文这里再举个例子:假设我们正在开发一个图形绘制应用程序,其中包含多种形状,例如圆形、矩形和三角形。最初的设计可能如下。

代码语言:javascript
复制
public class Shape {
    private String type;
    
    public void draw() {
        if (type.equals("Circle")) {
            drawCircle();
        } else if (type.equals("Rectangle")) {
            drawRectangle();
        } else if (type.equals("Triangle")) {
            drawTriangle();
        }
    }
    
    private void drawCircle() {
        System.out.println("Drawing a circle");
    }
    
    private void drawRectangle() {
        System.out.println("Drawing a rectangle");
    }
    
    private void drawTriangle() {
        System.out.println("Drawing a triangle");
    }
}

现在,我们要添加画五角星的功能,怎么办?按照上面的代码,我们只能修改原代码,再弄出个else if(type.equal("star")),再添加一个drawStar()的方法。这违反了开闭原则,因为我们应该对扩展是开放的,对修改是关闭的。

为了符合开闭原则,我们可以使用多态来解决这个问题。首先,我们定义一个抽象基类Shape:

代码语言:javascript
复制
public abstract class Shape {
    public abstract void draw();
}

然后,我们为每种具体的形状创建一个子类,并在子类中实现draw()方法:

代码语言:javascript
复制
public class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}
代码语言:javascript
复制
public class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
}
代码语言:javascript
复制
public class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a triangle");
    }
}

我们可以通过使用这些子类来绘制不同的形状,而无需修改Shape类的代码:

代码语言:javascript
复制
Shape circle = new Circle();
circle.draw(); 
// 输出:Drawing a circle

Shape rectangle = new Rectangle();
rectangle.draw(); 
// 输出:Drawing a rectangle

Shape triangle = new Triangle();
triangle.draw(); 
// 输出:Drawing a triangle

如果要添加星形的图案,再来个类就好了。

代码语言:javascript
复制
public class Star extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a star");
    }
}

画个星形图案。

代码语言:javascript
复制
Shape star = new Star();
star.draw(); 
// 输出:Drawing a star

我们可以轻松地扩展应用程序,添加新的形状,又没有修改现有的代码。这提高了代码的可维护性和扩展性。

总结

开闭原则是面向对象编程的基石之一。核心是:对扩展开放,对修改关闭

带来的好处如下:

  • 可扩展性:通过扩展已有的代码,我们可以轻松地添加新的功能,而不需要修改原有的代码。这样做可以降低引入新错误的风险,并且在整个系统中保持相对稳定的状态。
  • 可维护性:当需求变化时,我们只需要添加新的代码,而不是修改已有的代码。这样做可以减少代码的复杂性和不稳定性,从而简化代码的维护工作。同时,由于模块之间的耦合性较弱,可以更容易地定位和修复问题。
  • 可复用性:开闭原则鼓励我们构建具有高内聚和低耦合性的模块。这种模块设计可以更容易地被其他部分复用,提高了代码的可复用性。

它鼓励我们设计具有良好封装和扩展性的代码。通过将可变的部分进行抽象,并通过多态来处理变化,我们可以实现对扩展开放、对修改关闭的设计。这有助于降低代码的耦合度并提高系统的可拓展性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-15 08:00,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序视点 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • OCP 简介
  • 实践 OCP 的方法和技巧
  • 实践 OCP 的例子
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档