JavaScript设计模式与开发实践(1)

1,面向对象的 JavaScript

1.1 理解鸭子类型

鸭子类型的通俗说法是:“如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。”
国王要听的只是鸭子的叫声,这个声音的主人到底是鸡还是鸭并不重要。鸭子类型指导我们只关注对象的行为,而不关注对象本身。这里我个人的理解是把谁来做和做什么事给抽离开。在做什么事里面,我不需要关心是谁来做,我只需要关心怎么去做这件事。而至于谁来做,谁来做都可以,只要可以能做这件事就行。

var duck = {
 duckSinging: function(){
 	console.log( '嘎嘎嘎' );
 }
};
var chicken = {
 duckSinging: function(){
 	console.log( '嘎嘎嘎' );
 }
};
var choir = []; // 合唱团
var joinChoir = function( animal ){
 if ( animal && typeof animal.duckSinging === 'function' ){
	 choir.push( animal );
	 console.log( '恭喜加入合唱团' );
	 console.log( '合唱团已有成员数量:' + choir.length );
 }
};
joinChoir( duck ); // 恭喜加入合唱团
joinChoir( chicken ); // 恭喜加入合唱团

上面的代码就可以很好的解释了,在怎么做中,无需检查它们的类型,而是只需要保证它们拥有 duckSinging 方法。如果下次期望加入合唱团的是一只小狗,而这只小狗刚好也会鸭子叫,那么这只小狗也能顺利加入。
所以在静态语言中,大家都遵循着面向接口(面向对象)编程,而不是面向过程,通过一个抽象类来约束怎么做一件事,然而Javascript是动态语言并且没有接口的概念,这里我们就可以用鸭子模型,只要这个对象有了某种能力,那么它就可以去做某件事,而做的这件事不必像静态语言一样受谁来做的约束。

1.2 多态

多态用一句话来概括就是:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。
从字面上来理解多态不太容易,下面我们来举例说明一下。

主人家里养了两只动物,分别是一只鸭和一只鸡,当主人向它们发出“叫”的命令时,鸭会“嘎嘎嘎”地叫,而鸡会“咯咯咯”地叫。这两只动物都会以自己的方式来发出叫声。它们同样“都是动物,并且可以发出叫声”,但根据主人的指令,它们会各自发出不同的叫声。

接下来我们用代码来实现:

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() ); // 咯咯咯 

上述代码就蕴含着多态的思想,都是发出声音的动作,但只因为做这件事的动物不同,所以得到的结果也不同。注意,这里还是在培养我们一种思想,就是把做一件事和谁来做给分开。但上面的代码是有问题的,他在做什么事的时候,并没有把谁来做给解耦开,还是和谁来做耦合在一起,这样就会导致,如果后期又来了一条狗,那么在代码内又多了一条分支,这样后期维护起来会很困难,而且也违反了设计模式的开放—封闭原则。
要想对上面的代码进行优化,在Java中需要用到多态的语法,定义一个动物抽象类,他具有发出声音的动作,然后让谁来做去继承该抽象方法,去实现发出动作的具体内容,利用多态的语言,即左父右子创建多态子类(说白了,其实就是一个向上转型,逃避类型检查的作用),在做什么事内,做的内容需要接受一个动物类,这样经过多态创建的子类就可以逃避类型检查成功的作为参数传入。以上是个人的理解,下面是具体的Java实现多态的代码。

public abstract class Animal {
 	abstract void makeSound(); // 抽象方法
}
public class Chicken extends Animal{
 	public void makeSound(){
 		System.out.println( "咯咯咯" );
 	}
}
public class Duck extends Animal{
 	public void makeSound(){
 		System.out.println( "嘎嘎嘎" );
	}
}
Animal duck = new Duck(); // 多态语法
Animal chicken = new Chicken(); // 多态语法

现在剩下的就是让 AnimalSound 类的 makeSound 方法接受 Animal 类型的参数,而不是具体的Duck 类型或者 Chicken 类型:

public class AnimalSound{
 	public void makeSound( Animal animal ){ // 接受 Animal 类型的参数
 		animal.makeSound();
 	}
}
public class Test {
	 public static void main( String args[] ){
		 AnimalSound animalSound= new AnimalSound ();
		 Animal duck = new Duck();
		 Animal chicken = new Chicken();
		 animalSound.makeSound( duck ); // 输出嘎嘎嘎
		 animalSound.makeSound( chicken ); // 输出咯咯咯
	 }
} 

但在JavaScript中就完全没有这么复杂,这都是归功于JavaScript属于静态语言,它不需要像Java一样进行类型检查,所以JavaScript实现上面案例的代码如下:

var Duck = function(){}
Duck.prototype.sound = function(){
 	console.log( '嘎嘎嘎' );
};
var Chicken = function(){}
Chicken.prototype.sound = function(){
 	console.log( '咯咯咯' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯

var makeSound = function( animal ){
 	animal.sound();
};

由此可见,某一种动物能否发出叫声,只取决于它有没有 makeSound 方法,而不取决于它是否是某种类型的对象,这里不存在任何程度上的“类型耦合”。这正是我们从上一节的鸭子类型中领悟的道理。在 JavaScript 中,并不需要诸如向上转型之类的技术来取得多态的效果。

1.3 封装

1.4 继承

略(在之前红宝书相关内容中有更为详细的笔记)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值