在面向对象的程序设计中,开放封闭原则(OCP)是最重要的一条原则。很多时候,一个程序具有良好的设计,往往说明它是符合开放封闭原则的。 当需要改变一个程序的功能或者给这个程序增加新功能的时候,可以使用增加代码的方式,但是不允许改动程序的源代码。

故事背景

假设我们是一个大型 Web 项目的维护人员,在接手这个项目时,发现它已经拥有10万行以上的JavaScript代码和数百个 JS 文件。 不久后接到了一个新的需求,即在 window.onload 函数中打印出页面中的所有节点数量。这 当然难不倒我们了。于是我们打开文本编辑器,搜索window.onload函数在文件中的位置,在函数内部添加以下代码

window.onload = function(){ // 原有代码略console.log( document.getElementsByTagName( '*' ).length );
};
复制代码

应用OCP原则

Function.prototype.after = function( afterfn ){ var __self = this;return function(){var ret = __self.apply( this, arguments ); afterfn.apply( this, arguments );return ret;}
};
window.onload = ( window.onload || function(){} ).after(function(){ console.log( document.getElementsByTagName( '*' ).length );
});
复制代码

通过动态装饰函数的方式,我们完全不用理会从前 window.onload 函数的内部实现,就算拿到的是一份混淆压缩过的代码也没有关系。只要它从前是个稳定运行的函数,那么以后也不会因为我们的新增需求而产生错误。新增的代码和原有的代码可以互不影响。

编写符合OCP代码的方法

过多的条件分支语句是造成程序违反开放封闭原则的一个常见原因。每当需要增加一个新 的 if 语句时,都要被迫改动原函数。实际上,每当我们看到一大片的 if 或者 swtich-case 语句时,第一时间就应该考虑,能否利用对象的多态性来重构它们。

利用多态的思想

利用对象的多态性来让程序遵守开放封闭原则,是一个常用的技巧。

  • 不符合OCP
var makeSound = function( animal ){if ( animal instanceof Duck ){ console.log( '嘎嘎嘎' ); } else if ( animal instanceof Chicken ) {console.log( '咯咯咯' );}
};
var Duck = function(){};
var Chicken = function(){};
makeSound( new Duck() );
makeSound( new Chicken() );//动物世界里增加一只狗之后,makeSound 函数必须改成:
var makeSound = function( animal ){ if ( animal instanceof Duck ){console.log( '嘎嘎嘎' ); } else if ( animal instanceof Chicken ) {console.log( '咯咯咯' ); } else if ( animal instanceof Dog ) {console.log('汪汪汪' ); }
};
var Dog = function(){};
// 增加跟狗叫声相关的代码makeSound( new Dog() ); // 增加一只狗
复制代码

利用多态的思想,我们把程序中不变的部分隔离出来(动物都会叫),然后把可变的部分封 装起来(不同类型的动物发出不同的叫声),这样一来程序就具有了可扩展性。当我们想让一只狗发出叫声时,只需增加一段代码即可,而不用去改动原有的 makeSound函数

var makeSound = function( animal ){ animal.sound();
};
var Duck = function(){};
Duck.prototype.sound = function(){ console.log( '嘎嘎嘎' );
};
var Chicken = function(){};
Chicken.prototype.sound = function(){ console.log( '咯咯咯' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯
/********* 增加动物狗,不用改动原有的 makeSound 函数 ****************/
var Dog = function(){}; Dog.prototype.sound = function(){
console.log( '汪汪汪' ); };
makeSound( new Dog() ); // 汪汪汪
复制代码
放置挂钩

放置挂钩(hook)也是分离变化的一种方式。我们在程序有可能发生变化的地方放置一个挂钩,挂钩的返回结果决定了程序的下一步走向。这样一来,原本的代码执行路径上就出现了一个 分叉路口,程序未来的执行方向被预埋下多种可能性。

使用回调函数

在 JavaScript 中,函数可以作为参数传递给另外一个函数,这是高阶函数的意义之一。在这 种情况下,我们通常会把这个函数称为回调函数。在 JavaScript版本的设计模式中,策略模式和命令模式等都可以用回调函数轻松实现。 回调函数是一种特殊的挂钩。我们可以把一部分易于变化的逻辑封装在回调函数里,然后把 回调函数当作参数传入一个稳定和封闭的函数中。当回调函数被执行的时候,程序就可以因为回 调函数的内部逻辑不同,而产生不同的结果。

总结

开放封闭原则是一个看起来比较虚幻的原则,但我们还是能找到一些让程序尽量遵守开放封闭原则的规律,最明显的就是找出程序中将要发生变化的地方,然后把变化封装起来。 通过封装变化的方式,可以把系统中稳定不变的部分和容易变化的部分隔离开来。在系统的 演变过程中,我们只需要替换那些容易变化的部分,如果这些部分是已经被封装好的,那么替换起来也相对容易。而变化部分之外的就是稳定的部分。在系统的演变过程中,稳定的部分是不需要改变的。

系列文章:

《JavaScript设计模式与开发实践》最全知识点汇总大全

《JavaScript设计模式与开发实践》原则篇(3)—— 开放-封闭原则相关推荐

  1. 《JavaScript设计模式与开发实践》模式篇(12)—— 装饰者模式

    在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但是继承的方式并不灵活, 还会带来许多问题:一方面会导致超类和子类之间存在强耦合性,当超类改变时,子类也会随之 改变;另一方面,继承这种功能复 ...

  2. 《JavaScript设计模式与开发实践》模式篇(5)—— 观察者模式

    发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知.在 JavaScript 开发中,我们一般用事件模型 来替代传统的发布- ...

  3. 《JavaScript设计模式与开发实践》模式篇(3)—— 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 故事背景: 假设当 A 在心情好的时候收到花,小明表白成功的几率有 60%,而当 A 在心情差的时候收到花,小明表白的成功率无限趋近于 ...

  4. JavaScript设计模式与开发实践(网课学习)

    Js设计模式与开发实践 面向对象 5大设计原则 23种设计模式(实际只有21种) 设计模式主要分为下面三大类 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模 ...

  5. JavaScript设计模式与开发实践——JavaScript的多态

    "多态"一词源于希腊文polymorphism,拆开来看是poly(复数)+ morph(形态)+ ism,从字面上我们可以理解为复数形态. 多态的实际含义是:同一操作作用于不同的 ...

  6. 《JavaScript设计模式与开发实践》阅读摘要

    <JavaScript设计模式与开发实践>作者:曾探 系统的介绍了各种模式,以及js中的实现.应用,以及超大量高质量代码,绝对值得一读 面向对象的js 静态类型:编译时便已确定变量的类型 ...

  7. JS代理模式《JavaScript设计模式与开发实践》阅读笔记

    代理模式 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问. 保护代理和虚拟代理 保护代理:当有许多需求要向某对象发出一些请求时,可以设置保护代理,通过一些条件判断对请求进行过滤. 虚拟 ...

  8. javascript设计模式(javascript设计模式与开发实践读书笔记)

    javascript设计模式(javascript设计模式与开发实践读书笔记) 单例模式 策略模式 代理模式 迭代器模式 发布-订阅模式 命令模式 组合模式 模板方法模式 享元模式 职责链模式 中介者 ...

  9. 专访《Javascript设计模式与开发实践》作者曾探:爱编程 爱生活

     专访<Javascript设计模式与开发实践>作者曾探:爱编程 爱生活 发表于12小时前| 2742次阅读| 来源CSDN| 8 条评论| 作者夏梦竹 专访曾探图书作者Javascr ...

最新文章

  1. 前端知识之HTML内容
  2. 运维7年,对Linux的经验总结
  3. 益老而弥坚:软件开发哲学反思录
  4. Android+NDK+OpenGLES开发环境配置
  5. ORA-39095: Dump file space has been exhausted
  6. 用python画出叶子_太疯狂了!原来用粉笔画画,也可以这么美,简单几招教你,美到邻居羡慕嫉妒...
  7. c语言学习进阶-C语言程序实现矩阵乘法
  8. 高性能 TCP amp; UDP 通信框架 HP-Socket v3.2.3 正式宣布
  9. python读音Python怎么读
  10. 基于Keras搭建mnist数据集训练识别的Pipeline
  11. 银行专业术语解释说明 超级详细
  12. 读书感受 之 《穷查理宝典》
  13. 英飞凌XC2000系列单片机FLASH加解密策略
  14. 软件测试实战(微软技术专家经验总结)--第九、十章(团队工作、个人管理)读书笔记
  15. java 绘制动态的图形
  16. 【文字】文字消散效果
  17. 全国计算机技术与软件专业技术考试----(高级资格/高级工程师)各资格证详细介绍
  18. 历史上的经济危机各国最后都是怎么度过或解决的?
  19. 2022年9月11日:人生第一次相亲记录
  20. Android 高德地图选点,定位;实现地图选点上车功能;

热门文章

  1. Linux配置ssh无密码验证,rsync
  2. 位置子段最大子段和 hdu 1003 max sum ACM的开始
  3. RAID5EE 含有上次残余信息的分析
  4. linutx 基本配置
  5. 合并重定向 command file 21 解析
  6. 【bzoj5064】B-number 数位dp
  7. 【算法】N Queens Problem
  8. win2003的IIS無法使用,又一次安裝提示找不到iisadmin.mfl文件
  9. as3.0全屏代码…
  10. js+正文规则 高亮搜索关键字(二)