javascript设计模式与开发实践(一)- 多态

PS:上一篇文章发表之后,很多朋友关注了本人的思否和掘金的博客,虽然关注的朋友还有有限,但足够让我把自己在技术上的问题积累分享给大家,也希望大家能够喜欢,同时能动一动手指,给一颗心(赞),博主会持续更新下去

多态

本文是《javascript设计模式与开发实践》一书学习笔记,因书中所表述的概念简单明了,故将整本书的笔记奉上,全部文章大概在20篇左右,还请朋友们持续关注

动态语言类型

编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言

静态类型语言,声明任何变量或者形参都需要指定类型,例如java语言。
动态类型语言,声明任何变量或者形参都不需要指定类型,javascript就是动态类型语言。

所谓动态,可以多层面的理解,首先,声明变量不需要指定类型,其次,在多态思想下,java中需要利用父类实现多态,而javascript就不需要,本身自带多态属性。

多态

熟悉java的朋友知道,java三大特征之一就有多态,多态给java带来了很大的灵活性,很多设计模式也是通过多态来实现,java中的多态涉及到向上转型和向下转型,而javascript(以下简称js)的”多态”就相对来说容易实现

我们来看一段“多态”的js代码

var makeSound = function(an) {
    if(an instanceof Duck) {
        console.log("嘎嘎嘎");
    } else if(an instanceof Dog) {
        console.log("汪汪汪");
    }
}

var Dog = function(){};
var Duck = function(){};

makeSound(new Dog());
makeSound(new Duck());

这段代码确实体现了“多态性”,当我们分别向鸭和鸡发出“叫唤”的消息时,它们根据此 消息作出了各自不同的反应,但是这样写会有一个弊端,当更多的类型出现时,我们要不断的修改makeSound函数,后期makeSound函数也会变得十分巨大,这不符合良好代码设计的规范,多态背后的思想是将“做什么”和“谁去做以及怎样去做”分离开来,也就是将“不变的事 物”与 “可能改变的事物”分离开来。在这个故事中,动物都会叫,这是不变的,但是不同类 型的动物具体怎么叫是可变的。把不变的部分隔离出来,把可变的部分封装起来,这给予了我们 扩展程序的能力,程序看起来是可生长的,也是符合开放—封闭原则的,相对于修改代码来说, 仅仅增加代码就能完成同样的功能,这显然优雅和安全得多

首先,我们把makeSound函数修改一下:

var makeSound = function(an) {
    an.speak();
}

这段代码传入一个对象,然后调用对象的speak函数

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 函数

类型检查和多态

现在,我们来进一步了解多态,之前说到,java的多态需要利用继承来实现,我们现在把动物的例子换成java代码

public class Duck {
    public void speak(){
        System.out.println( "嘎嘎嘎" );
    }
}

public class Dog {
    public void speak(){
        System.out.println( "汪汪汪" );
    }
}

public class AnimalSpeak{
    public void makeSound(Duck duck){
        duck.speak();
    }
}

public static void main(String args[]){
    AnimalSpeak an = new AnimalSpeak();
    Duck duck = new Duck();
    an.makeSound(duck); // 输出:嘎嘎嘎
}

现在鸭子已经顺利叫出来了,但是我们想让狗也叫,发现不太容易实现,因为makeSound函数中,形参是Duck类型,传入Dog类型一定会报错,这个时候继承就出现了,java设计思路是我先创建一个父类,具体传入的类型由子类决定,但是makeSound函数中的形参确是父类类型,实现如下:

public abstract class Animal{
    abstract void speak(); // 抽象方法
}

public class Duck extends Animal {
    public void speak(){ // 覆写父类中的抽象方法
        System.out.println( "嘎嘎嘎" );
    }
}

public class Dog extends Animal {
    public void speak(){ // 覆写父类中的抽象方法
        System.out.println( "汪汪汪" );
    }
}

public class AnimalSpeak{
    public void makeSound(Animal an){
        an.speak();
    }
}

public static void main(String args[]){
    AnimalSpeak an = new AnimalSpeak();
    Animal duck = new Duck();
    Animal dog = new Dog();
    an.makeSound(duck); // 输出:嘎嘎嘎
    an.makeSound(dog); // 输出:汪汪汪
}

js中的多态

JavaScript 对象的多态性是与生俱来的,为什么这么说? 仔细看看这两个函数:

public void makeSound(Animal an){
    an.speak();
}

function(an) {
    an.speak();
}

js和java中的函数的形参是不同的,java定死了传入的类型,而js是动态的,js随便可以传入任何类型,所以,我们之前说js是动态类型语言,在 JavaScript 这种将函数作为一等对象的语言中,函数本身也是对象,函数用来封装行为并 且能够被四处传递。当我们对一些函数发出“调用”的消息时,这些函数会返回不同的执行结 果,这是“多态性”的一种体现,也是很多设计模式在 JavaScript 中可以用高阶函数来代替实现的原因。

    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000013510949
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞