1 定义

软件实体(类、模块、函数等等)应该是可以扩展的,但是不可修改的。开放-封闭原则主要体现在两个方面:

  • 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
  • 对修改封闭,意味着一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

返回目录

2 如何实现

在OCP中,实现开放封闭的方法就是抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。这是实施开放-封闭原则的基本思路,同时这种机制建立在两个基本的设计原则的基础上,这就是Liskov替换原则和合成/聚合复用原则。
       实现OCP原则的设计模式主要有模板模式、策略模式。而封装变化,是实现这一原则的重要手段,将经常发生变化的状态封装为一个类。具体设计模式的编写可以参考如下文章(4.1,4.2章节):
https://blog.csdn.net/weixin_37624828/article/details/106059837

2.1 问题: 一个糟糕的设计

代码清单:

  1. ShapeType.java --枚举类
  2. Point.java
  3. Shape.java
  4. Square.java
  5. Circle.java
  6. OcpDemo1.java

1 ShapeType.java

public enum ShapeType {/*** 圆*/CIRCLE,/*** 方*/SQUARE
}

2 Point.java

public class Point {private double x;private double y;public double getX() {return x;}public void setX(double x) {this.x = x;}public double getY() {return y;}public void setY(double y) {this.y = y;}public Point(double x, double y) {this.x = x;this.y = y;}@Overridepublic String toString() {return "Point{" +"x=" + x +", y=" + y +'}';}
}

3 Shape.java

public abstract class Shape {ShapeType itsType;
}

4 Square.java

public class Square extends Shape {double itsSide;Point itsToLeft;public Square(ShapeType itsType, double itsSide, Point itsToLeft) {this.itsType = itsType;this.itsSide = itsSide;this.itsToLeft = itsToLeft;}public void drawSquare(){System.out.println("绘制方形");System.out.println(toString());}@Overridepublic String toString() {return "Square{" +"itsSide=" + itsSide +", itsToLeft=" + itsToLeft +", itsType=" + itsType +'}';}
}

5 Circle.java

public class Circle extends Shape{double itsRadius;Point itsCenter;public Circle(ShapeType itsType, double itsRadius, Point itsCenter) {this.itsType = itsType;this.itsRadius = itsRadius;this.itsCenter = itsCenter;}public void drawCircle(){System.out.println("绘制圆形");System.out.println(toString());}@Overridepublic String toString() {return "Circle{" +"itsRadius=" + itsRadius +", itsCenter=" + itsCenter +", itsType=" + itsType +'}';}
}

6 OcpDemo1.java

public class OcpDemo1 {public static void main(String[] args) {List<Shape> shapeList = new ArrayList<>();shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));for (int i = 0; i < shapeList.size(); i++) {switch (shapeList.get(i).itsType){case CIRCLE:((Circle) shapeList.get(i)).drawCircle();break;case SQUARE:((Square) shapeList.get(i)).drawSquare();break;default:System.out.println("非圆非方");}}}
}

OcpDemo1中的main方法就不符合OCP原则,因为它对新的类型的添加不是封闭的,每次添加一个新类型就需要在switch菜单中添加一个选项。
       在实际工作中并非每一个判断条件都像上述选项中这么规范,一般的判断条件都是由逻辑操作符组合而成的复杂判断条件,因此这样的设计是一个糟糕的设计。

2.2 解决方案:遵循OCP

类图

注:蓝色代表Shape类型是可以扩展的

代码清单:

  1. Shape.java --接口
  2. Circle.java
  3. Square.java
  4. OcpDemo2.java

1 Shape.java

public interface Shape {/*** 绘制形状方法*/void draw();
}

2 Circle.java

public class Circle implements Shape{ShapeType itsType;double itsRadius;Point itsCenter;Circle(ShapeType itsType, double itsRadius, Point itsCenter) {this.itsType = itsType;this.itsRadius = itsRadius;this.itsCenter = itsCenter;}@Overridepublic void draw(){System.out.println("绘制圆形");System.out.println(toString());}@Overridepublic String toString() {return "Circle{" +"itsRadius=" + itsRadius +", itsCenter=" + itsCenter +", itsType=" + itsType +'}';}
}

3 Square.java

public class Square implements Shape {ShapeType itsType;double itsSide;Point itsToLeft;public Square(ShapeType itsType, double itsSide, Point itsToLeft) {this.itsType = itsType;this.itsSide = itsSide;this.itsToLeft = itsToLeft;}@Overridepublic void draw(){System.out.println("绘制方形");System.out.println(toString());}@Overridepublic String toString() {return "Square{" +"itsSide=" + itsSide +", itsToLeft=" + itsToLeft +", itsType=" + itsType +'}';}
}

4 OcpDemo2.java

public class OcpDemo2 {public static void main(String[] args) {List<Shape> shapeList = new ArrayList<>();shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));// 绘制图形drawShape(shapeList);}/*** 绘制图形* @param list 图形集合*/private static void drawShape(List<Shape> list) {for (Shape shape : list) {shape.draw();}}
}

如果list需要添加一个新类型时,drawShape方法无需做出修改,只需要实现一个新类型即可,这就遵循了开放-封闭原则。Shape类型是可以扩展的(遵循了开放),drawShape方法无需修改(遵循了封闭)。

3 结论

在许多方面,OCP都是面向对象设计的核心所在。遵循这个原则可以体现面向对象技术的好处(灵活性、可重用性以及可维护性)。但是并不是只要使用面向对象语言就需要遵循这个原则,开发人员应该对程序中频繁变化的部分做出抽象,而不是对程序肆意抽象。抽象和拒绝抽象同样重要

返回目录

开放-封闭原则(The Open-Closed Principle)相关推荐

  1. 开放-封闭原则(The Open-Closed Principle,OCP)

    自己设计的软件系统"易于维护"."扩展性好"."可重用"."具有灵活性",这是每位程序员所追求的目标."开闭原 ...

  2. 五大软件设计原则学习笔记2——开放封闭原则

    五大软件设计原则SOLID: 单一职责原则(Single responsibility principle,SRP) 开放封闭原则(Open–closed principle,OCP) Liskov ...

  3. C++设计模式-开放-封闭原则基本概念与实例

    目录 基本概念 举一个例子 基本概念 在如那就的设计模式中,不能修改,但可以扩展的实现是一条十分重要的原则,它是开放-封闭原则(The Open-Clossed Principle,简称OCP)或开- ...

  4. 大话设计模式三之单一职责原则、开放-封闭原则、依赖倒置原则、里氏代换原则

    单一职责原则 单一职责原则(SRP),意思就是说,功能要单一.准确解释是,就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或 ...

  5. 三、单一职责原则、开放-封闭原则、依赖倒转原则

    一.单一职责原则 1.定义:就一个类而言,应该仅有一个引起它变化的原因. 2.为什么要?:如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力 ...

  6. 开放-封闭原则(OCP)

    开放-封闭原则(The Open-Close Principle) 软件实体(类.模块.函数等)应该是可以扩展的,但是不可以修改的. 两个特征 1.对于扩展是开放的(Open for extensio ...

  7. 开放封闭原则(SCP:Open-Closed Principle)

    定义 GoF定义 Software entities (classes, modules, functions, etc.) should be open for extension, but clo ...

  8. 面象对象设计6大原则之二:开放封闭原则

    转载自 面象对象设计6大原则之二:开放封闭原则 开放封闭原则(OCP),The Open Closed Principle 定义 一个软件的实体,包括类.方法.模块.应该对扩展开放,对修改关闭. 也就 ...

  9. 开放封闭原则_开放/封闭原则

    开放封闭原则 I have to admit the first time I peeked at the academic definition of the Open/Closed Princip ...

最新文章

  1. 盘点|最实用的机器学习算法优缺点分析,没有比这篇说得更好了
  2. R语言neuralnet包构建神经网络模型:基于乳腺癌数据集
  3. 获取枚举类型的 中文 描述 和值
  4. java设计模——反射的应用 (利用反射来去除if判断语句)
  5. 百度搜索打不开第二页_北易信息:百度爱采购适合做优化推广吗
  6. 简单小程序代码_开个小程序店铺需要多少钱?
  7. Qt程序窗口关闭不退出而最小化到托盘的方法
  8. java 保存 设置_java – 保存设置的实现
  9. Google Android操作系统内核编译图文教程
  10. 【转载】为什么要用黑莓?
  11. 华翼宽带android客户端,太凶残了:电信推华翼宽带专门防蹭网
  12. android崩解日志,android – 使用rxJava2和改造的UndeliverableException
  13. 【codeVS 1082】树状数组(区间修改,区间查询)模版题
  14. 主板诊断卡的使用方法视频教程
  15. 全局钩子,解决命名烦恼!——代码翻译小工具。
  16. Sopcast软件中凤凰卫视频道列表代码
  17. 计算机无法访问dota服务器,dota2无法与任何服务器建立连接如何解决
  18. 语音共振峰的获取python
  19. 百度糯米用大数据重塑O2O产业
  20. 大数据薪水大概多少_大数据工程师工资一般多少钱

热门文章

  1. Smarter公众号做CV界最优质的内容输出(16人银河战舰)
  2. “爱情呼叫转移”有感
  3. Cannot determine the organization name for this ‘dev.azure.com‘ remote url 解决方法
  4. 新零售:新与旧的唯一评判标准就是:科技是第一生产力
  5. 字节跳动张一鸣:给互联网人才的一些中肯建议!
  6. HTML+CSS+JS实现简单登录模板
  7. 2018年广东工业大学文远知行杯新生程序设计竞赛 1013 在那天的雪停息之前β...
  8. 记录linux的内网穿透frp操作
  9. HTML5网页页面无刷新更新页面URL
  10. 用vc对oracle数据库编程,用VC开发基于ORACLE数据库应用程序