用《英雄联盟》解释一下面向对象中接口的作用

在面向对象编程的思想中,接口是一个非常重要的概念。按书上介绍的,使用接口,可以实现运行时多态、易维护、易拓展等等优点。拥有多年编程经验的人应该能理解这些话的含义,对于一个初学编程的萌新来说,看完这段话完全不知所云。那今天我用《英雄联盟》为背景,详细的分析一下接口在面向对象编程中的作用,以及使用接口的优势。
这次使用java作为编写demo的语言,主要原因有两个:

  1. java是最流行的编程语言,基本上学过编程的都会java语言;
  2. java是一门对面向对象特性支持比较好的语言;

还记得我刚开始学习java的时候,就很不理解接口的作用,感觉接口有点多余。

例如我定义了一个接口,但是我在实现这个接口的类中还要写接口的实现方法,那我不如直接就在这个类中写实现方法岂不是更便捷,还省去了定义接口

相信不止我一个人有过这样的疑惑吧。
后来随着写代码,看阅读别人的代码,逐渐开始理解接口的作用了,慢慢觉得接口是一个非常方便和牛逼的东西。
教材上,网上解释接口的例子大多数使用定义一个Animal接口,然后Dog实现了这个接口,Cat实现了这个接口;还有一种用USB接口举例。大多数人看完还是一脸懵逼。
现在用一种新的方式——《英雄联盟》为背景介绍一下。
说了这么半天,开始进入正题吧。

先圈两个重点:
  1. Java之所以要有接口,是因为java不支持多继承,使用接口,可以间接的实现多继承的一些特性;像C++就不存在接口这个东西,因为C++支持多继承
  2. 在面向对象的概念中,子类(派生类)可以自动转换为父类(基类)类型;也就是说,A类实现了接口B,那么A的实例化对象可以自动转换为B类型
public class Main {
    public static void main(String[] args) {
        B a = new A();
    }
}

interface B {

}

class A implements B {

}

这样的代码是正确的。


开始demo部分,我们定义一个Skill接口,里面有 QWER 四个方法,代表英雄的四个技能。为了简单,被动技能和召唤师技能就不写了。
然后从五个位置上单、打野、中单、ADC、辅助中各挑选一个英雄,作为例子。上路中我最喜欢的是锐雯,打野我玩的最多,纠结了半天选了盲僧。中单里必须选亚索,ADC里选择了暴走萝莉,辅助里选择了锤石。

先上代码再解释:

//技能接口
interface Skill {
    void Q();

    void W();

    void E();

    void R();
}

//放逐之刃-锐雯
class RuiWen implements Skill {

    public RuiWen() {
        System.out.println("断剑重铸之日,骑士归来之时");
    }

    @Override
    public void Q() {
        System.out.println("折翼之舞");
    }

    @Override
    public void W() {
        System.out.println("震魂怒吼");
    }

    @Override
    public void E() {
        System.out.println("勇往直前");
    }

    @Override
    public void R() {
        System.out.println("放逐之锋");
    }
}

//盲僧-李青
class LiQing implements Skill {

    public LiQing() {
        System.out.println("我用双手成就你的梦想");
    }

    @Override
    public void Q() {
        System.out.println("天音波/回音击");
    }

    @Override
    public void W() {
        System.out.println("金钟罩/铁布衫");
    }

    @Override
    public void E() {
        System.out.println("天雷破/摧筋断骨");
    }

    @Override
    public void R() {
        System.out.println("猛龙摆尾");
    }
}

//疾风剑豪-亚索
class YaSuo implements Skill {

    public YaSuo() {
        System.out.println("死亡如风,常伴吾生");
    }

    @Override
    public void Q() {
        System.out.println("斩钢闪");
    }

    @Override
    public void W() {
        System.out.println("风之障壁");
    }

    @Override
    public void E() {
        System.out.println("踏前斩");
    }

    @Override
    public void R() {
        System.out.println("狂风绝息斩");
    }
}

//暴走萝莉-金克斯
class JinKeSi implements Skill {

    public JinKeSi() {
        System.out.println("规则就是用来打破的");
    }

    @Override
    public void Q() {
        System.out.println("枪炮交响曲!");
    }

    @Override
    public void W() {
        System.out.println("震荡电磁波!");
    }

    @Override
    public void E() {
        System.out.println("嚼火者手雷!");
    }

    @Override
    public void R() {
        System.out.println("超究极死神飞弹!");
    }
}

//魂锁典狱长-锤石
class ChuiShi implements Skill {

    public ChiShi() {
        System.out.println("我们要怎样进行这令人愉悦的折磨呢");
    }

    @Override
    public void Q() {
        System.out.println("死亡判决");
    }

    @Override
    public void W() {
        System.out.println("魂引之灯");
    }

    @Override
    public void E() {
        System.out.println("厄运钟摆");
    }

    @Override
    public void R() {
        System.out.println("幽冥监牢");
    }
}

代码有点多,但是很简单,写了5类,对应5个英雄。每个类的构造方法中,打印了这个英雄在排位中被选中时的台词。每个类都实现了skill这个接口,并重写了QWER这4个方法,在方法中打印了这个英雄技能的名称。
在main方法中初始化这5个英雄,并调用每个英雄的QWER这四个技能,代码:

public class Main {
    public static void main(String[] args) {
        //初始化锐雯释,放技能
        Skill ruiWen = new RuiWen();
        ruiWen.Q();
        ruiWen.W();
        ruiWen.E();
        ruiWen.R();

        //初始化李青,释放技能
        Skill liQing = new LiQing();
        liQing.Q();
        liQing.W();
        liQing.E();
        liQing.R();

        //初始化亚索,释放技能
        Skill yaSuo = new YaSuo();
        yaSuo.Q();
        yaSuo.W();
        yaSuo.E();
        yaSuo.R();

        //初始化金克斯,释放技能
        Skill jinKeSi = new JinKeSi();
        jinKeSi.Q();
        jinKeSi.W();
        jinKeSi.E();
        jinKeSi.R();

        //初始化锤石,释放技能
        Skill chuiShi = new ChuiShi();
        chuiShi.Q();
        chuiShi.W();
        chuiShi.E();
        chuiShi.R();
    }
}
注意一点:

我们在实例化这5个英雄时,这5个英雄都是Skill类型的
看一下运行结果:


可以看到,这5个英雄依次被实例化,并释放了QWER这4个技能。


可能到这有的同学没看懂,这和接口有什么关系?接口带来了哪些好处?

简单分析一下:
  1. 接口这个概念,其实就是定义了一种规范。在 Skill 这个接口中,定义了Q、W、E、R这四个方法,只要是实现了这个接口的类,一定会有这四个方法。
  2. 接口可以看做是实现多继承的一种方式(这样说可能不严谨)。java中没有多继承这种机制,失去了一些灵活性。但是去掉多继承后,语法简单了很多,像C++中,因为有多继承,又引入了虚继承的概念。说多了,回到正题。一个类实现一个接口后,可以看做是这个接口的子类,所以,我们在实例化英雄时(new Ruiwen()等),可以直接实例化为 Skill 类型的。

结合这两点,所以我们每一个Skill类型的对象,都可以调用 Q、W、E、R 这四个方法。
有人会提出疑问,我在每个类中都定义 Q、W、E、R 这四个方法不就行了。但是如何保证每个类里都有这四个方法呢?通过接口约束,可以保证,所有实现这个接口的类中,一定有这四个方法。

再通过下面这个用法,看一下接口怎样实现多态的:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Skill hero;
        Scanner scanner = new Scanner(System.in);
        switch (scanner.nextInt()) {
            case 1:
                hero = new RuiWen();
                break;
            case 2:
                hero = new LiQing();
                break;
            case 3:
                hero = new YaSuo();
                break;
            case 4:
                hero = new JinKeSi();
                break;
            case 5:
                hero = new ChuiShi();
                break;
            default:
                hero = new RuiWen();
        }

        hero.Q();
        hero.W();
        hero.E();
        hero.R();
    }
}

简单看一下代码,定义了一个Skill类型的变量hreo。通过输入不同的值,来判断实例化哪一个英雄。最后调用英雄的 Q、W、E、R 方法。
先输入 1 看一下,输入 1 应该是实例化锐雯这个英雄


没有问题,输入1成功实例化了锐雯这个英雄,并调用了锐雯的四个技能。
再换一个输入值看一下:

这次输入了 2 ,实例化了李青这个英雄,并调用了李青的四个技能。

简单说一下使用了接口后的优势:
  1. 使用接口后,实现了运行时多态,也就是 hero 具体是哪个类的对象,在编译阶段我们是不知道的,只有当程序运行时,通过我们输入的值才能确定 hero 是哪个类的对象。
  2. 使用了接口后,所有实现了 Skill 接口的类,都可以实例化为 Skill 类型的对象。如果不是这样,那有多少个英雄(类)就要定义多少个变量。现在英雄联盟有145个英雄,那就要定义145个变量,这。。。。

总结:

  1. 接口的作用是定义了定义了一些规范(也就是定义了一些方法),所有实现了这个接口的类,必须要遵守这些规范(类中一定有这些方法)
  2. 一个类实现了一个接口, 可以看做 是这个接口的子类,注意是可以看做。子类类型可以自动转换为父类类型,所以任何出现接口的地方,都可以使用实现这个接口的类的对象代替。最常见的就是方法中传参,定义一个接口类型的变量,传入一个实现了接口的对象。

最后:文章是下班后半夜写的,加上自身能力有限,文中如有不正确的地方,欢迎评论区探讨,共同提高。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,946评论 6 13
  • 1 面向对象No6 面向对象 OO Object Oriented 编程时以对象为单元,封装数据和逻辑,以此提...
    征程_Journey阅读 1,137评论 0 2
  • java继承 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。 继承就是子类继...
    863cda997e42阅读 665评论 0 1
  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 1,537评论 0 6
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32