两截门--一个被水平分割为两部分的门,这样每一部分都可以独立保持开放或封闭

开放-封闭原则(The Open-Closed Principle)

软件实体(类、模块、函数)应该是可以扩展的,但是不可以修改的。
如果程序中的一处改动就会产生连锁反应,导致一系列的相关模块的改动,那么设计就具有僵化的臭味。如果正确的应用OCP,那么以后再进行同样的改动时,就只需要添加新的代码,而不必改动已经正常运行的代码。

描述

主要两个特征:

  1. “对于扩展是开放的”
    模块的行为是可以扩展的,当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。简言之,我们可以改变模块的功能。
  2. “对于更改是封闭的”
    对模块进行扩展时,不必改动模块的源代码。

关键是抽象

下图展示了一个简单的不遵循OCP的设计。Client类和Server类都是具体类,Client类使用Server类。如果我们希望Client对象使用另外一个不同的服务器对象,那么就必须要把Client类中使用Server类的地方更改为新的服务器类

下图是根据OCP设计重构的设计

ClientInterface类是一个拥有抽象成员函数的抽象类,Client类使用这个抽象类。如果我们希望Client对象使用一个不同的服务器类,那么只需要冲ClientInterface类派生一个新的类,无需对Client类做任何改动。

Shape应用程序

应用程序中有Circle、Square列表,需求是:绘制他们
从OCP原则考虑,设计方案如下,

class Shape{
draw();
}class Circle extends Shape{draw(){}
}class Square extends Shape{draw(){}
}Class DrawAllShape{void drawAllShapes(List<Shape> lists){for(Shape shape :lists){shape.draw();}}
}

根据此设计,如果新增一个Triangle类,只需新增代码即可,无需改动上述代码,达到了开闭原则。真的吗???

并非100%封闭

如果需求要求所有圆必须在正方形之前绘制,那么DrawAllShape无法对这种变化做到封闭。要实现这个需求,我们需要修改DrawAllShape,使它首先扫描列表中的圆,然后在扫描所有的正方形。

预测变化和贴切的结构

一般来说,无论模块是多么封闭,都会存在一些无法对之封闭的变化,没有对于所有的情况都贴切的模型。
既然不能完全封闭,就要有策略的对待这个问题,设计人员必须对于他设计的模块应该对哪种变化封闭作出选择,他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。这需要设计人员具备一些从经验中获得的预测能力。
遵循OCP的代价是昂贵的,创建正确的抽象是要花费开发时间和精力的,同时,那些抽象也增加了软件设计的复杂性,开发人员有能力处理的抽象的数量也是有限的,显然,我们希望把OCP的应用限定在可能会发生的变化上。
  • 只受一次愚弄
    最初编写代码的时候,假设变化不会发生,当变化发生了,我们就创建抽象来隔离以后发生的同类变化。
  • 刺激变化
    尽早查明可能发生的变化,尽早接受变化带来的改变。

Shape改造

class Shape{draw();//precedes();precedes(OrderRule order){}
}
Class DrawAllShape{sort(list);void drawAllShapes(List<Shape> lists){for(Shape shape :lists){shape.draw();}}
}

precedes()考虑到枚举排序的话违背了OCP,可以将规则定义起来,改造成precedes(OrderRule order),排序规则从OrderRule中读取,此时对与Shape绘制顺序的变化不封闭的唯一部分就是OrderRule。

结论

在许多方面,OCP都是面向对象设计的核心所在。遵循这个原则可以的带来面向对象技术所声称的巨大好处(灵活性,可重用性,可维护性)。对于应用程序中的每个部分都肆意的进行抽象同样不是一个好主意。正确的做法是,开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。

转载于:https://www.cnblogs.com/vincent0928/p/6568354.html

面向对象设计原则之开闭原则相关推荐

  1. Java面向对象设计原则1——开闭原则

    在我们学习面向对象编程的时候,总会出现一些问题,好比以前刚刚写好的代码,上线测试可以.正常运行,突然有一天说要加一个功能,改完之后,发现以前正常运行的功能不能用了,类似这样的问题有好多好多,为了避免类 ...

  2. 6大设计原则之开闭原则

    开闭原则的定义 开闭原则的定义: 一个软件实体,如类.模块和函数应该对扩展开放,对修改关闭.即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化. 软件实体包括一下部分 项目或软件 ...

  3. Java设计原则之单一职责原则、开闭原则、里氏代换原则

    文章目录 面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 面向对象设计原则概述 软件的可维护性(Maintainability)和可复用性(Reusability)是两个非常重要的用于衡量 ...

  4. 设计原则:开闭原则(OCP)

    1.什么是开闭原则 开闭原则的英文是Open Closed Principle,缩写就是OCP.其定义如下: 软件实体(模块.类.方法等)应该"对扩展开放.对修改关闭". 从定义上 ...

  5. 设计模式-02.经典设计原则-第一节-单一职责原则,开闭原则,里式替换,接口隔离【万字长文系列】

    文章目录 设计模式经典设计原则-第一节 单一职责原则(SRP) 如何理解单一职责原则? 如何判断类的职责是否足够单一? 类的职责是否设计得越单一越好? 开闭原则(OCP) 如何理解"对扩展开 ...

  6. 关于Java面向对象程序设计原则之一——开闭原则的思考与分享

    整理日期:2022-05-27 目录 一.开闭原则 二.为什么使用开闭原则 三.如何在程序设计中体现开闭原则 一.开闭原则 开闭原则(Open-Closed Principle, OCP)是指一个软件 ...

  7. [设计原则] 六大设计原则之“开闭原则”

    [设计原则] 六大设计原则之"开闭原则" 目录 [设计原则] 六大设计原则之"开闭原则" 什么是开闭原则 为什么使用开闭原则 如何使用开闭原则 注意事项 总结 ...

  8. 设计模式-软件架构设计七大原则及开闭原则详解

    前言 在日常工作中,我们使用Java语言进行业务开发的时候,或多或少的都会涉及到设计模式,而运用好设计模式对于我而言,又是一个比较大的难题.为了解决.克服这个难题,Remi酱特别开了这个博客来记录自己 ...

  9. 七大设计原则之开闭原则

    一.开闭原则介绍 开闭原则(Open Closed Principle)是编程中最基础,也是最重要的设计原则.编程中遵循其他原则以及使用设计模式的目的就是遵循开闭原则. 一个软件实体如类,模块和函数应 ...

  10. 设计模式六大原则之--开闭原则(OCP)

    设计模式六大原则之--开闭原则(OCP) 前言 1 描述 2 理解: 3 问题由来: 4 使用LoD的好处: 5 难点: 6 最佳实践: 7 范例: 前言 The Open - Closed Prin ...

最新文章

  1. 华为消息推送 有透传通道吗_华为首款头戴耳机FreeBuds Studio正式发布,能否撑起品牌之名?...
  2. 不关闭seLinux解决vsftpd服务本地用户不能登录问题(500 OOPS: cannot change directory:/home/***
  3. SCSF 系列:Smart Client Software Factory 启动过程详解
  4. bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
  5. How to tell if UIViewController's view is visible
  6. 有向图的拓扑排序的理解和简单实现(Java)
  7. 基于小波变换的图像压缩解压缩仿真
  8. 《系统集成项目管理工程师》必背100个知识点-31WBS的分解原则
  9. [Android]关于IntentService
  10. 原生JS字符串操作方法汇总
  11. 430单片机实现三人投票表决器_长虹KFR-28变频空调器室内机控制板电路原理分析...
  12. 拉拢苹果用户,谷歌推出“从 iOS 转移到 Android” App
  13. Python Seaborn教程
  14. Struts2 - 常用的constant总结
  15. 人工智能——前言概述
  16. linux能安装cad快速看图不,ubuntu下能过wine安装cad快速看图
  17. 如何自己搭建测试环境
  18. NFT交易平台2.0来了,源代码,智能合约整套
  19. CSS 使文字纵向排列的七种方
  20. CRMEB在线教育知识付费系统应用领域及功能介绍

热门文章

  1. android.content.Context.getResources()‘ on a null object reference
  2. 用diff命令制作补丁
  3. ElasticSearch7.x「新特性」
  4. 查看docker的端口映射情况
  5. Spring IOC流程源码分析
  6. linux文件系统启动流程 ---笔记整理
  7. linux内核printk调试
  8. Android Framework常用工具及LOG调试方法
  9. DPOS共识算法—缺失的白皮书
  10. GAN的理解与TensorFlow的实现