装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于以后的功能,并提供加强功能,那么自定义的这个类就称为装饰类。
装饰类通常会通过构造方法,来接收被装饰的对象,并且基于被装饰的对象的功能,提供更强的功能。
例如:
1: import java.io.*;
2:
3: /*
4: 使用装饰设计模式,比较灵活,降低了类与类之间的关系
5: */
6: class Person
7: {
8: public void chifan()
9: {
10: System.out.println("吃饭");
11: }
12: }
13:
14: class SuperPerson
15: {
16: private Person p;
17:
18: //将Person类的对象通过SuperPerson的构造函数传进来,这样就可以在
19: //SuperPerson类中使用Person对象的方法,并且可以对Person对象的功能进行增强
20: SuperPerson(Person p)
21: {
22: this.p=p;
23: }
24:
25: public void superChifan()
26: {
27: System.out.println("开胃酒");
28: p.chifan();
29: System.out.println("甜点");
30: }
31:
32: }
33:
34: class PersonDemo
35: {
36: public static void main(String[] args)
37: {
38: Person p=new Person();
39: SuperPerson sp=new SuperPerson(p);
40:
41: sp.superChifan();
42: }
43: }
44:
45:
46:
47:
MyReader 专门用来读取数据的类
|---MyTextReader
|---MyBufferedTextReader
|---MyMediaReader
|---MyBufferedMediaReader
MyReader有很多子类,例如MyTextReader和MyMediaReader,但是单个读取的效率太低,因此又出现了使用缓冲区的子类,加强形式,但是这样MyReader每增加一个子类,就需要增加一个加强形式。这样扩展性太差。
如果想Buffer功能单独写成一个类呢,那么有
class MyBufferReader
{
MyBufferedReader(MyTextReader mytext) { }
MyBufferedReader(MyMediaReader mymedia) { }
………….
}
这样的话,MyReader每增加一个子类,MyBufferReader就要增加一个构造方法,扩展性也很差。那么找其参数的共同类型,改写成多态的形式,这样就提高了扩展性。
class MyBufferedReader extends MyReader
{
MyBufferReader(MyReader r) { }
}
装饰类因为增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强的功能。所以装饰类和被装饰类通常都是属于一个体系中。
MyReader 专门用来读取数据的类
|---MyTextReader
|---MyMediaReader
|---MyBufferedReader
LineNumberReader:(BufferedReader的子类)
跟踪行号的缓冲字符输入流,此类定义了方法setLineNumber和getLineNumber,用于设置和获取当前行号。
1: import java.io.*;
2:
3: class MyLineNumberReader
4: {
5: private FileReader r;
6: private int num=0;
7: MyLineNumberReader(FileReader r)
8: {
9: this.r=r;
10: }
11:
12: public String myReadLine()throws IOException
13: {
14: num++;
15: StringBuilder sb=new StringBuilder();
16: int ch=0;
17: while((ch=r.read())!=-1)
18: {
19: if(ch=='\r')
20: continue;
21: if(ch=='\n')
22: return sb.toString();
23: else sb.append((char)ch);
24: }
25:
26: if(sb.length()!=0)
27: return sb.toString();
28:
29: return null;
30:
31: }
32:
33: //设置行号
34: public void mySetLineNumber(int num)
35: {
36: this.num=num;
37: }
38:
39: //获取行号
40: public int myGetLineNumber()
41: {
42: return num;
43: }
44:
45: public void myClose()throws IOException
46: {
47: r.close();
48: }
49:
50:
51: }
52:
53:
54:
55:
56: class MyLineNumberReaderDemo
57: {
58: public static void main(String[] args) throws IOException
59: {
60: FileReader fr=new FileReader("MyBufferedReaderDemo.java");
61: MyLineNumberReader mylnr=new MyLineNumberReader(fr);
62:
63: String line=null;
64: while((line=mylnr.myReadLine())!=null)
65: {
66: System.out.println(mylnr.myGetLineNumber()+":"+line);
67: }
68: mylnr.myClose();
69:
70:
71: }
72: }
73:
字节流:
需求,如果想要操作图片数据,这是需要使用到字节流。InputStream和OutputStream
1: import java.io.*;
2:
3:
4: class FileStream
5: {
6: public static void writeFile()throws IOException
7: {
8: FileOutputStream fos=new FileOutputStream("fos.txt");
9:
10:
11: //字节流只可以写入字节或者字节数组,abcde为字符串,需要进行转换,getBytes()
12: //getBytes()方法,将String编码为byte序列,并将结果存在一个新的byte数组中
13: fos.write("abcde".getBytes());
14:
15: //如果没有使用到指定的缓冲区,是不需要缓冲的,但是需要关闭资源
16: fos.close();
17: }
18:
19: //单个字节读取
20: public static void readFile_1()throws IOException
21: {
22: FileInputStream fis=new FileInputStream("fos.txt");
23:
24: int ch=0;
25: while((ch=fis.read())!=-1)
26: {
27: System.out.println((char)ch);
28: }
29: fis.close();
30: }
31:
32: //按字节数组来进行读取
33: public static void readFile_2()throws IOException
34: {
35: FileInputStream fis=new FileInputStream("fos.txt");
36:
37: byte[] buf=new byte[1024];
38: int len=0;
39:
40: while((len=fis.read(buf))!=-1)
41: {
42: System.out.println(new String(buf));
43: }
44:
45: fis.close();
46: }
47:
48: public static void readFile_3()throws IOException
49: {
50: FileInputStream fis=new FileInputStream("fos.txt");
51:
52: //available()方法,返回值为文件中的字节数,包括换行符,这样可以定义一个刚好的缓冲区,不需要循环
53:
54: byte[] buf=new byte[fis.available()];
55:
56: fis.read(buf);
57:
58: System.out.println(new String(buf));
59:
60: fis.close();
61: }
62:
63:
64:
65: public static void main(String[] args) throws IOException
66: {
67: readFile_3();
68: }
69: }
70:
练习:复制一张图片
1: import java.io.*;
2:
3: class PictureCopy
4: {
5: public static void main(String[] args)
6: {
7: FileInputStream fis=null;
8: FileOutputStream fos=null;
9: try
10: {
11: fis=new FileInputStream("IMG_0696.jpg");
12: fos=new FileOutputStream("abc.jpg");
13: byte[] buf=new byte[1024];
14:
15: int len=0;
16: while((len=fis.read(buf))!=-1)
17: {
18: fos.write(buf);
19: }
20:
21: }
22: catch (IOException e)
23: {
24: System.out.println("...");
25:
26: }
27: finally
28: {
29: try
30: {
31: fis.close();
32: }
33: catch (IOException e)
34: {
35: System.out.println("关闭读取资源失败");
36:
37: }
38: try
39: {
40: fos.close();
41: }
42: catch (IOException e)
43: {
44: System.out.println("关闭写入资源失败");
45:
46: }
47: }
48: }
49: }
50:
MP3的复制,通过缓冲区:
1: class CopyMP3
2: {
3: public static void main(String[] args) throws IOException
4: {
5: //定义一个读取流对象,读取目标文件中的数据
6: BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
7:
8: //定义一个输出流对象,用来将读取到的数据写入到目的文件中去
9: BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
10:
11: int by=0;
12: byte[] buf=new byte[1024];
13: while((by=bufis.read(buf))!=-1)
14: {
15: bufos.write(by);
16: }
17:
18: bufis.close();
19: bufos.close();
20:
21: }
22: }
23:
自定义字节流缓冲区:
1: class MyBufferedInputStream
2: {
3: private InputStream in;
4: //定义一个byte型的数组,用于存储数据
5: private byte[] buf=new byte[1024];
6: //count为计数器,pos为数组的指针
7: private int pos=0,count=0;
8:
9: MyBufferedInputStream(InputStream in)
10: {
11: this.in=in;
12: }
13:
14: //一次读取一字节,从
15: public int myRead() throws IOException
16: {
17: //通过in来读取硬盘上的数据,并且存储到buf中
18: if(count==0)
19: {
20: count=in.read(buf);
21: if(count<0)
22: return -1;
23: pos=0;
24: byte b=buf[pos];
25: count--;
26: pos++;
27:
28: return b&255;
29: }
30: else if(count >0)
31: {
32: byte b=buf[pos];
33: count--;
34: pos++;
35:
36: return b&255;
37: }
38: return -1;
39: }
40:
41: public void myClose()throws IOException
42: {
43: in.close();
44: }
45:
46: }
47:
48: /*
49: why b&255?
50:
51: 若数据文件的第一个数据恰好是1111 1111
52: 提升成了int类型以后,数据值为-1
53:
54: 是-1的原因是因为在8个1前面补得为1,如果在前边补0,即可以保留原字节数据不变,又可以避免-1的出现
55:
56: 1111 1111 1111 1111 1111 1111 1111 1111
57: 0000 0000 0000 0000 0000 0000 1111 1111
58:
59:
60: 0000 0000 0000 0000 0000 0000 1111 1111
61: 提升为int型后,多占了内存,write方法写入时,将前面的舍弃,只保留后8位
62:
63: */
读取键盘录入:
需求:通过键盘录入数据,当录入一行数据,就将该行数据进行打印,如果录入的数据为over,那么停止录入
1: class InputStreamDemo
2: {
3: public static void main(String[] args)
4: {
5: InputStream in=System.in;
6: StringBuilder sb=new StringBuilder();
7: while(true)
8: {
9: int ch=in.read();
10: if(ch=='\r')
11: continue;
12: if(ch=='\n')
13: {
14: String s=sb.toString();
15: if("over".equals(s))
16: break;
17: System.out.println(s.toUpperCase());
18: //每次录入一行数据,就将该行数据进行打印以后,应该将存在StringBuilder里面的
19: //内容清空,下次录入时,才不会有下一次的数据
20:
21: sb.delete(0,sb.length());
22:
23: }
24: else sb.append((char)ch);
25: }
26: }
27: }
28:
29: /*
30: 以上代码即为读一行数据的原理,即readLine()方法
31: 那能不能直接用readLine方法来完成键盘录入的一行数据的读取呢?
32:
33: 但是readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法,是字节流InputStream的方法
34: 那么能不能将字节流转换成字符流,而使用字符流缓冲区的readLine方法呢?
35:
36: 使用InputStreamReader类
37:
38: */
1: public void method()throws Exception
2: {
3: InputStream in=System.in;
4:
5: //将字节流对象转成字符流对象,使用转换流
6: InputStreamReader isr=new InputStreamReader(in);
7: //为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
8: BufferedReader bufr=new BufferedReader(isr);
9:
10: String line=null;
11: while((line=bufr.readLine())!=null)
12: {
13: if("over".equals(line))
14: break;
15: System.out.println(line.toUpperCase());
16: }
17:
18: bufr.close();
19: }