php的interface == 鸡肋?

话说当年,php5诞生的时候,向java,c++学了好多面向对象的语法元素。其中就有interface。在java圈子里,主流的观念是要面向接口编程而不是面向类编程,将接口与实现分离。记得在Spring in Action的例子里,要创建一个骑士对象,首先写一个Knight接口,里面定义了骑士可以做什么。具体怎么做则是在类KnightImpl里实现的。看上去似乎有一点麻烦。不过java大牛们教育我们,这是为了更好的灵活性。这样使用骑士的时候不用关心这是个什么样的骑士,而且可以在不修改代码,只修改工厂的配置文件,就可以用另一个实现来替换现有的实现。更寻常的说法是,比如Map接口,通常我们使用一个映射表的时候只要能够满足键值对应的操作就行。我们可以根据具体需要选用哈希表实现或是查找树实现,甚至自己定义一个存放在数据库中的Map。简单的说,接口定义了一组操作,实现了某个接口的对象也就能提供这个接口规定的一组操作。接口就像是一个协议或者说一个标准。这么说来,interface应该是一个好东西,似乎是面向接口编程所必不可少的,interface不就是接口的英文词么。那这篇文章的题目又是怎么回事呢?

还是拿例子说话。
interface Computer{
    function add($a, $b);
    function minus($a, $b);
….
}

class Mainframe implements Computer{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

class Calculator implements Computer{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

不管是大型机还是小计算器,都可以算加减法。想要算加法的时候只要拿一个实现了Computer接口的东西就行。比如
function doAdd(Computer $c, $a, $b){
    return $c->add($a, $b);
}
看起来不错。不过能算加减法的不仅仅是那些用电的东西。我国古代劳动人民的智慧结晶——算盘也能算加法。那么如果要拿算盘算加法,就要有一个算盘类。那这个算盘类该不该实现Computer接口呢?这个算盘似乎也算不上是一个计算机啊。或许该另外建立一个Calculatable的接口,让计算机和算盘都去实现这个接口,这样似乎就不错了。有时候我们只需要用到Calculatable的一部分功能。比如Calculatable定义了基本的加减乘除,但我们买菜算账的时候通常只需要加法。这时候如果用Calculatable的话就需要接受一些无用的东西。再用一个php的SPL里的例子。SPL里有一个ArrayAccess接口,可以让对象像数组一样用下标去访问。这是一个很有意思的语法糖。不过有时候只需要按下标读功能就可以了,但是为了要满足规定,还是要把ArrayAccess接口的所有方法都实现一遍,于是就要写好几个throw new Exception(‘xxx is not writable’);之类的东西。这实在有点罗嗦。

为什么不换一个写法呢?扔掉那些interface,直接写
class Mainframe{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

class Calculator{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}

class Abacus{
    function add($a, $b){
        //…
    }

    function minus($a, $b){
        //…
    }
}
在需要计算的时候,也不用限定一定要是Computer,把对象直接扔过去。
function doAdd($c, $a, $b){
    return $c->add($a, $b);
}

如果在试图在一个不能算加法的东西比如易拉罐上执行add,解释器自然会报错。也就是说,只有满足接口的对象才能够正常运行。你看,不用interface一样可以实现面向接口编程,而且更加灵活。

不用interface搞面向接口编程这听起来还是有点玄乎。毕竟这个interface就是接口的英文单词啊。好吧,interface确实是英文单词,但并不代表interface这个语法元素就等价于接口。就好像把狗的尾巴也叫做腿,这狗也不是就有了五条腿。interface只是叫了这个名字而已。当然,interface在一定程度上也为面向接口编程提供了方便,比如提供了编译期的检查。而且对于强类型语言来说,这样的语法元素是很重要的,比如java。而对于弱类型语言,比如php,却不是必须的。而对于一些更动态的语言,比如python,ruby来说,更是很难相容的。

 

12 thoughts on “php的interface == 鸡肋?

  1. YERNSUN

    这么说来你也不必用面向对象了!
    博主用个简单的运算就说interface是鸡肋,看看你的参数,要我想算三个数的平方和楼主的参数岂不是要十几个。
    也不想想面向对向是用来干嘛的,一个小工项目也没必要大量使用面向对象…
    以为自己能干点什么就牛叉了,有和自己去写个引擎…

    Reply
  2. wps2000

    凡是超类型都算是接口吧~~~
    面向接口编程现在我把它理解成面向超类型编程了。应该说,在设计框架的时候interface才会发挥一点做作用吧,貌似像我这种打字员是无法体会的真正的精髓的。type hints 我倒认为是一个好东西,自己的函数,方法之类的,只要能使用,我一定使用。type hints在一定程度上可以减轻调试的负担

    Reply
  3. giky

    接口还是很有用嘀,很多设计模式都是靠接口实现。至于说接口多余,那就是接口设计的不对了。需要二口的插座你偏要设计个三口的,那当然会有多余。

    Reply
  4. cid73

    所以说还是 SOA 最能解决问题. 我们不要用框架, 利用 Web server 来传送, 一切协作都使用 XML, 通过公用(或事先协定)的 DTD/Schema 来校验. 硬件成本会增加, 但是开发成本会大大下降. 对程序员的要求也将大大下降, 我才不理你怎么写, 只要你传过来的 XML 可以通过校验就没问题, 呵呵.

    Reply
  5. cid73

    Java 的函数可以重载, 接口就是协作中的契约. PHP 不支持函数重载, 但是接口还是可以限制传入参数的数量和类型的(虽然不那么地道), 在协作中还是有一定作用的. 不过我倒希望 PHP 快点加入强类型支持, 类型安全总是一个话题.

    Reply
  6. D.c.

    脚本语言本来就没必要搞那么复杂的东西
    历史上似乎PHP每次想引入些新功能最后都被证明是好心办坏事
    PHP5开始已经不伦不类了,所以就放弃了…
    话说看Spring in Action不是看接口,而是看IoC和AOP阿..

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.