接口和面向接口编程

  谈到接口的时候,通常会涉及以下几种含义:
  第一种接口是指一个库或者模块对外提供了某某API接口。通过主动暴露的接口来通信,可以隐藏软件系统内部的工作细节。
  第二种接口是一些语言提供的关键字,比如Java的interface。interface关键字可以产生一个完全抽象的类。这个完全抽象的类用来表示一种契约,专门负责建立类与类之间的联系。
  第三种接口即是谈论的“面向接口编程”中的接口,接口是对象能响应的请求的集合

  不关注对象的具体类型,而仅仅针对超类型中的“契约方法”来编写程序,可以产生可靠性高的程序,也可以极大地减少子系统实现之间的相互依赖关系,这就是面向接口编程
  从过程上来看,“面向接口编程”其实是“面向超类型编程”。当对象的具体类型被隐藏在超类型身后时,这些对象就可以相互替换使用,关注点才能从对象的类型上转移到对象的行为上。“面向接口编程”也可以看成面向抽象编程,即针对超类型中的abstract方法编程,接口在这里被当成abstract方法中约定的契约行为。这些契约行为暴露了一个类或者对象能够做什么,但是不关心具体如何去做。

interface

  除了用抽象类来完成面向接口编程之外,使用interface也可以达到同样的效果。虽然很多人在实际使用中刻意区分抽象类和interface,但使用interface实际上也是继承的一种方式,叫作接口继承。
  相对于单继承的抽象类,一个类可以实现多个interface。抽象类中除了abstract方法之外,还可以有一些供子类公用的具体方法。interface使抽象的概念更进一步,它产生一个完全抽象的类,不提供任何具体实现和方法体,但允许该interface的创建者确定方法名、参数列表和返回类型,这相当于提供一些行为上的约定,但不关心该行为的具体实现过程。

JS

  因为JS是一门动态类型语言,类型本身在JS中是一个相对模糊的概念。也就是说,不需要利用抽象类或者interface给对象进行“向上转型”。除了number、string、boolean等基本数据类型之外,其他的对象都可以被看成“天生”被“向上转型”成了Object类型。
  在动态类型语言中,对象的多态性是与生俱来的,但在另外一些静态类型语言中,对象类型之间的解耦非常重要,甚至有一些设计模式的主要目的就是专门隐藏对象的真正类型。
  因为不需要进行向上转型,接口在JS中的最大作用就退化到了检查代码的规范性。比如检查某个对象是否实现了某个方法,或者检查是否给函数传入了预期类型的参数。如果忽略了这两点,有可能会在代码中留下一些隐藏的bug。
  如果JS有编译器帮助检查代码的规范性,那事情要比现在美好得多,不用在业务代码中到处插入一些跟业务逻辑无关的防御性代码。作为一门解释执行的动态类型语言,把希望寄托在编译器上是不可能了。如果要处理这类异常情况,只有手动编写一些接口检查的代码

用鸭子类型进行接口检查。

”如果它走起来像鸭子,叫起来也是鸭子,那么它就是鸭子"

  鸭子类型是动态类型语言面向对象设计中的一个重要概念。利用鸭子类型的思想,不必借助超类型的帮助,就能在动态类型语言中轻松地实现面向接口编程。比如,一个对象如果有push和pop方法,并且提供了正确的实现,它就能被当作栈来使用;一个对象如果有length属性,也可以依照下标来存取属性,这个对象就可以被当作数组来使用。如果两个对象拥有相同的方法,则有很大的可能性它们可以被相互替换使用。
  在Object.prototype.toString.call([])==='[object Array]'被发现之前,经常用鸭子类型的思想来判断一个对象是否是一个数组,代码如下:

var isArray = function( obj ){ 
  return obj &&
    typeof obj === 'object' && 
    typeof obj.length === 'number' &&
    typeof obj.splice === 'function'
};
TS

  TypeScript的是JavaScript的一个超集,本质上向这个语言添加了可选的静态类型和基于类的面向对象编程,通过TypeScript,可以使用静态语言的方式来编写JS程序,TypeScript可以实现类,接口,枚举,泛型,方法重载等,用简洁的语法丰富了JavaScript的使用,用TypeScript来实现一些设计模式,显得更加原汁原味。

参考文献

《JavaScript设计模式与开发实践》

你可能感兴趣的:(接口和面向接口编程)