JAVA学习第四十九课 — IO流(三):缓冲区2 & 装饰设计模式

一、模拟BufferedReader

自定义MyBuffereaReader

对于缓冲区而言,里面其实就是封装一个数组,对外提供方法对数组的操作,这些方法最终操作的都是数组的角标

原理:从源中取出数据存入缓冲区,再从缓冲区不断的取出数据,取完后,继续从源中继续取数据,进缓冲区,直至源中的数据取完,用-1做为结束标记

import java.io.*;
class MyBufferedReader {
	private FileReader fr;
	
	//定义数组作为缓冲区
	private char[] ch = new char[1024];
	//定义一个指针用于对数组的操作,当操作数组的最后一个元素后,指针归零
	private int pos = 0;
	//定义一个计数器,当缓冲区的数据减至0后,继续从源中取数据加到缓冲区中
	private int count = 0;
	
	MyBufferedReader(FileReader fr) {
		this.fr = fr;
	}
	public int Myread() throws IOException{
		//从源中获取一批数据到缓冲区中,先判断count是否是0
		if(count==0) {
			count = fr.read(ch);
			pos = 0;
		}
			if (count<0)  
				return -1;
			
			char temp = ch[pos++];
			count--;
			return temp;
	}
	public String MyReadLine() throws IOException{
		
		//将读取的数据存储到缓冲区中
		StringBuilder sb = new StringBuilder();
		int ch = 0;
		while((ch = Myread())!=-1){
		
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			
			sb.append((char)ch);
		}
		if(sb.length()!=0)
			return sb.toString();
		return null;
	}
	public void myClose() throws IOException{
		fr.close();
	}
}
public class Main 
{
	public static void main(String[] args) throws IOException {
	
		FileReader fr = new FileReader("ACM.txt");
		MyBufferedReader msb = new MyBufferedReader(fr);
		
		String str = null;
		
	while((str = msb.MyReadLine())!=null){

			System.out.println(str);
		}
		msb.myClose();

	}
}


二、装饰设计模式

当对一组对象的功能进行增强时,就可以使用该模式进行问题的解决,上述的自定义MyBufferedReader类就是很好的体现,对于FileReader类比原来的功能简便,当然上述代码写的比较简单

class Room{
	public void show(){
		System.out.println("房子");
	} 
}
class NewRoom 
{
	private Room or;
	public NewRoom(OldRoom or) {
		// TODO Auto-generated constructor stub
		this.or = or;
	}
	public void show(){
		or.show();
		System.out.println("平房");
	}
}

一定要避免的是修改源代码,当然继承也可以实现功能的增强。

但是继承的话,会让继承体系复杂且麻烦


装饰设计模式和继承的区别:

继承:如果为了增强功能,就要继续写子类,只是为了一个新的NewRoom,就要创建一个子类,NewRoom后出现别墅呢,又要创建子类,逐渐的,导致继承体系越来越臃肿

装饰设计模式:无论NewRoom还是别墅,都是Room的一种,都保持着房子的基本属性

所以,利用装饰设计模式,只需要把被装饰的对象传入即可,可以将缓冲技术单独抽取进行封装,要缓冲区谁将谁和缓冲相关联即可,这样的设计的相对体系会变的简单。


三、LineNumberReader

API文档解释:跟踪行号的缓冲字符输入流。此类定义了方法setLineNumber(int)getLineNumber(),它们可分别用于设置和获取当前行号。

import java.io.*;

public class Main 
{
	public static void main(String[] args) throws IOException {
	
		FileReader fr = new FileReader("ACM.txt");
		LineNumberReader lr = new LineNumberReader(fr);
		
		String str = null;
		
		lr.setLineNumber(10);//设置行号从10开始
		while((str = lr.readLine())!=null){
			System.out.println(str+" line : "+lr.getLineNumber());
		}	
		lr.close();
	}
}

此类用的地方不是很多,知道怎么用即可。


四、练习

一定要用字节流文件复制媒体文件

import java.io.*;

public class Main 
{
	public static void main(String[] args) throws IOException {
		//copy_mp3_1();
		//copy_mp3_2();//开发建议使用这种
		copy_mp3_3();
	}

	public static void copy_mp3_3() throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("D:\\盛夏光年.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\盛夏光年3.mp3");
		
		byte[] by = new byte[fis.available()];//局限:文件过大,就不行了
	
		fis.read(by);
		fos.write(by);
	
		fos.close();
		fis.close();
	}

	public static void copy_mp3_2() throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("D:\\盛夏光年.mp3");
		BufferedInputStream br = new BufferedInputStream(fis);
		
		FileOutputStream fos = new FileOutputStream("D:\\盛夏光年2.mp3");
		BufferedOutputStream bw = new BufferedOutputStream(fos);
		
		int len = 0;
		while((len = br.read())!=-1){
				bw.write(len);
				bw.flush();
		}
		br.close();
		bw.close();
	}

	public static void copy_mp3_1() throws IOException {
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream("D:\\盛夏光年.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\盛夏光年1.mp3");
		
		byte[] by = new byte[1024];//注意Mp3文件的字节数,这个数组越接近效率越块
		int len = 0;
		while((len = fis.read(by))!=-1){
				fos.write(len);
				fos.flush();
		}
		fos.close();
		fis.close();
	}
}


装饰者模式的应用:

/**
 * 总结装饰者模式:
 * 是你还有你,一切依靠你
 * @author Administrator
 *
 */
class MyInputStream extends InputStream{  // extends / implements :-> 是你
	
	private InputStream in;               //还有你
	private int key;
	MyInputStream(InputStream in,int key){
		this.in = in;
		this.key = key;
	}
	
	@Override
	public int read() throws IOException {  // this.in.read() 依靠你
		
		return this.in.read() - key; // 将原文件的读取 更改 , 这个key就成为了文件解密的密码
	}
	
	//解密文件时,只需把 key 逆序 写回文件
	
}

对象增强的手段
* 继承
  被增强的对象固定的
  增强的内容也是固定的
* 装饰者模式
  被增强的对象是可以切换的
  增强的内容是固定的
* 动态代理(AOP)
  被增强的对象可以切换:Service
  增强的内容也可以切换:事务处理

继承:
缺点:
1. 增强的内容是死的,不能动!
2. 被增强的对象也是死的!

装饰者模式
1. 增强的内容是不能修改的!
2. 被增强的对象可以是任意的!


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值