第一章.设计原则-----开放-封闭原则

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haochangdi123/article/details/85603224

在面向对象的程序设计中 ,开放-封闭原则 (OCP)是最重要的一条原则。很多时候,一个程序具有良好的设计,往往说明它是符合开放-封闭原则的。

它的定义如下:
软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。

开放-封闭原则的思想:
当需要改变一个程序的功能或者给这个程序增加新功 能的时候,可以使用增加代码的方式,但是不允许改动程序的源代码。

1.扩展window.onload函数

假设我们是一个大型 Web 项目的维护人员,在接手这个项目时,发现它已经拥有 10 万行以上的 JavaScript 代码和数百个 JS 文件。

接到了一个新的需求,即在 window.onload 函数中打印出页面中的所有节点数量。这很简单:

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

如果目前的 window.onload 函数是一个拥有 500 行代码的巨型函数,里面密布着各种变量和交叉的业务逻辑,而我们的需求又不仅仅是打印一个 log 这么简单。

改动代码是一种危险的行为, 也许我们都遇到过 bug 越改越多的场景。刚刚改好了一个 bug,但是又在不知不觉中引发了其他的 bug。

我们可以通过增加代码,而不是修改代码的方式,来给 window.onload 函数添加新的功能:

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 函数的内部实现

2. 开放-封闭消除条件分支

过多的条件分支语句是造成程序违反开放封闭原则的一个常见原因。每当需要增加一个新 的 if 语句时,都要被迫改动原函数。

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

扫描二维码关注公众号,回复: 5052903 查看本文章

我们举一个让动物发出叫声的例子:
下面先提供一段不符合开放封闭原则的代码。每当我们增加一种新的动物时,都需要改动 makeSound 函数的内部实现:

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 Chcken){
 		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() ); // 汪汪汪

3. 如何遵循开放-封闭原则

我们能找到一些让程序尽量遵守开放封闭原则的规律,最明显的就是找出程序中将要发生变化的地方,然后把变化封装起来。

通过封装变化的方式,可以把系统中稳定不变的部分和容易变化的部分隔离开来。在系统的 演变过程中,我们只需要替换那些容易变化的部分,如果这些部分是已经被封装好的,那么替换起来也相对容易。而变化部分之外的就是稳定的部分。在系统的演变过程中,稳定的部分是不需要改变的。

帮助我们编写遵守开放封闭原则的代码方式:

3.1.利用对象的多态性

参考动物叫的例子

3.2.放置挂钩

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

可以在父类中的某个容易变化的地方放置挂钩,挂钩的返回结果由具体子类决定。这样一来,程序就拥有了变化的可能。

3.3 使用回调函数

在 JavaScript 中,函数可以作为参数传递给另外一个函数,这是高阶函数的意义之一。在这 种情况下,我们通常会把这个函数称为回调函数。在 JavaScript 版本的设计模式中,策略模式和 命令模式等都可以用回调函数轻松实现。

回调函数是一种特殊的挂钩。我们可以把一部分易于变化的逻辑封装在回调函数里,然后把 回调函数当作参数传入一个稳定和封闭的函数中。当回调函数被执行的时候,程序就可以因为回 调函数的内部逻辑不同,而产生不同的结果。

参考资料

JavaScript设计模式与开发实践----曾探

猜你喜欢

转载自blog.csdn.net/haochangdi123/article/details/85603224
今日推荐