今天是我自学Java的第39天。
感谢你的观看,谢谢你。
话不多说,开始今天的学习:
用过安卓手机的同学应该都知道:
打开文件管理,可以查看到文件分类:
所有图片都在图片栏里;所有视频都在视频栏里;所有音乐都在音乐栏里……等等。
那这种需求在Java代码里面要如何做到?
就需要使用到过滤器了。
一、过滤器
什么叫过滤器?
就是根据特定的要求,找出对应条件的文件。
比如说,过滤出图片文件:
①创建一个file对象
路径填写我们现在作为例子的文件夹“F:/test"。
②定义一个find方法
该方法的作用为:查找文件夹中的图片文件。
③file如果是文件
根据后缀名是否为“jpg”来判断图片文件,并输出该文件。
④file如果是文件夹
因为我们要查询的是图片文件,那么要先遍历。
使用file的listFilts方法,再使用增强for循环遍历。
子文件里面可能同时又有文件夹和文件,故递归
⑤递归调用自己
find方法本身就是查找文件夹里的图片文件的,那么直接调用自己就好了。
OK,代码写完,运行下来发现控制台打印的都是文件夹中的图片文件,需求解决。
但是现在问题来了,这种代码写下来水平就很差,因为代码的可拓展性太差了。
什么叫可拓展性?
拓展性越强,需求改变时,需要修改的代码越少。
就拿上述例子来说:是,确实解决了查找图片的需求,但是如果现在要查找音乐文件呢?该怎么办?如果要查找视频文件呢?
得将代码复制粘贴,然后将“jpg”一个个修改,这样的话代码就太冗余了。
如何解决扩展性问题?
二、过滤器优化
①定义一个查找方法
设置两个参数:文件对象,后缀名;根据后缀名查找对应的文件。
②如果是文件
根据isFile()方法,判断是否是文件,若是文件再进行判断,同时结束递归。
③判断文件是否满足要求。
根据提供的后缀名,来判断是否满足的要求。
④如果是文件夹
先遍历,再递归。
OK,需求解决了,现在想查找某种类型的文件,直接在调用方法时设定参数就好了。
那么问题又来了:
如果有用户要查询前缀名为a的图片,该怎么办?
如果有用户要查询包含“cad”的图片,又该怎么办?
如果有用户要查询大小小于1M的图片,又该怎么办?
因为用户的需求是各种各样的,程序员得去满足这些要求。
我觉得写代码有一个最大的魅力:实现需求时要考虑的非常全面,这样在遇到问题的时候,能很好地去应对。
就像网上流传的一句话:只有将用户想象成最傻最傻的人,考虑到各种各样的问题,才能写出好的代码。
三、过滤器再次优化
如何进一步优化?仔细看第二节中的代码:
③是问题的核心所在,因为③将代码给写死了,endsWith方法只能用来判断后缀名。
那怎么解决这个问题?
接口,Java的精髓就在于接口。
具体什么意思?
现在要查找对应的文件对吧,我不写具体的查找条件了,我就制定一个接口,谁要用接口,重写方法就好了:
要根据后缀名查找文件?行,重写方法就好了。
要根据前缀名查找文件?行,重写方法就好了。
用户有任何要求,只需要重写接口里的方法,写出对应的需求就好了。
高级程序员和低级程序员差别在哪?
高级程序员写出的代码,能解决某类问题,他在写接口,在制定规则。
低级程序员写出的代码,只能解决某个问题,他在实现接口,写出用户具体的要求。
所以接口是每一个Java程序员应该认真研究的:如何使用接口,如何写接口。
回到过滤器,如何写接口?
①定义过滤器接口MyFilter
要过滤文件?实现这个接口就好了。
接口里定义一个抽象方法,我给你一个file,具体是什么过滤条件我不清楚,你重写我的方法时写清楚,并将结果告诉我就好了。
②定义一个查找方法find,设定两个参数
一个是file,一个是定义的接口。
为何要拿接口作为参数?因为接口能制定规则。
接口是没法实例化创建对象的,那么无论是谁,你想要使用find方法,必须实现这个接口和重写接口里的抽象方法。
③重写接口里的抽象方法
根据用户的需求,写出具体的过滤条件就好了,再返回一个结果。
④多态
父类引用在调用方法时,会调用子类重写后的方法,这是多态。
这里并没有将过滤条件写死,而是不同的人在调用find方法时,根据不同的重写方法,有不同的结果。
⑤遍历并递归
递归已经说了很多遍了,不再阐述。
所以什么叫代码的可拓展性?
无论用户有什么过滤要求,我只需要修改③中重写的方法就可以了,其他代码都不用改,这就是代码的可拓展性。
还能优化么?是可以的,在③中可以使用lambad表达式代替匿名内部类。
以上就是关于过滤器一点一点的优化,当然我这写的比较粗糙,我估计都存在什么问题,只不过我自己水平有限,没有发现而已。
但核心思想还是考虑到了的。
核心思想是啥?
就是接口、面向对象三大特性之一的多态。
当一个方法里参数有接口时,必定会有多态,因为接口没法实例化创建对象,必定需要其实现类对象。