• 欢迎访问废江网站,承蒙遇见 QQ群
  • 本站将致力于推送优质的java知识以及算法,开源代码!

java组合接口 抽象出功能

架构思维 站点默认 2年前 (2021-12-07) 41748次浏览 已收录 1个评论 扫描二维码
文章目录[隐藏]

背景

今天,在写一个多线程的时候,犹豫了一下。为什么多线程可以其一是继承Thread类,然后重写run方法,表示是一个线程,然后Main中实例化出对象,调用start方法启动,其一就是实现Runnable接口,然后声明Thread的时候传入实现了Runnable接口的对象,也是构造出了一个线程。这两种方法有什么区别吗?脑海中回忆了之前看的java成神之路中的继承和组合的概念,遂灵光闪现,记下这篇文章。

例子

这个例子,主要在这篇博客上:https://www.cnblogs.com/vincent-blog/p/4389871.html我这里就不重复写代码了。

说的是有两个类,昆虫类和蜜蜂类。昆虫类中有两个方法,移动和攻击,并且在攻击的时候需要移动一次,于是,父类昆虫类中是这样写的:

那么,如果蜜蜂继承昆虫类(事实也正是如此),问题就来了。蜜蜂再调用attack方法的时候,不仅仅自己的move了一次,父类昆虫也move了一次。但要知道,移动是不一样的,蜜蜂是fly,而其他一些昆虫就是走或者爬。这样肯定是不行的。

分析

首先,思考一下如何解决,不看那篇博客的话。蜜蜂继承昆虫这个不能改,这点毋庸置疑。那么继承了昆虫就有了昆虫的移动和攻击,移动方法没有问题。蜜蜂可以重写改方法,但是攻击呢?有人会说,昆虫父类中,别把移动丢进攻击里面。这样蜜蜂重写了移动,重写了攻击不就ok了? 但我想说,这样是不对的,攻击的功能就被你改掉了,攻击之前是有移动的,这是一个需求,或者说一组功能。那怎么办?

解决办法

将这个attack抽象出来!看下面的代码:

蜜蜂在构造函数中传入了实现了attack接口的实现类,蜜蜂类中这样写:

这样,将这个attack攻击和父类昆虫组合起来了,而不是单一的继承昆虫。

拓展

上面这个例子,在声明蜜蜂传入attack实现类,不正是我们声明多线程的第二种方式吗。所谓多线程,即多线程对象+多线程要做的事情。java中则是将多线程要做的事情(其实就是上面的attack功能)抽象出来,用一个接口来定义规则,然后通过实现类再次传回多线程对象。这样做的好处是什么?可以将其这个多线程要做的事情看作是一个资源,然后很多多线程都去解决这一个资源(即要做的事情)。典型的生产者和消费者就是这样。生产和消费者都要对同一个资源进行操作,即资源仓库。这时,你是生产者的多线程还是消费者的多线程,传入的都是这个资源仓库实现类。

题外

上面这些其实就是java通过组合+接口的方式实现了多继承。为什么说是多继承?你可以把上面的attack想象成为一个类,不就是bee蜜蜂类继承了昆虫和attack吗。事实上了,在c++中确实就是这样。java中不能实现多继承很简单,如果类B,C继承了A,当D继承了B,C的时候,在当D调用方法时就会混乱。至于java为什么不引入多继承?因为不太需要:在实际的应用中人们发现继承更多的只被用在两种场合扩充/改善基类,以及实现多态。对于前者,单继承足以;而对于后者,则真正需要的其实是纯抽象类,即只包含纯虚函数的基类。而对于这一种基类,由于其目的和普通的实例类已经有所不同,因此在java中将其改称为interface,即接口加以明确区分。

 


废江博客 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:java组合接口 抽象出功能
喜欢 (1)
[]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽
  1. 博主讲得好啊接口起到了约束和抽象出功能的作用约束,例如java中collection接口继承iterable接口,使得集合都具有迭代器遍历的功能抽象出功能,例如线程中,要实现一个线程需要继承thread,然后写其中的run方法,这时可以把run方法抽象出来,用一个接口Runnable接口定义run方法,当Thread继承了这个接口,这时我们可以在构造方法中传入runnable的实现类,使得run方法可以从中抽象出来。
    2022-01-15 14:27 回复