`
huntfor
  • 浏览: 195231 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

白话面向接口编程

 
阅读更多

引子:小时候布置作业的时候,我的老师一般会把布置的作业写在一张纸上,把纸交给课代表,再有课代表把作业告诉同学们,收作业的时候也是,老师一般会问课代表要作业,收作业的工作并不会亲自动手,干活的始终都是课代表。

 

所以,打我们上小学开始,我们就已经开始接触面向接口了,课代表就是老师与学生之间的接口。再抽象一点,比如小学班里只有一个老师,教语文,数学,英语三门课,有个小班长,是老师的助理,班长手下有三个课代表,分别对应于三门课,收作业的时候,老师只需要对班长说“收作业”(班长是接口,或者抽象类),班长会对三个课代表说“收作业”(多态,三个课代表是实现),这样就达到了目的,而不需要对每个课代表都说一遍“收XX作业”。当指令需要带动时,老师只需要对班长说“把每门的作业上面写上title”,班长继续相关指令“每门作业写上是哪门课的”,这样班里同学就会在语文作业本上写上“语文”两个大字,数学本上写上“数学”,以此类推。

 

看到这里大家应该对面向接口有一个初步的了解了,当一个工程的实现类比较多的时候,比如说课代表比较多,老师是不需要对每个课代表发布指令的,因为每个课代表的基本职能是类似的,只是实现不一样罢了,所以就可以抽象出一个接口(班长),让课代表各自实现班长的方法,这样以后老师下达指令(编程)就只需要面向班长就可以了。而不需要对每个课代表所谓面向接口编程。

 

下面看看官方版解释:

接口应该是定义实现分离。接口的本身反应了系统设计人员对系统的抽象理解。一般的,当我们在编写一个系统或者工具的时候,我们在意的是,这个工具能做什么,而不是它是怎么做的。即,我们不关注它是怎么实现的,按照这种思想来编程,即面向接口编程。

 

画外音:正如很多书中,接口名的定义一般都是readable,moveable等等,从名称上就可以看出接口是表示其实现类能(can do )做什么。普通类(包括抽象类)则表示其子类是(is a kind of)什么,Thinking in Java中的命名很有门道。

 

 再来看面向接口与面向对象编程的关系

首先我们要确定的是,面向接口属于面向对象的范畴,个人觉得,面向接口只是对面向对象又做了一层封装,将what to do 和how to do 做了分离,比如最简单的计算机主板给我们提供了各种各样的接口,拿USB接口来说,对计算机而言,需要一个输入设备,至于你插的是普通键盘还是机械键盘,它都不关心,计算机只面向了USE插口,只要是符合这个插口规范的设备,都一视同仁,并不需要对滚轮鼠标、光电鼠标、甚至各种牌子的鼠标分别处理。

 

再者,来看JAVA的跨平台性,JVM本身也是面向接口的,对上提供的JDK库是统一的,对各个操作系统的编译器是不同的,只要你编写的代码符合对上的接口,对于任何OS都一视同仁,并不需要码农对每种OS分别处理(这所谓一次编写,到处运行)这下大家看到面向对象的好处了吧。接口层,将规范(what to do)与实现(how to do)做了分离,再配合多态(接口的意义,希望大家还记得各科课代表的例子),可以轻易的提升软件灵活性以及可维护性。

 

下面我们举一个学习多态时候的小例子,来看一下什么叫面向接口:

 

既然是接口,首先定义一个接口:

 

package Gof;

public interface Runable {
	void walk();
	void run();
	void stop();
}
 

 

好了,接下来我们针对Runable编写几个实现类

 

package Gof;

public class InterfaceOriented {
	
	//参数设为接口,从而避免了为每个实现类定义一个相同的方法
	//这个方法还可以修改逻辑的顺序,比如stop->walk->run->walk->stop等等,只需一份就好
	private static void doEverything(Runable runable){
		System.out.println("now I am ready to run....");
		runable.run();
		System.out.println("I am tired and wanna walk for a while...");
		runable.walk();
		System.out.println("I am totally tired wanna stop....");
		runable.stop();
	}
	public static void main(String[] args) {
		
		Runable person = new Person();
		Runable cat = new Cat();
		Runable dog = new Dog();
		Runable fox = new Fox();
		doEverything(person);
	}
	
	
}


class Person implements Runable{
	@Override
	public void run(){
		System.out.println("people run....");
	}
	@Override
	public void walk(){
		System.out.println("people walk....");
	}
	@Override
	public void stop(){
		System.out.println("people stop....");
	}
}

class Cat implements Runable{
	@Override
	public void run(){
		System.out.println("cat run....");
	}
	@Override
	public void walk(){
		System.out.println("cat walk....");
	}
	@Override
	public void stop(){
		System.out.println("cat stop....");
	}
}

class Dog implements Runable{
	@Override
	public void run(){
		System.out.println("dog run....");
	}
	@Override
	public void walk(){
		System.out.println("dog walk....");
	}
	@Override
	public void stop(){
		System.out.println("dog stop....");
	}
}

class Fox implements Runable{
	@Override
	public void run(){
		System.out.println("fox run....");
	}	@Override
	public void walk(){
		System.out.println("fox walk....");
	}	
	@Override
	public void stop(){
		System.out.println("fox stop....");
	}
}
 

 

如果突然来了一只狼wolf,那么只需要将wolf作为参数传进去即可,这里我们定义的doEverything方法是面向Runable接口的,只要符合这个标准(实现类)都可以直接插入作为参数。是不是很像只要符合鼠标规范的,就可以直接插入USB接口?

 

 

当然面向接口编程中指的接口并非狭义的接口,而是更高层的抽象,就拿本例来说,还可以做更高一层的抽象,比如下篇博文要介绍的工厂模式。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics