(1)
Dog d = new Dog()
d.bark();(2)
Animal animal = new Dog();
animal.makeSound();(3)
a = getAnimal();
a.makeSound();
(3)为什么最好啊?
Dog d = new Dog()
d.bark();(2)
Animal animal = new Dog();
animal.makeSound();(3)
a = getAnimal();
a.makeSound();
(3)为什么最好啊?
没有继承,没有多态的效果,没有任何扩展性。行为的结果一目了然,在编译阶段就已经明了,根本不需要上下文。(2) Animal animal = new Dog();
animal.makeSound();
用到了继承,用到了多态,animal.makeSound();这个行为的结果需要运行时才能确定下来,问题是第一行的代码其实已经透露了结果,换个表达方式就是,扩展性不够。如果需要扩展功能,需要修改的代码量太,修改的地方也多。(3)
a = getAnimal();
a.makeSound();
行为的结果在当前,无法预知,只有运行才能得到结果,而且可能每次运行条件不同,得到的结果也不同。因此给扩展增加了很多可能性。对于需要扩展功能时,可能不需要修改原来代码,只要增添新代码就可以运行得很好。
举例:
你有一个网络协议库,里面目前支持 TCP,IP,FTP...等150+种,而且源代码不可见。接口你知道,有一天你很牛,写了个HTML5,想集成进去,那么你需要做的事情就是 实现这个协议,并实现特定的接口,最后注册到协议库中就行了。
伪代码:
#define HTML5 .... //定义了HTML5对应的协议代码值(应该是个整数或者是个字符串,我猜,可以参考ethereal源代码对各个协议的定义,看太久忘记了)
class html5parse{} //实现html5的协议,并实现协议的接口,假设为html5parse,然后你需要做的就是:
Regesit(HTML5,html5parse);
//在ethereal中,接口是一个函数句柄,那么html5parse理解为一个static函数
然后当有html5的报文进来后,你的代码就会被自动调起来,进行解析了。
你根本不需要修改原来的代码,而原来的代码就可以调用你后来才实现的东西了。
这就是面向接口编程的美妙的地方。
当然这是个人体会,表达肯定不如书本描述的,纯粹个人体会,反正我就是这么用的。
定义一个接口 磁盘
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); 看到没?当我们定义download这个类的时候,我们也不知道我们会存到那个地方去,我们用接口来定义,当我们想改变存储目标时,我们只需要指定一个具体的实例对象就可以了,而不需要对download类本身做任何修改。
}}