JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片

释放双眼,带上耳机,听听看~!

JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片


一.装饰设计模式

其实我们自定义readLine就是一种装饰模式

  • 当想要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,并且提供加强功能,那么自定义的该类就称为装饰类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1package com.lgl.hellojava;
2
3public class HelloJJAVA {
4    public static void main(String[] args) {
5
6        Person p = new Person();
7        p.eat();
8        // 开始进行增强
9        superPerson p1 = new superPerson(p);
10        p1.superEat();
11    }
12}
13
14class Person {
15    public void eat() {
16        System.out.println("吃饭");
17    }
18}
19
20class superPerson {
21
22    private Person p;
23
24    public superPerson(Person p) {
25        this.p = p;
26    }
27
28    public void superEat() {
29        System.out.println("小菜+吃饭");
30    }
31}
32

这里的逻辑就是当我们吃饭这个功能需要增强的时候,我们应该装饰他

  • 装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能提供更强的功能

二.继承和装饰的区别

你现在知道了装饰模式,那你一定会疑问,和继承的道理类似,对吧,我们现在来说下他们的区别

这里我们就不写代码了,我们看注释


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1package com.lgl.hellojava;
2
3public class HelloJJAVA {
4    public static void main(String[] args) {
5        /**
6         * MyReader:专门用于读取数据的类
7         * MyTextReader:专门读取文本 两个向上抽取,形成继承体系
8         */
9
10        /**
11         * 想实现更多的功能
12         * MyBufferReader
13         * myBufferTestReader
14         */
15
16        /**
17         *谁需要加强就传谁进来
18         * class MyBufferReader{
19         * }
20         */
21
22    }
23}
24
25

这个逻辑大概是这样的,我们有两个功能,一个读取文件,一个读取文本,他们其实是有共性的,你就把他们共性部分抽取出来,可是我现在在读取文本的时候我顺便想读取图片呢?其实,我们就是这样才产生的装饰者模式

  • 装饰者模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系
  • 装饰类因为增强已有对象,具备功能和已有的想相同,只不过提供了更强的功能,所以装饰类和被装饰类通常属于一个体系中的

三.LineNumberReader

这也是一个子类

他也是一个包装类,我们看例子


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1package com.lgl.hellojava;
2
3import java.io.FileNotFoundException;
4import java.io.FileReader;
5import java.io.IOException;
6import java.io.LineNumberReader;
7
8public class HelloJJAVA {
9    public static void main(String[] args) {
10        FileReader fr;
11        try {
12            fr = new FileReader("test.txt");
13            LineNumberReader lnr = new LineNumberReader(fr);
14            String line = null;
15            while((line = lnr.readLine()) != null){
16                System.out.println(lnr.getLineNumber()+":"+line);
17            }
18            lnr.close();
19        } catch (FileNotFoundException e) {
20            // TODO Auto-generated catch block
21            e.printStackTrace();
22        } catch (IOException e) {
23            // TODO Auto-generated catch block
24            e.printStackTrace();
25        }
26    }
27}
28
29

他输出的结果

他可以获取和设置行号

四.自定义LineNumberReader

我们可以根据他的原理自己也来实现一个,仔细看注释


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1package com.lgl.hellojava;
2
3import java.io.FileNotFoundException;
4import java.io.FileReader;
5import java.io.IOException;
6import java.io.Reader;
7
8public class HelloJJAVA {
9    public static void main(String[] args) {
10        try {
11            FileReader fr = new FileReader("test.txt");
12            MyLineNumberReader my = new MyLineNumberReader(fr);
13            String line = null;
14            while ((line = my.MyReadLine()) != null) {
15                System.out.println(my.getLineReader() + ":" + line);
16            }
17            my.MyClose();
18        } catch (FileNotFoundException e) {
19            // TODO Auto-generated catch block
20            e.printStackTrace();
21        }
22    }
23}
24
25class MyLineNumberReader {
26    // 读取
27    private Reader r;
28    // 行号
29    private int lineReader;
30
31    // 构造方法
32    public MyLineNumberReader(Reader r) {
33        this.r = r;
34    }
35
36    // 提供对外方法
37    public String MyReadLine() {
38        // 行号自增
39        lineReader++;
40        StringBuilder sb = new StringBuilder();
41        int ch = 0;
42        try {
43            while ((ch = r.read()) != -1) {
44                if (ch == '\r')
45                    continue;
46                if (ch == '\n')
47                    return sb.toString();
48                else
49                    sb.append((char) ch);
50            }
51            if (sb.length() != 0)
52                return sb.toString();
53        } catch (IOException e) {
54            // TODO Auto-generated catch block
55            e.printStackTrace();
56        }
57        return null;
58    }
59
60    public int getLineReader() {
61        return lineReader;
62    }
63
64    public void setLineReader(int lineReader) {
65        this.lineReader = lineReader;
66    }
67
68    public void MyClose() {
69        try {
70            r.close();
71        } catch (IOException e) {
72            // TODO Auto-generated catch block
73            e.printStackTrace();
74        }
75    }
76
77}
78
79

这个思路是不是很清晰,实际上和LineNumberReader是类似的

五.字节流读取操作

字符流我们讲的差不多了,我们接着说字节,其实他们类似的,知识他操作的是字节而已

  • inputStream:读
  • outputStream:写

我们还是从例子开始


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1package com.lgl.hellojava;
2
3import java.io.FileNotFoundException;
4import java.io.FileOutputStream;
5import java.io.IOException;
6
7public class HelloJJAVA {
8    public static void main(String[] args) {
9        writeFile();
10
11    }
12
13    // 写文件
14    public static void writeFile() {
15        try {
16            FileOutputStream fo = new FileOutputStream("demo.txt");
17            fo.write("test".getBytes());
18            fo.close();
19        } catch (FileNotFoundException e) {
20            // TODO Auto-generated catch block
21            e.printStackTrace();
22        } catch (IOException e) {
23            // TODO Auto-generated catch block
24            e.printStackTrace();
25        }
26    }
27}
28
29

这里我们可以看到,他写入数据不需要刷新,现在还没有涉及到缓存区,我们继续看,写已经写好了,现在我们开始读,对于读取数据,我们开头用到的两种方法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1// 字符读数据
2    public static void readFile() {
3        try {
4            FileInputStream fs = new FileInputStream("demo.txt");
5            int ch = 0;
6            while ((ch = fs.read()) != -1) {
7                System.out.println((char) ch);
8            }
9            fs.close();
10        } catch (FileNotFoundException e) {
11            // TODO Auto-generated catch block
12            e.printStackTrace();
13        } catch (IOException e) {
14            // TODO Auto-generated catch block
15            e.printStackTrace();
16        }
17    }
18
19    // 字节读取
20    public static void readFile1() {
21        try {
22            FileInputStream fs = new FileInputStream("demo.txt");
23            byte[] buf = new byte[1024];
24            int len = 0;
25            while ((len = fs.read(buf)) != -1) {
26                System.out.println(new String(buf, 0, len));
27            }
28            fs.close();
29        } catch (FileNotFoundException e) {
30            // TODO Auto-generated catch block
31            e.printStackTrace();
32        } catch (IOException e) {
33            // TODO Auto-generated catch block
34            e.printStackTrace();
35        }
36    }
37

现在我们有了专门处理的字节流,我们可以这样做


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1public static void readFile2() {
2        try {
3            FileInputStream fs = new FileInputStream("demo.txt");
4            int num = fs.available();
5            System.out.println(num);
6            fs.close();
7        } catch (FileNotFoundException e) {
8            // TODO Auto-generated catch block
9            e.printStackTrace();
10        } catch (IOException e) {
11            // TODO Auto-generated catch block
12            e.printStackTrace();
13        }
14    }
15

我们发现直接用available就可以拿到字节了,原理其实是这段代码


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1public static void readFile2() {
2        try {
3            FileInputStream fs = new FileInputStream("demo.txt");
4            byte[] buf = new byte[fs.available()];
5            fs.read(buf);
6            System.out.println(new String(buf));
7            fs.close();
8        } catch (FileNotFoundException e) {
9            // TODO Auto-generated catch block
10            e.printStackTrace();
11        } catch (IOException e) {
12            // TODO Auto-generated catch block
13            e.printStackTrace();
14        }
15    }
16

六.I/O复制图片

ok,这里算是一个小练习,复制一张图片,我们理顺下思路

  • 1.用字节读取流和图片关联
  • 2.用字节流写入流对象创建一个图片文件,存储数据
  • 3.通过循环读写,完成数据存储
  • 4.关闭流

OK,我们用代码说话


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1package com.lgl.hellojava;
2
3import java.io.FileInputStream;
4import java.io.FileNotFoundException;
5import java.io.FileOutputStream;
6import java.io.IOException;
7
8public class HelloJJAVA {
9    public static void main(String[] args) {
10        FileOutputStream fos = null;
11        FileInputStream fis = null;
12
13        try {
14            // 复制
15            fos = new FileOutputStream("copy_img.png");
16            // 原图
17            fis = new FileInputStream("img.png");
18
19            byte[] buf = new byte[1024];
20
21            int len = 0;
22
23            while ((len = fis.read(buf)) != -1) {
24                fos.write(buf, 0, len);
25            }
26
27            fis.close();
28            fos.close();
29        } catch (FileNotFoundException e) {
30            // TODO Auto-generated catch block
31            e.printStackTrace();
32        } catch (IOException e) {
33            // TODO Auto-generated catch block
34            e.printStackTrace();
35        }
36    }
37}
38
39

这样。我们图片就拷贝过来了

好的,知识点今天就到这里

有兴趣的可以加群:555974449,咱们一起学习,一起进步!

给TA打赏
共{{data.count}}人
人已打赏
安全技术

详解Node.js API系列 Crypto加密模块(2) Hmac

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索