契约
魔兽争霸3中死亡骑士(Death Knight)出生时就会说一句:
The pact is sealed.
契约已签订。
看过N多童话故事和电影的小伙伴们肯定熟悉这种场景:
大反派斗不过主角,处于劣势时,就会与诸如恶魔签订契约,以自己的青春换取强大的力量,即:
青春 --> 恶魔 恶魔 --> 力量
我们把这个再改变一下:
恶魔 【得到】{青春} -> {力量}
看起来有点眼熟,这不就是function/method干的事情吗?
function 与恶魔签订契约(青春) {
return 力量;
}
拿一个PHP简单的函数来说吧,此函数是这样的:
function getFullName($givenName, $surname) { return $givenName.' '.$surname; }
对于调用方来说,如此调用:$fullName = getFullName($realGivenName, $realSurname);
输入 $realGivenName 和 $realSurname 不知道是否返回结果,有结果也不知道是什么。
这里 $givenName和 $surname 两个形参对比之下就是契约条件,而返回的值就是契约回馈。
每天在敲代码,原来就是在写各种各样的契约,然后各个契约被各种各样的大反派(调用方)签订(调用)。
再来看Java的一个方法
public static String getFullName(String givenName, String surname) { return givenName + " " + surname; }
给一个String类型 和 一个String参数,返回一个String 类型的结果;
去跟PHP对比一下,发现Java的Method契约条件的限制更加严格了,而契约回馈的描述也更加准确了。
即PHP函数在调用时,函数形参如果不限制类型的话,可以是任意类型($givenName 可以是一个int,也可以是array,甚至是一个resource类型,或者干脆是null),
基于动态语言的特点,甚至还可以传多于/少于(少于的话PHP会报Warning级别的错误)function规定的参数数目进去!
所以在上面这种实现在遇到特殊情况下,就会出现意想不到的结果,因此具体实现要对变量类型、值做各种判断;
而Java在实现内则不需要做类型判断,只需要处理空的情况即可;
对于return 的结果来说,PHP function实现可以返回 null、int,array,resource... 又是不限制类型和值!契约回馈又是模糊的描述……
所以,PHP function/method 契约是模糊的,契约回馈的描述也是模糊,而Java则更加强调契约发起方和契约执行方的明确的责任;
如此这般,PHP 一个function/method 实现(契约执行方)就头大了,调用方(契约发起方)传过来的参数(契约条件)很有可能存在
意想不到的情况,于是就需要在实现内加类型判断, 处理空或者其他情况。调用方也不知道实现是否真的能达成契约描述(function/method名称,注释等)
那样的美好的结果,调用方又得对实现返回进行判断。
而Java则只是对象参数需要处理null的情况,因为有一步编译的过程,类型则不需要费心。即在通过编译后,契约双方的基本条件和回馈描述被保证了。
PS:这么一说,编译器(Compiler)听起来就像是一个公证人似的。
总的来说,PHP因为不必在声明变量或者制定方法签名时声明类型,所以是弱契约。
弱契约的好处是显而易见的:
调用方的责任限制变少,执行方(实现)的责任 加重(即兼容 各种参数情况),那么只需要一个契约执行方,就可以满足多种调用方的情况。
即一个function/method实现,调用方多种情况来调用都是没问题的;
我们也可以把这种实现成为健壮的实现;
Java则是强契约,好处不必多说,但是劣势对比弱契约也是很明显,调用方参数若是出现了另外一种类型或者参数变多/变少,则不得不重载(Overload),
如果业务复杂起来,重载方法写起来简直是恶心;
说道这里泛型横空出世,我们可以理解泛型其实就是在强契约和弱契约之间的一种折中,即Method契约不再死板地限制某个具体类型,也不死板地规定
返回某个具体类型,而是规定为某一系列的类型,即在强契约的上弱化了一些,将类型限制放宽。
使用了泛型的方法,则可以满足调用方的某一系列的参数类型情况,让我们少些重载方法,减少了代码量 :)
return ;