简介
最近学习Java基础的时候被面向接口编程的思想迷住了,自己研究了好一会才搞明白,面向接口太伟大了,我将用我写的第一篇文章记录下这个思想的过程。接下来将通过一个通俗的例子阐述面向接口编程的便利性,虽然实际开发中不太了解,但起码思想是一样的。在阅读本文时大家应有接口实现的基础了,我就不加赘述。
第一阶段
假设有帅哥小明,有一天她苦苦追求的女生说会踢足球和打篮球的男生会好加分。于是小明花重金请来了一个会打篮球和踢足球的金牌教练,代码如下。
篮球类:
public class Basketball {
public void play(){
System.out.println("教练教我打篮球");
}
}
足球类:
public class Football {
public void play(){
System.out.println("教练教我踢足球");
}
请来的金牌教练:
public class Coach {
public void teach(Football f){
f.play();
}
public void teach(Basketball b){
b.play();
}
}
这时候小明只需在Main类中调用这个教练即可,无脑操纵:
public class Main {
public static void main(String[] args) {
Coach c=new Coach();
Basketball b = new Basketball();
Football f = new Football();
c.teach(f);
c.teach(b);
}
}
可是后来小明追求的女生说,会打羽毛球,打排球,打棒球的男生都好加分,但请来的教练只会篮球和足球,还好小明找的是金牌教练,马上就能学会其他球类,教练需要马上学习羽毛球、排球、棒球才能教小明。
这时球类一多,如果再继续在Coach类中新增teach方法的重写,然后每次都要在Main中new不同的球类对象,会显的十分冗杂......,这种代码一写出来就会被枪毙
这里很容易想到做一个抽象类,将所有的球抽象起来,满足is-a关系的求全部继承这个抽象类Ball
public abstract class Ball {
public abstract void play();
}
public class Basketball extends Ball {
public void play(){
System.out.println("教练教我打篮球");
}
}
public class Football extends Ball {
public void play(){
System.out.println("教练教我踢足球");
}
}
public class Badminton extends Ball{
public void play(){
System.out.println("教练教我打羽毛球");
}
}
//................................以此类推
此时教练类就不需要重载一个个teach方法,只需将抽象类作为方法的参数传入,利用向上转型与动态绑定的思想,即可实现方法的准确调用。
更新后的教练类:
public class Coach {
public void teach(Ball ball){
ball.play();
}
}
此时小明的调用:
public class Main {
public static void main(String[] args) {
Coach c=new Coach();
c.teach(new Football());
c.teach(new Basketball());
}
}
想学什么就new什么给教练的teach方法,教练就马上教你,很方便有木有~
第一阶段到此结束,以上的方法用的还挺不错,真方便啊,到此其实是面向对象的编程思想,可是慢慢的问题又出现了......
第二阶段
由于金牌教练,小明现在可谓是球类的大神了,可是他追求的女生又说,会弹吉他的男生好帅啊,他希望他的男朋友会弹吉他,小明愣住了。
小明苦恼了,他想,自己的教练是球类教练啊,怎么教他弹吉他......于是他与教练商量。
自有转机,谁叫小明请的是金牌教练,教练说他什么都能学,他有办法!!!
现在球类与乐器类不是同一个类,如果像上面那样用抽象类就会显得乱套了,此时走到更高一层的抽象——接口,干脆将球类与乐器类用一个接口Skill(才艺)抽象出来
public interface Skill {
void play();
}
将所有的乐器、球类去实现这个接口
public abstract class Ball implements Skill {
public abstract void play();
}
public class Basketball extends Ball {
public void play(){
System.out.println("教练教我打篮球");
}
}
//球类省略...........
public class Guitar implements Skill{
public void play(){
System.out.println("教练教我学吉他");
}
}
教练的方法参数也变成了接口类型
public class Coach {
public void teach(Skill s){
s.play();
}
}
此时小明就完完全全可以信任金牌教练了,他想学什么,只需要教练学会马上就可以教他,点读机教练,哪里不会new哪里
public class Main {
public static void main(String[] args) {
Coach c=new Coach();
c.teach(new Football());
c.teach(new Basketball());
c.teach(new Guitar());
}
}
教练经过与小明的长久交往,他也知道了小明会有一些三分钟热度的爱好,比如学编程(programming),于是教练觉得为此专门开一个类很不划算,因为小明只会学一次(类只用一次),甚至不需要给这个东西专门起名字,因此教练用了匿名内部类。
public class Main {
public static void main(String[] args) {
//花重金买来金牌教练
Coach c=new Coach();
//通过new对象向金牌教练学习
c.teach(new Football());
c.teach(new Basketball());
c.teach(new Guitar());
//对三分钟热度的技能用匿名内部类
c.teach(new Skill(){
@Override
public void play() {
System.out.println("教练教我学编程");
}
});
}
}
正是由于金牌教练的存在,他追求的女生被小明的才华深深吸引了,牵手成功。
小明的死党二狗听说了之后,心里也想快点找个女朋友,希望也有一门才艺,然后就找了个拳击教练(BoxingCoach类)教他拳击。
public interface Boxing {
public void boxing();
}
public class BoxingCoach implements Boxing {
@Override
public void boxing() {
System.out.println("专业拳击教练教拳击!");
}
}
public class Train {
public void training(Boxing b){
b.boxing();
}
public static void main(String[] args) {
Train train = new Train();//进行一次训练
BoxingCoach boxingCoach = new BoxingCoach();//请拳击教练
train.training(boxingCoach);//由专业教练教拳击
}
}
后来二狗由于暴脾气与拳击教练闹翻了,于是拳击教练不干了,走人。
二狗来找小明借他的金牌教练,小明一看二狗是面向接口编程就爽快的答应了,他让自己的金牌教练去学拳击(实现Boxing 接口)
public class Coach implements Boxing {
public void teach(Skill s){
s.play();
}
public void boxing(){
System.out.println("小明的金牌教练教拳击");
}
}
随后就可以在训练中使用金牌教练教拳击
public class Train {
public void training(Boxing b){
b.boxing();
}
public static void main(String[] args) {
Train train = new Train();//进行一次训练
// BoxingCoach boxingCoach = new BoxingCoach();//请拳击教练
// train.training(boxingCoach);//由专业教练教拳击
Coach coach = new Coach();//请来小明的金牌教练
train.training(coach);//由金牌教练教拳击
}
}
编者心得:
在编程时,接口没有is-a关系的限制,只要你觉得你的类需要这个功能,就去实现这个接口,就像金牌教练要学拳击就要去实现拳击接口,面向接口编程应用广泛,比抽象类用的更多,个人觉得精华在于方法参数的接口化。
灵感来源:CodeSheep