前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >天命吃鸡还是落地成盒 学学装饰模式先

天命吃鸡还是落地成盒 学学装饰模式先

作者头像
用户5745563
发布2019-07-04 14:55:23
3240
发布2019-07-04 14:55:23
举报
文章被收录于专栏:码思客
java零基础入门-高级特性篇(十三) IO 流 3

本章介绍另一个流派-字符流。其实如果上一章字节流已经掌握的话,字符流学起来会更加简单。先来看看字符流的结构,他与字节流的结构稍有不同。

主要类

字节流中主要的类有4个,而字符流中有6个,简单介绍一下这6个类。输入流中FileReader是核心,虽然是核心类,但是其实它本身没有什么功能,类中只有构造器,它继承InputSteamReader类,主要功能来自于继承的InputSteamReader类。而BufferedReader是将FileReader包装后,具有缓冲功能的字符输入流,文件较大请使用带缓冲功能的流。

FileReader

字符流

FileReader的例子和上一章字节流的写法十分相似,也是首先根据文件路径创建File对象,然后设置一个字符数组,最后循环输出读入的字符。用法难度不大,这里主要来看看FileReader里面到底在干什么。

FileReader

FileReader里面只有3个构造器,而构造器里面创建了字节流然后作为参数传给了父类的构造器。为什么字符流里面用的是字节流?往下看,父类InputSteamReader的构造器里面有一个关键的类-StreamDecoder,这个类的作用就是对字节流进行编码和解码。这样一来,就能弄清楚FileReader和InputSteamReader到底是做什么用的了。

FileReader的作用,其实是表示“我是字符流家族的”,然而它背地里偷偷跟字节流家族搭上线,它的存在只是保证了字符流家族的完整性。

InputSteamReader的作用,帮助FileReader在背地里将字节流进行编码转换,让字符流看上去是在直接处理字符,所以他还有个名字叫做“转换流”。

虽然字节流和字符流都可以处理中文,但是在处理需要编码的文字的时候还是建议使用字符流,这样会减少发生错误的几率。

FileWriter

写入文件

字符输出流看上去要简单很多,首先根据路径参数创建一个文件,然后将内容写入到创建的文件中。但是这里要注意一个地方,就是FileWriter的flush方法。这个方法比较重要,因为如果在最后不调用这个方法的话,文字是不会被写人到文件的。原因就是FileWriter有缓冲区,flush方法就是将缓冲区中的内容清空,把文字写入到文件。这里肯定有同学会问了,这个FileWriter名字上没有Buffered这个标识啊,为啥会有缓冲区?这里要说明一个概念,FileWriter是有默认的缓冲区大小的,而带有Buffered的缓冲输出流的缓冲区是可以配置大小的。

字符缓冲流

缓冲流

和字节流一样,更高级的缓冲流只需要对字符流进行一层包装即可,然后流就具有缓冲功能了,并且是可以设置缓冲区大小的缓冲功能。上节说过,流是需要关闭的,在关闭流的过程中,会自动检查缓冲区的内容是否被清空,如果没有清空缓冲区就关闭流,程序会自动调用flush方法清空缓冲区。所以,一般只要记得关闭流就可以了,不需要特意去清空缓冲区。

装饰模式

前面讲过工厂模式,这里再来讲一个装饰模式,因为缓冲流这种设计,就是最好的装饰模式实现。装饰模式是啥?我们先来吃把鸡就应该懂了。最近吃鸡游戏很火,要想吃鸡,你需要装备性能好,配置高的武器才行,比如我比较喜欢用的是M416这把武器。这把武器的配件非常多,虽然搜起来比较困难,但是一旦全部搜齐了,交战起来火力那是可以秀敌人一脸的。

没有配件的M416这把枪就是下面的样子。如果没有配件,用起来是非常困难的,首先没有瞄准镜,瞄准敌人很困难,其次没有握把和枪头,开火后难以控制准星,所以我们需要尽快搜到配件安装到枪上,才能提高我们的作战能力。

M416

来看看如何设计代码,首先游戏里面肯定不止这一种枪,除了步枪还有手枪,狙击枪等等,所以老规矩,将枪作为父类提出来,作为抽象类,可以实现枪的公用方法,也可以只要抽象方法,不同的枪都来继承它就行了。M416继承了枪这个类以后,只需要实现枪这个类定义的抽象方法即可。

M416的代码

这里只实现了一个M416,当然各位也可以实现其他的枪,比如SCAR,98k等等。只需要继承Gun这个父类即可。但是这里要说明的不是实现各种枪,而是要实现枪的配件,下面看看一把有配件的M416长什么样。

配件

现在要开始设计带有配件的M416的代码了。那么问题就来了,配件不是固定的,我们可能刚落地就搜到所有配件,也有可能直到游戏结束都只能搜到一个配件,所以我们设计的带有配件的M416不是固定的,也就是说我们有很多种可能会出现的M416形态。

可能形态

看到这么多种可能,有的同学可能掐指一算,嗯~1+2+3=6个类,撸起袖子开始顺着写6个类。我想说,其实我这里只是简化了配件数量,其实M416的配件还有弹夹和枪托,并且每个部位的配件可能不止一种,比如弹夹还可以分为扩容弹夹和快速弹夹,真要一个个写下来,可能几十个类都写不完。那么该怎么办?让他们自由组合就可以了,好了,装饰模式登场了。

装饰模式可以动态的给一个对象加上更多的责任(功能),在不需要创造更多的子类的情况下,将对象的功能进行扩展。来看看如何使用装饰模式解决上面这个问题。

首先创建一个抽象装饰类,这个类的作用就是动态的传入对象,这个对象只要是Gun或者Gun的子类都可以,简单的说,只要传入一把枪就行,然后用具体装饰类对这个抽象装饰类进行“装饰”,加上各种功能即可。

抽象装饰和具体装饰

抽象装饰类,用于维护一个对象,这个对象可以是任何一个M416,没有配件或者有配件都可以,然后在具体的装饰类中,可以继续对这个对象进行功能的添加,这样就可以在M416的基础上,配置各种配件,而不需要为特定的形态创建新的类。

装配M416

首先创建一个无配件的M416,再创建3个带配件的M416,最后创建一个有所有配件的M416。这里最重要的就是好好理解抽象装饰类的作用和具体装饰类的作用,正因为有了这两个重要的部件,才能灵活的对各种功能进行组装。

理解了上面这个例子,再来对比一下这个例子和IO流中的设计,来看看IO流中如何使用装饰模式。

对比

左边的结构就是上例的结构,各位应该已经明白了。再来看右图,有没有发现结构几乎一样?其实不止结构一样,连功能都几乎没有区别,前面章节说过InputStream是所有字节输入流的抽象基类,其实他扮演的角色和Gun一样,他就是为了构建各种字节输入流而存在。FileInputStream就像没有配件的M416一样,他只有最简单的功能,如果需要额外的功能,需要创建抽象装饰类,然后创建带有新功能的具体装饰类。来看看代码上的对比。

对比

缓冲流的用法就是将普通流作为参数传递给缓冲流构造器,这与M416加配件的过程一样。都是把没有附加功能的类,包装成带有各种新功能的“高级类”,而在IO流中,当然就是“高级流”了。流的家族很大,这里只介绍了最常用的缓冲流BufferedInputStream,其实还有很多其他带有功能的高级流,比如上图中LineNumberInputStream也是一种带有功能的高级流,它的功能是获取当前输入流的行数和设置行数,这些都是具体的装饰类。

以上就是字节输入流的装饰模式展示,其他字节输出流,字符的输入输出流也都是装饰模式,结构上大同小异。这也是为什么IO流家族体系庞大的原因之一。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码思客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档