您的位置:首页 > 职场人生

黑马程序员——Java基础—IO流(一)

2015-04-11 18:49 417 查看
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———

一概述

二IO流的区分

三IO流常用基类

一Writer类

二Reader类

三字符流练习

四字符流缓冲区

五装饰设计模式

IO流概述

一、概述

Java对数据的处理都是通过流的方式,称为
IO(Input-Outpu)
流。IO流用于处理设备上的数据传输,如硬盘上储存的数据,内存中驻留的数据。

二、IO流的区分

1.按流向分

按流向分为:输入流和输出流。

2.按操作数据分

流按操作数据分为两种:字节流与字符流。

小扩展:

字符流的出现是为了方便处理文本字符。英语有英文字符集ASCII码;中文字符集由原来的GB2312,扩展为现在的GBK。之后,国际标准化组织计划将世界上所有国家的文字都进行编排,形成了国际标准码表,UNICODE;优化之后,形成了UTF-8字符编码表。那么,如果一个电脑用GBK编码存储文本,另一个电脑用UTF-8编码读取,就会出现乱码。Java就这个情况,在字节流的基础上,增加了字符流。字符流内部融合了编码表,并可以指定查询的编码表,处理文本字符更加方便,避免乱码。

三、IO流常用基类

1.字符流的抽象基类

Reader

Writer

2.字节流的抽象基类

InputStream

OutputStream

IO流用于操作数据,数据的最常见体现形式是文件。那么以操作文件为主,从字符流开始,来演示IO流程序。

IO流(一)

字符流



一、Writer类

1.概述

Writer
类可以在硬盘上创建一个文件,并写入或添加数据。该类的子类还能实现写入过程中的不同功能。

2.
FileWriter


FileWriter
类专门用于操作文件。该对象中只有构造方法,并且没有空参数的构造方法,因为初始化的时候必须要有文件对象,才能进行写入操作。在示例代码中,将对每个环节做详细注释。

1)文件创建并写入

第一步:创建
FileWriter
对象,传入要操作的文件名

class FileWriterDemo {
public static void main(String[] args) throws IOException {
/* 在当前目录创建一个名为demo.txt的文件作为文本写入的目标 */
FileWriter fw = new FileWriter("demo.txt");
}
}


注意:

-创建文件会报出异常,此处先抛出,后期会有专门处理异常的代码;

-如果指定文件夹下有同名文件,该文件将被覆盖,所以要小心创建操作

第二步:写入自定义数据

class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("demo.txt");
/* 将字符串写入缓冲区 */
fw.write("abcde");
/* 将缓冲区中的内容写入文件 */
fw.flush();
}
}


注意:

-writer()方法不是将文本内容直接写入文件,而是先写入流的缓冲区;

-flush()方法将缓冲区中的内容写入到文件;每次调用完writer()方法,都要调用flush()

第三步:关闭流资源

class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("demo.txt");
/* 将字符串写入缓冲区 */
fw.write("abcde");
/* 将缓冲区中的内容写入文件 */
fw.flush();
/* 关闭流资源,关闭之前会刷新缓冲区一次 */
fw.close();
}
}


注意:

-由于每个系统创建文件写入内容的方式不同,Java需要调用系统底层的功能来实现文件的创建和写入;使用完系统资源的之后,一定要调用close()方法,关闭该资源;

-close()方法与flush()方法的区别在于,close()方法刷新缓冲区之后,关闭了该输出流资源,之后不能再写入数据;而flush()之后,可以继续写入数据,流资源依然存在;

第四步:针对处理IO异常

class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("abcde");
fw.flush();
} catch(IOException e) {
System.out.println(e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}


注意:

-用try catch捕捉并处理异常;

-关闭资源的代码一定要放在finally中;

-close()方法同样会抛出IO异常,同样需要用try catch捕捉并处理;

-如果创建文件的路径有误(例如电脑上没有k盘,创建时却写fw = new FileWriter(“k:\”demo.txt”);),那么会报出FileNotFoundException文件无法找到异常,同时会报出NullPointerException空指针异常,因为路径找不到,fw对象没有建立,而finally中还要调用close()方法,会发生空指针异常;所以需要在finally中建立判断;

-无论读、写数据还是关闭资源操作,都有可能发生IO异常

2)文件的续写

在原有数据的基础上,续写自定义数据。

第一步:修改构造方法

class FileWriterDemo {
public static void main(String[] args) throws IOException {
/* 传递一个布尔型参数,true表示不覆盖已有文件
* 从文件内容末尾开始添加新内容;如果文件不存在
* 则创建一个新文件
*/
FileWriter fw = new FileWriter("demo.txt", true);
}
}


第二步:写入自定义数据

class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt", true);
/* windows中判断换行是用\r\n来判断,\n只适用于linux系统 */
fw.write("nihao\r\nxiexie");
fw.flush();
} catch(IOException e) {
System.out.println(e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}


二、Reader类

1.概述

Reader
类用于高效读取字符流。该类的子类可以实现读取过程中的不同功能。

2.FileReader类

FileReader
类是用于读取字符文件的便捷类。该类包含默认的字符编码和默认的字节缓冲区大小。

1)read()方法读取文件

第一步:创建FileReader对象

class FileReaderDemo {
public static void main(String[] args) {
try {
/* 创建一个文件读取流对象,并与指定名称的文件相关联 */
FileReader fr = new FileReader("demo.txt");
} catch(IOException e) {
System.out.println(e.toString());
}
}
}


注意:

创建FileReader对象时关联的读取文件必须已经存在,不然会发生FileNotFoundException

第二步:读入单个字符并关闭资源

class FileReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("demo.txt");
/* read()方法一次读一个字符,第二次调用会自动读取下一个字符 */
int ch1 = fr.read();

System.out.print("ch1 = " + (char)ch1);

} catch(IOException e) {
System.out.println(e.toString());
} finally {
try {
if(fr != null)
fr.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}


注意:

read()方法读到文件末尾没有字符的时候,会返回-1;可以利用这个机制,循环读取所有数据

第三步:一次性读取全部数据

class FileReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("demo.txt");
int ch = 0;
/* 当ch不等于-1的时候,继续读文件,直到文件末尾 */
while((ch = fr.read()) != -1) {
System.out.print("ch = " + (char)ch);
}
} catch(IOException e) {
System.out.println(e.toString());
} finally {
try {
if(fr != null)
fr.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}


2)read(ch[] ch)方法读取文件

第一步:定义一个字符数组用于储存读到的字符

class FileReaderDemo {
public static void main(String[] args) {
try {
FileReader fr = new FileReader("demo.txt");
/* 创建长度为10的字符数组 */
char[] buff = new char[10];

} catch(IOException e) {
System.out.println(e.toString());
}
}
}


第二步:读取字符并存入字符数组

class FileReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("demo.txt");

char[] buff = new char[10];
/* 读取字符并存入字符数组 */
int num = fr.read(buff);
System.out.print(new String(buff));
} catch(IOException e) {
System.out.println(e.toString());
} finally {
try {
if(fr != null)
fr.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}


注意:

read(ch[] ch)方法返回的是读取了多少个字符;独到文件末尾,返回-1;可以利用这一机制,循环读取全部字符

第三步:一次性读取全部数据

class FileReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("demo.txt");

char[] buff = new char[1024];

int num = 0;
/* 当返回值不等于-1时,继续读文件 */
while((num = fr.read(buff)) != -1) {
/* 读取了多少个字符,就打印多少个字符 */
System.out.print(new String(buff, 0, num));
}
} catch(IOException e) {
System.out.println(e.toString());
} finally {
try {
if(fr != null)
fr.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}


注意:

-缓冲区字符数组通常定义1024的整数倍长度;

-read(ch[] ch)方法的效率优于read()方法;由于read()方法读一个字符,写一个字符,效率低下;而raead(ch[] ch)方法读取一段字符到缓冲区,然后一起写入,效率较高

三、字符流练习

1.读取文件并打印

读取一个
.java
文件,打印在控制台上。

示例代码:

package com.heisejiuhuche.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo {
public static void main(String[] args) {
// print_1();
print_2();
}

/* 用read(ch[] ch)方法读取所有数据 */
private static void print_1() {
/* 创建FileReader引用 */
FileReader fr = null;
try {
/* 创建FileReader对象,关联文件 */
fr = new FileReader(
"C:\\RuntimeDemo.java");

/* 创建字符串缓冲区 */
char[] ch = new char[1024];

int len = 0;

/* 当read方法返回值不等于-1,继续读文件 */
while ((len = fr.read(ch)) != -1) {
System.out.print(new String(ch, 0, len));
}
} catch (FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch (IOException e) {
throw new RuntimeException("操作失败");
} finally {
try {
if (fr != null) {
/* 关闭资源 */
fr.close();
}
} catch (IOException e) {
throw new RuntimeException("输入流关闭失败");
}
}
}

/* 用read()方法读取所有数据 */
private static void print_2() {
/* 创建FileWriter引用,关联文件 */
FileReader fr = null;
try {
/* 创建FileWriter对象,关联文件 */
fr = new FileReader(
"C:\\RuntimeDemo.java");

int ch = 0;

/* 当read方法返回值不等于-1,继续读文件 */
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
} catch (FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch (IOException e) {
throw new RuntimeException("操作失败");
} finally {
try {
if (fr != null) {
fr.close();
}
} catch (IOException e) {
throw new RuntimeException("输入流关闭失败");
}
}
}
}


注意:

打印在控制台上不要用println方法,否则会出现不必要的换行

2.复制文件

将指定文件从一个目录复制到另一个目录。

原理:

将一个文件的内容写入到另一个目录下的另一个文件中

示例代码:

package com.heisejiuhuche.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyFileTest {
private static FileReader fr;
private static FileWriter fw;

public static void main(String[] args) {
copy_1();
//      copy_2();
}

/* 用read(ch[] ch)方法复制文件 */
private static void copy_1() {
try {
/* 创建目的文件 */
fw = new FileWriter(
"C:/Users/jeremy/Documents/javaTmp/Runtime.java");

/* 关联需要复制的文件 */
fr = new FileReader(
"C:\\RuntimeDemo.java");

/* 创建字符数组缓冲区 */
char[] buff = new char[1024];

/* 循环控制 */
int len = 0;

/* 将需要复制的文件写入缓冲区,并将缓冲区文件写入目的文件 */
while ((len = fr.read(buff)) != -1) {
fw.write(buff, 0, len);
}
fw.flush();
} catch (FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch (IOException e) {
throw new RuntimeException("操作失败");
} finally {
try {
if (fw != null) {
fw.close();
}
if (fr != null) {
fr.close();
}
} catch (IOException e) {
throw new RuntimeException("流资源关闭失败");
}
}
}
/* 用read()方法复制文件 */
private static void copy_2() {
try {
/* 步骤与上述方法相近 */
fw = new FileWriter(
"C:/Users/jeremy/Documents/javaTmp/Runtime.java");
fr = new FileReader(
"C:\\RuntimeDemo.java");

int ch = 0;

while((ch = fr.read()) != -1) {
fw.write(ch);
}
fw.flush();
} catch(FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch(IOException e) {
throw new RuntimeException("操作失败");
} finally {
try {
if(fw != null) {
fw.close();
}
if(fr != null) {
fr.close();
}
} catch(IOException e) {
throw new RuntimeException("流资源关闭失败");
}
}
}
}


四、字符流缓冲区

1.概述

缓冲区的出现,提高了字符流对数据的读写效率。缓冲区可以实现先读出一部分数据,再一起写入,避免了硬盘在读与写之间频繁操作,提高读写速度。缓冲区必须结合流才能使用,在流的基础上对流的功能进行了增强。开发时通常都有缓冲区。

2.缓冲区对应类

缓冲区对应两个类,分别是
BufferedWriter
BufferedReader
。它们提供的方法,可以实现对文本字符数据的高效读写。

3.BufferedWriter类

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。在创建
BufferedWriter
类时,必须先有流对象。

1)文件创建并写入

第一步:创建字符流输出流对象

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输出流对象 */
FileWriter fw = new FileWriter("Demo.txt");
}
}


第二步:创建缓冲字符输出流对象

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输出流对象 */
FileWriter fw = new FileWriter("Demo.txt");
/* 创建缓冲字符输出流对象,并将字符输出流对象作为参数传递给其构造方法 */
BufferedWriter buffWriter = new BufferedWriter(fw);
}
}


第三步:调用方法进行写入

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输出流对象 */
FileWriter fw = new FileWriter("Demo.txt");
/* 创建缓冲字符输出流对象,并将字符输出流对象作为参数传递给其构造方法 */
BufferedWriter buffWriter = new BufferedWriter(fw);

for(int x = 1; x < 5; x++) {
buffWriter.write("abcde" + x);
/* 缓冲区提供的新方法,能跨平台换行 */
buffWriter.newLine();
buffWriter.flush();
}
}
}


注意:

只要用到缓冲区,就要调用flush()方法进行刷新

第四步:写入完毕,关闭资源

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输出流对象 */
FileWriter fw = new FileWriter("Demo.txt");
/* 创建缓冲字符输出流对象,并将字符输出流对象作为参数传递给其构造方法 */
BufferedWriter buffWriter = new BufferedWriter(fw);

for(int x = 1; x < 5; x++) {
buffWriter.write("abcde" + x);
/* 缓冲区提供的新方法,能跨平台换行 */
buffWriter.newLine();
buffWriter.flush();
}
/* 关闭缓冲区 */
buffWriter.close();
}
}


注意:

正真进行写入操作的是字符输出流FileWriter;所以关闭缓冲区其实就是关闭FileWriter对象

4.BufferedReader类

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。在创建
BufferedReader
类时,必须先有流对象。该缓冲区提供了
readLine()
方法,使获取文本数据更高效。

1)文件读取

第一步:创建字符输入流对象

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输入流对象并关联目标文件 */
FileReader fr = new FileReader("Demo.txt");
}
}


第二步:创建缓冲字符输入流对象

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输入流对象并关联目标文件 */
FileReader fr = new FileReader("Demo.txt");
/* 创建缓冲字符输入流对象,并将字符输入流对象作为参数传递给其构造方法 */
BufferedReader buffReader = new BufferedReader(fr);
}
}


第三步:调用方法读取数据

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输入流对象并关联目标文件 */
FileReader fr = new FileReader("Demo.txt");
/* 创建缓冲字符输入流对象,并将字符输入流对象作为参数传递给其构造方法 */
BufferedReader buffReader = new BufferedReader(fr);
/* 调用readLine()方法读取数据,如果独到最后一行,该方法返回null */
String line = null;
while((line = buffReader.readLine()) != null) {
System.out.println(line);
}
}
}


第四步:关闭缓冲区

class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/* 创建一个字符输入流对象并关联目标文件 */
FileReader fr = new FileReader("Demo.txt");
/* 创建缓冲字符输入流对象,并将字符输入流对象作为参数传递给其构造方法 */
BufferedReader buffReader = new BufferedReader(fr);
/* 调用readLine()方法读取数据,如果独到最后一行,该方法返回null */
String line = null;
while((line = buffReader.readLine()) != null) {
System.out.println(line);
}
/* 关闭缓冲区 */
buffReader.close();
}
}


5.缓冲区练习

1)通过缓冲区复制一个
.java
文件

示例代码:

package com.heisejiuhuche.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyByBuffTest {
private static BufferedWriter buffw;
private static BufferedReader buffr;

public static void main(String[] args) {
copy();
}

private static void copy() {
try {
/* 分别创建缓冲区对象,并关联文件 */
buffw = new BufferedWriter(new FileWriter(
"C:/Users/jeremy/Documents/javaTmp/SystemDemo.java"));
buffr = new BufferedReader(new FileReader(
"C:\\Users\\jeremy\\java\\workspaces\\test\\src\\com\\heisejiuhuche\\api\\SystemDemo.java"));
/* 循环控制,记录读取的每一行 */
String line = null;
/* 读取数据,直到最后一行 */
while((line = buffr.readLine()) != null) {
buffw.write(line);
buffw.newLine();
buffw.flush();
}
} catch(FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch(IOException e) {
throw new RuntimeException("操作失败");
} finally {
/* 关闭缓冲区 */
try {
if(buffw != null) {
buffw.close();
}
if(buffr != null) {
buffr.close();
}
} catch(IOException e) {
throw new RuntimeException("流资源关闭失败");
}
}
}
}


注意:

使用readLine()方法读取时,不会读取每一行的回车符;所以在写入时,每写一行要调用newLine()方法换行

6.readLine()方法

1)原理



readLine()
方法的实现是基于
read()
方法的。如图,
readLine()
方法在内存中创建了一个字符数组作为缓冲,每次读取操作都调用
read()
方法,读取一个字符。步骤
1
2
3
4
5
读取了五次,并分别将这五个字符存入字符数组。当读到换行附的时候,
readLine()
方法不会将换行字符存入数组,而将字符数组中的字符组成字符串返回,再由输出流调用写入方法,在第
6
步写入目标文件。

2)自定义readLine()方法

模拟一个
BufferedReader
类,要求有
readLine()
功能的方法和
close()
功能的方法。

示例代码:

package com.heisejiuhuche.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class MyBufferedReaderTest {
/* 在main方法中读取一个文件,并在控制台打印,测试MyBufferedReader类 */
public static void main(String[] args) {
MyBufferedReader buffr = null;
try {
FileReader fr = new FileReader("Demo.txt");

buffr = new MyBufferedReader(fr);

String line = null;

while ((line = buffr.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch (IOException e) {
throw new RuntimeException("操作失败");
} finally {
try {
if(buffr != null)
buffr.close();
} catch(IOException e) {
throw new RuntimeException("资源关闭失败");
}
}
}
}

class MyBufferedReader {
/* 持有FileReader的引用,因为readLine()方法基于read()方法 */
private FileReader fr;

/* 初始化时需要传入字符流对象 */
MyBufferedReader(FileReader fr) {
this.fr = fr;
}

/* 创建readLine()方法,标识异常 */
public String readLine() throws IOException {
/* 用StringBuilder代替数组,完成字符串拼接 */
StringBuilder sb = new StringBuilder();

int ch = 0;

/* 调用read()方法,读取数据 */
while ((ch = fr.read()) != -1) {
/* 如果读到'\r',跳过,继续读下一个字符 */
if (ch == '\r')
continue;
/*如果读到'\n',标识一行结束,返回这行的字符串 */
if (ch == '\n')
return sb.toString();
else
/* 如果是字符,就加入StringBuilder */
sb.append((char)ch);
}
/* 这行代码排除了行末没有'\n'而整行字符串不会被打印的情况 */
if (sb.length() != 0) {
return sb.toString();
}
/* 如果读到文件最后,返回null */
return null;
}

/* 创建关闭缓冲区方法,标识异常 */
public void close() throws IOException {
fr.close();
}
}


程序输出结果:

abcd1
abcd2
abcd3


7.LineNumberReader类

LineNumberReader
类是可以跟踪行号的缓冲字符输入流。
LineNumberReader
BufferedReader
的子类,其使用也必须结合流。该类的用法和
BufferedReader
基本一致。

1)输出带行号文本

示例代码:

package com.heisejiuhuche.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class LineNumberReaderDemo {
public static void main(String[] args) {
LineNumberReader lnr = null;
try {
lnr = new LineNumberReader(new FileReader("SystemDemo.java"));

String line = null;

while((line = lnr.readLine()) != null) {
/* 调用getLineNumber()方法现实行号 */
System.out.println(lnr.getLineNumber() + ":" + line);
}
} catch(FileNotFoundException e) {
throw new RuntimeException("文件不存在");
} catch(IOException e) {
throw new RuntimeException("操作失败");
} finally {
try {
if(lnr != null)
lnr.close();
} catch(IOException e) {
throw new RuntimeException("资源关闭失败");
}
}
}
}


程序输出部分结果:

6:public class SystemDemo {
7:  public static void main(String[] args) {
8:      Properties prop = System.getProperties();


五、装饰设计模式

1.定义

装饰设计模式是当要对已有对象进行功能增强时,可以定义一个新类,将已有对象传入;基于已有对象的功能提供加强功能;那么自定义的这个类就叫做装饰类。如第四部分自定义
readLine()
方法练习中,自定义的
MyBufferedReader
就是一个装饰类。

2.装饰和继承的区别

装饰类增强了原有类的功能,问题是为什么不直接继承原有类,并复写方法,在方法里增强该方法的功能?以一个例子说明装饰和继承的区别。

现在有一个继承体系,
MyReader
类是基类,用于读取数据;该基类有数个子类,
MyTextReader
MyMediaReader
MyDataReader
,分别用于读取文本、多媒体和数据库数据,已有继承体系结构如下:

MyReader

MyTextReader

MyMediaReader

MyDataReader

现发现三个子类的功能不够强大,要要加缓冲技术;按照继承的思想,那么就在三个子类下面再各自创建三个具备缓冲功能的子类,继承结构变为:

MyReader

MyTextReader

MyBufferedTextReader

MyMediaReader

MyBufferedMediaReader

MyDataReader

MyBufferedDataReader

这样做看似没有问题,但是缺点在于拥有缓冲功能的代码没有复用性,并导致继承体系结构庞大臃肿。因此,做好的做法不是创建子类,而是保持原有继承体系不变,将具备缓冲功能的代码提取出来,将需要增强的对象传递进来即可:

class MyBufferedReader {
MyBufferedReader(MyTextReader text) {}
MyBufferedReader(MyMediaReader media) {}
MyBufferedReader(MyDataReader data) {}
}


这样的做法已经简化了继承体系,同时增强了功能;但是后期
MyReader
基类下继续添加新的子类时,这个
MyBufferedReader
类还需修改;因此,应该使用多态的特性,在
MyBufferedReader
中只需接收
MyReader
类的对象即可;由于
MyBufferedReader
增强的是
MyReader
子类的功能,这些功能都是趋同的,因此最好让
MyBufferedReader
作为
MyReader
的子类,加入继承体系:

class MyBufferedReader extends MyReader{
MyBufferedReader(MyReader r) {}
}


新的继承结构如下:

MyReader

MyTextReader

MyMediaReader

MyDataReader

MyBufferedReader

装饰设计模式比继承灵活,避免了继承体系的复杂臃肿。

3.装饰设计模式特点

装饰设计模式灵活性强,在扩展原有类功能的前提下,不失原有类的方法,即后期开发中,扩展功能和原有功能都可以视情况使用。

———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: