面向对象的javascript系列文章(1)接口——是一个标准委员会

在面向对象开发中,接口确实是一个特别抽象的名词,加上一些语法的赘述,“醉了~再见”有木有。

一般在java中对于接口的定义会是这样的:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。来源于百度百科微笑别打我,但是人家说的有错?

这个定义完全就是在说怎么去创建使用一个接口,接口的特征啊。第一次学接口看到这个定义的时候 我有种这样的感觉,可能定义接口的作者会有这个心态:“你有种去理解,能get到算我输。”(开个玩笑了~毕竟人家是学术性的)读者可以看看我换个角度是怎么理解的,明白与否以及描述的理解上的错误 欢迎留言批评。

其实接口就是一个标准委员会,有ECMAScript标准委员会、http标准委员会、水龙头水管接口标准委员会…… 他们的职责无非就是制定某个行业某种商品的标准,以及去监督这个商品的产生是否遵循标准去执行,否则就去警告。

还不理解?没关系能理解标准委员会就好。在下面的第一节中会详细描述的。感受一下我扯淡的水平微笑

 

一、到底什么是接口?

 先定义两个东西水管和水龙头

当这个社会还是很单纯的就只有一家水官厂一家书龙头厂他们在商量好接头的型号为圆形之后,分别制作了一个模具,开始大规模的生产,生产的样子如下,他们貌似很开心的赚钱着。

当有一天,随着社会的需求不断增加,水龙头厂企业发现个这个矛头,然后就开始大力的研发模具生产新的型号的水龙头,这种水龙头是“互联网+”的产品,但是这家公司的设计师由于疏忽吧接头改为了三角形。生产如下:

 

这家水官厂发现接口变了,所以为了不错过商机,也跟着研发了新的接头的水管,但是仅仅是接头变了。

 就这样随着社会的不断发展,需求逐渐扩大,水龙头厂就这么的不断研发着新的型号的模具、制造新的型号的产品……但只是研发模具的人员总是疏忽不断改变接头的型号,发展到是这样的:

 

 

你说,到最后谁能疯,当然是水官厂的研发磨具的人员了。他们站出来呐喊了,

水管厂研发磨具的人员:“水龙头的研发人员挺好了能不能别总是在改接头了说好的圆形呢再见”,

水龙头厂也很冤枉啊,说:“我们这里研发人员经常换人他们并不知道之前是圆形的啊”。

水管厂研发磨具的人员:“你们知道吗?这些水管几乎都一样的就是接头变了,让我们还要加班重新开发新的模具委屈”。

最终水管厂研发磨具的人员和水龙头研发磨具的人员成立了一个水龙头水管接口标准委员会,这个委员会经过几天的讨论就郑重发布消息了:“标准如下:研发的任何新产品的模具接头只能是圆形的不能有其他型号。好处如下:(一)可以让任何一方不再制造无用的重复高相似的仅仅是接头不一样的模具,增加复用性(二)规定圆形之后可能有更好的稳定不同类型的水管不不同类型水龙头的搭配方式。(三)便于我们委员会的监督,如果谁不遵守标准谁就拉出去斩了……”。

之后的很多年,他们都不管去开发新的接口,所以水管厂和水龙头厂最终最在了一起。

 

用伪代码描述是这样的:

 

interface socket(){
	final int yuan = "圆形";
	int Type();
}

class 智能水龙头 implement socket{
	int Type(){
	     return yuan;
	}
};

class 净水水龙头 implement socket{
	int Type(){
	     return yuan;
	}
};

class 水管 implement socket{
	int Type(){
	     return yuan;
	}
};

class 组装水龙头水管 {
	socket _水管;
	socket _水龙头;
	
	//先暂且不考虑水管和水龙头谁染都实现一个接头但不是一类东西的问题
	void set水管(socket){
		_水管 = socket;
	};
	void set水龙头(socket){
		_水龙头 = socket;
	};

	void 组装(){
		if(_水管.Type == _水龙头.Type){
			开始组装……
		}
	}
}

var 组装1 = new 组装水龙头水管();
组装1.set水管(new 智能水龙头());
组装1.set水管(new 水管());
组装1.组装();

var 组装2 = new 组装水龙头水管();
组装2.set水管(new 净水水龙头());
组装2.set水管(new 水管());
组装2.组装();

 

二、接口的出现有哪些好处?

 

嗯 如果不喜欢这种很二逼的解析方式的话,可以看看下面这一个比较官方的解析,同时会说出什么是接口以及他的好处。

------------------------------------------------------------------------------------------------

 

标准委员会                    =======>   接口 interface
不同种类的水龙头和水管的模具  =======>   实现接口的类
具体的水龙头和水管            =======>   类的对象

 

 

(1)提高代码的重用

在《设计模式》一书中提出的可复用的面向对象设计的第一条原则中就说到“针对接口而不是实现编程”,正如上述

所看到的没有标准委员会,将会出现什么情况? 各种各样重复的高相似的水管,或者各种各样相似的水龙头。这无疑增加了类的数量,并且有些类的相似程度还不少仅仅就是为了能够迎合水龙头的改变。如果针对接口去编程,那么无疑能够增加类的重用。

 

(2)解耦

考虑最复杂的情况,如果没有接口的话,每一种水龙头,对于水管内部这么一个类为了重用势必要添加ifelse语句进行对水龙头类型的检查,同时并调用他们的方法,这使得这一个水管类与其他水龙头类都有联系。如果有接口的话就好多了,水管与接口关联、任意种类的水龙头与接口关联,接口起到一个中间层,这样依赖性大大减少。

 

(3)稳定的通信方式

只要接口确定,并按标准实现,那么还担心类之间不能通信?

 

(4)便于测试和调试

只要发现有一个类没有实现接口的方法,或者传入的类型不是我想要的,那么标准委员会必然要行驶监督的权利。

 

(5)使得代码更稳固

更加稳固不如说可扩展性,比如我增加水管的类型,很简单其他的类不需要动,仅仅是只要能遵循接口就好,如果接口想扩展新方法,那么实现的类就必须去实现它。

 

 综上所述:接口就是一种契约,一种标准,他是方法或者常量的集合,这些方法的名字参数必须确定,实现它的类严格按照这种这个名字这些参数去实现,否则抛出异常。

 

 

 

三、Java语言是怎么实现接口的?

 这个实例时定义了一个磁盘接口,U盘、硬盘灯存储媒介都比如实现这种接口,也就是说,无论是哪种存储媒介都要保存到磁盘中去。

然后定义一个下载类,这里面可以根据不同媒介向磁盘写信息。

 

定义一个接口 磁盘
interface Disk(){
  void save(File file);  
};

u盘和硬盘都是磁盘,都实现这个接口

class UDisk implement Disk{
 void save(File file){} 
}


class HardDisk implement Disk{
 void save(File file){} 
}

一个需要用磁盘来存储的下载工具
class Download{
  Disk disk;
  用接口声明,我们不知道,也不用知道,我们未来会存到什么样的磁盘,
  我们不依赖于任何类型的磁盘,我们只依赖于这个接口


  void download(File file){
       disk.save(file);
  }
    
  void setDisk(Disk disk){
  this.disk=disk;
  }

  public static void main(String[] args){
  Download download = new Download();
  设置存储目标为U盘
  download.setDisk(new UDisk());
  文件被存到了U盘
  download.download(file);

  设置存储目标为硬盘
  download.setDisk(new HardDisk());
  文件被存到了硬盘
  download.download(file);

某天我们想把下载的文件保存到CD里边,我们只需要定义CDDisk类,
实现Disk接口就可以不对download本身做任何修改,
就可以方便的将文件下载到CD或其他介质里。
我们的Download类不依赖于任何具体的类,这样就解除了与任何具体存储设备的耦合!
  }

}

 

 

 

这个例子展现出对下来类的重用,同时下载类和其他的存储媒介仅仅是通过save进行关联,并且这种关联还是下载类关联到Disk接口,其他存储媒介关联到Disk接口实现的,所以解耦。并且一筹添加新的媒介形式仅仅定义新的媒介就好只要实现接口不需要更改下载类。

 

 

四、Javascript语言是怎么实现接口的?

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
/*
定义接口 
返回的对象格式为 {name,method}
有一个静态方法
 */
var Interface = (function (){
	var Interface = function(name,methods){
		if(typeof name !== 'string')
			throw typeError('Interface的name参数必须为string类型');
		if(!Array.isArray(methods))
			throw typeError('Interface的methods参数必须为Array类型');
		
		this.name = name;
		this.methods = methods;
	}
	Interface._implement = function(obj,inter){
		if(typeof obj !== 'object')
			throw typeError('Interface._implement的第一个参数必须为object类型');
		if(!Array.isArray(inter))
			throw typeError('Interface._implement的第二个参数必须为Array类型');
		for(var i = 0; i<inter.length; i++){
			var interItem = inter[i];
			if(interItem.constructor !== Interface)
				throw typeError(interItem+'不是一个Interface类型');
			for(var j = 0; j<interItem.methods.length; j++){
				var m = interItem.methods[j];
				if(!(m in obj)&&(typeof obj[m] !== 'function')){
					throw new Error('在对象 '+obj+' 中,没有实现接口 '+interItem.name+' 的 '+m+' 方法!');
				}
			}
		}

		return true;
	};
	return Interface;
})();

// 定义接口Disk
var Disk = new Interface("Disk",["save"]);

//定义U盘 硬盘类 

// UDisk implements Disk
function UDisk(){

};
UDisk.prototype.save = function(){
	console.log("u盘正在保存");
};

// HardDisk implements Disk
function HardDisk(){
	
}
HardDisk.prototype.save = function(){
	consloe.log("硬盘正在保存");
};


function CDDisk(){

}
CDDisk.prototype.save = function(){
	consloe.log("CD正在保存");
};

// 一个下载类 其中使用到各种媒介保存到磁盘中

function Download(){

	this.Disk ;
}

Download.prototype.download = function(){
	this.Disk.save();

};
Download.prototype.setDisk = function(disk){
	Interface._implements(disk,[Disk]);
	this.Disk = disk;

}


var d = new Download();
Download.setDisk(new UDisk());
Download.download();




</script>
</body>
</html>

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值