天天看點

第21天 輸入字元流、輸出字元流、緩沖字元流、裝飾者模式

1.輸入字元流

1.1輸入輸出位元組流回顧

位元組流: 

輸入位元組流

----------| InputStream 輸入位元組流的基類   抽象類

-------------|FileInputStream 讀取檔案資料的輸入位元組流。

-------------|BufferedInputStream 緩沖輸入位元組流

緩沖輸入位元組流出現的目的: 為了提高讀取檔案資料的效率。 該類其實内部就是維護了一個8kb位元組數組而已。

輸出位元組流:

---------| OutputStream 輸出位元組流的基類。  抽象類。

--------------| FileOutStream  向檔案輸出資料的輸出位元組流。

--------------| BufferedOutputStream 緩沖輸出位元組流。  該類出現的目的是為了提高寫資料的效率 。 其實該類内部也是維護了一個8kb的數組而已,當調用其write方法的時候資料預設是向它内部的數組中存儲 的,隻有調用flush方法或者是close方法或者是8kb的位元組數組存儲滿資料的時候才會真正的向硬碟輸出。

使用位元組流讀取和寫入中文

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class Demo1 {
	public static void main(String[] args) throws IOException {
//		writeTest();
		readrTest();
	}
	//使用位元組流讀取中文
	public static void readrTest() throws IOException{
		//找到目标檔案
		File file = new File("F:\\a.txt");
		//建立資料的輸入通道
		FileInputStream fileInputStream = new FileInputStream(file);
		//讀取内容
		//int content = 0;
		/*while((content = fileInputStream.read())!=-1){ //出現亂碼的原因: 一個中文在gbk碼表中預設是占兩個位元組,
	   // 目前你隻讀取了一個位元組而已,是以不是一個完整的中文。
			System.out.print((char)content);
		}*/
		byte[] buf = new byte[2];
		for(int i = 0 ; i < 3 ; i++){
			fileInputStream.read(buf);
			System.out.print(new String(buf));
		}
		//關閉資源
		fileInputStream.close();
		
	}
	//使用位元組流寫中文。   位元組流之是以能夠寫中文是因為借助了字元串的getBytes方法對字 
符串進行了編碼(字元---->數字)。 
	public static void writeTest() throws IOException{
		//找到目标檔案
		File file = new File("F:\\a.txt");
		//建立資料的輸出通道
		FileOutputStream fileOutputStream  = new FileOutputStream(file);
		//準備資料,把資料寫出。
		String data = "大家好";
		byte[] buf = data.getBytes();	//把字元串轉換成位元組數組
		System.out.println("輸出的内容:"+ Arrays.toString(buf));
		fileOutputStream.write(buf);
		///關閉資源
		fileOutputStream.close();
	}
}
           

1.2字元流

計算機并不區分二進制檔案與文本檔案。所有的檔案都是以二進制形式來存儲的,是以,從本質上說,所有的檔案都是二進制檔案。是以字元流是建立在位元組流之上的,它能夠提供字元層次的編碼和解碼。例如,在寫入一個字元時,Java虛拟機會将字元轉為檔案指定的編碼(預設是系統預設編碼),在讀取字元時,再将檔案指定的編碼轉化為字元。

1.3常見的碼表如下:

ASCII:    美國标準資訊交換碼。用一個位元組的7位可以表示。

ISO8859-1: 拉丁碼表。歐洲碼表,用一個位元組的8位表示。又稱Latin-1(拉丁編碼)或“西歐語言”。ASCII碼是包含的僅僅是英文字母,并且沒有完全占滿256個編碼位置,是以它以ASCII為基礎,在空置的0xA0-0xFF的範圍内,加入192個字母及符号,

藉以供使用變音符号的拉丁字母語言使用。進而支援德文,法文等。因而它依然是一個單位元組編碼,隻是比ASCII更全面。

GB2312: 英文占一個位元組,中文占兩個位元組.中國的中文編碼表。

GBK:   中國的中文編碼表更新,融合了更多的中文文字元号。

Unicode:  國際标準碼規範,融合了多種文字。所有文字都用兩個位元組來表示,Java語言使用的就是unicode。

UTF-8:    最多用三個位元組來表示一個字元。

(我們以後接觸最多的是iso8859-1、gbk、utf-8)

檢視上述碼表後,很顯然中文的‘中’在iso8859-1中是沒有對映的編碼的。或者一個字元在2中碼表中對應的編碼不同,例如有一些字在不同的編碼中是有交集的,例如bjg5 和gbk 中的漢字簡體和繁體可能是一樣的,就是有交集,但是在各自碼表中的數字不一樣。

例如

使用gbk 将中文儲存在計算機中,

   中  國

對映 100  200   如果使用big5 打開

可能   ?  ...  

不同的編碼對映的是不一樣的。

很顯然,我們使用什麼樣的編碼寫資料,就需要使用什麼樣的編碼來對資料。

ISO8859-1:一個位元組

GBK: 兩個位元組包含了英文字元和擴充的中文 ISO8859-1+中文字元

UTF-8萬國碼,推行的。是1~3個位元組不等長。英文存的是1個位元組,中文存的是3個位元組,是為了節省空間。

位元組流:位元組流讀取的是檔案中的二進制資料,讀到的資料并不會幫你轉換成你看得懂的字元。

字元流: 字元流會把讀取到的二進制的資料進行對應 的編碼與解碼工作。   字元流= 位元組流 + 編碼(解碼)

輸入字元流:

----------| Reader 輸入字元流的基類   抽象類

-------------| FileReader 讀取檔案的輸入字元流。

FileReader的用法:

   1. 找到目标檔案

   2. 建立資料的輸入通道

   3. 讀取資料

   4. 關閉資源

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
	public static void main(String[] args) throws IOException {
		readTest2();
	}
	
	//使用緩沖字元數組讀取檔案。
	public static void readTest2() throws IOException{
		//找到目标檔案
		File file = new File("F:\\1208project\\day21\\src\\day21\\Demo1.java");
		// 建立資料的輸入通道
		FileReader fileReader = new FileReader(file);
		//建立緩沖字元數組讀取檔案資料
		char[] buf = new char[1024];
		int length = 0 ; 
		while((length = fileReader.read(buf))!=-1){
			System.out.print(new String(buf,0,length));
		}
	}
	public static void readTest1() throws IOException{
		//找到目标檔案
		File file = new File("F:\\1208project\\day21\\src\\day21\\Demo1.java");
		//建立資料的輸入通道
		FileReader fileReader = new FileReader(file);
		int content = 0 ;
		while((content = fileReader.read())!=-1){ //每次隻會讀取一個字元,效率低。
			System.out.print((char)content);
		}
		//關閉資源
		fileReader.close();
	}
}
           

1.4 Reader

方法:

intread():

讀取一個字元。傳回的是讀到的那個字元。如果讀到流的末尾,傳回-1.

intread(char[]):

将讀到的字元存入指定的數組中,傳回的是讀到的字元個數,也就是往數組裡裝的元素的個數。如果讀到流的末尾,傳回-1.

close()

讀取字元其實用的是window系統的功能,就希望使用完畢後,進行資源的釋放

由于Reader也是抽象類,是以想要使用字元輸入流需要使用Reader的實作類。檢視API文檔。找到了FileReader。

1,用于讀取文本檔案的流對象。

2,用于關聯文本檔案。

構造函數:在讀取流對象初始化的時候,必須要指定一個被讀取的檔案。

如果該檔案不存在會發生FileNotFoundException.

public class IoTest1_Reader {
	public static void main(String[] args) throws Exception {
		String path = "c:/a.txt";
		// readFileByInputStream(path);
		readFileByReader(path);
	}

	/**
	 * 使用位元組流讀取檔案内容
	 * @param path
	 */
	public static void readFileByInputStream(String path) throws Exception {
		InputStream in = new FileInputStream(path);

		int len = 0;
		while ((len = in.read()) != -1) {
			System.out.print((char) len);
		}

		in.close();
	}

	/**
	 * 使用字元流讀取檔案内容
	 */
	public static void readFileByReader(String path) throws Exception {
		Reader reader = new FileReader(path);
		int len = 0;
		while ((len = reader.read()) != -1) {
			System.out.print((char) len);
		}

		reader.close();
	}

}
           

2.輸出字元流

2.1 Writer

Writer中的常見的方法:

1) write(ch): 将一個字元寫入到流中。

2) write(char[]): 将一個字元數組寫入到流中。

3) write(String): 将一個字元串寫入到流中。

4) flush():重新整理流,将流中的資料重新整理到目的地中,流還存在。

5) close():關閉資源:在關閉前會先調用flush(),重新整理流中的資料去目的地。然流關閉。

發現基本方法和OutputStream 類似,有write方法,功能更多一些。可以接收字元串。

同樣道理Writer是抽象類無法建立對象。查閱API文檔,找到了Writer的子類FileWriter

1:将文本資料存儲到一個檔案中。

public class IoTest2_Writer {
	public static void main(String[] args) throws Exception {
		String path = "c:/ab.txt";

		writeToFile(path);
	}
	/**
	 * 寫指定資料到指定檔案中
	 * 
	 */
	public static void writeToFile(String path) throws Exception {
		Writer writer = new FileWriter(path);
		writer.write('中');
		writer.write("世界".toCharArray());
		writer.write("中國");

		writer.close();
	}
}
2:追加檔案:
預設的FileWriter方法新值會覆寫舊值,想要實作追加功能需要
使用如下構造函數建立輸出流 append值為true即可。
FileWriter(String fileName, boolean append)
FileWriter(File file, boolean append)
3:flush方法
	如果使用字元輸出流,沒有調用close方法,會發生什麼?
private static void writeFileByWriter(File file) throws IOException {
		FileWriter fw = new FileWriter(file);
		fw.write('新');
fw.flush();
		fw.write("中國".toCharArray());
		fw.write("世界你好!!!".toCharArray());
		fw.write("明天");	
		// 關閉流資源
		//fw.close();
	}
程式執行完畢打開檔案,發現沒有内容寫入.原來需要使用flush方法. 重新整理該流的緩沖。
為什麼隻要指定claose方法就不用再flush方法,因為close也調用了flush方法.
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
輸出字元流:
------| Writer 輸出字元流的基類。 抽象類
-----------| FileWriter 向檔案資料資料的輸出字元流
FileWriter的使用步驟:
	1. 找到目标檔案。
	2. 建立資料輸出通道
	3. 寫出資料。
	4. 關閉資源
FileWriter要注意的事項:
	1. 使用FileWriter寫資料的時候,FileWriter内部是維護了一個1024個字元數組的,寫資料的時候會先寫入到它内部維護的字元數組中,如果需要
	把資料真正寫到硬碟上,需要調用flush或者是close方法或者是填滿了内部的字元數組。
	2. 使用FileWriter的時候,如果目标檔案不存在,那麼會自動建立目标檔案。
	3.使用FileWriter的時候, 如果目标檔案已經存在了,那麼預設情況會先情況檔案中的資料,然後再寫入資料 , 如果需要在原來的基礎上追加資料,
	需要使用“new FileWriter(File , boolean)”的構造方法,第二參數為true。
public class Demo1 {
	public static void main(String[] args) throws IOException {
		writeTest1();
	}
	
	public static void  writeTest1() throws IOException{
		//找到目标檔案
		File file = new File("F:\\a.txt");
		//建立資料輸出通道
		FileWriter fileWriter = new FileWriter(file,true);
		//準備資料,把資料寫出
		String data = "今天天氣非常好!!";
		fileWriter.write(data);  //字元流具備解碼的功能。
		//重新整理字元流
//		fileWriter.flush();
		//關閉資源
		fileWriter.close();	
	}
}
           

3.字元流與位元組流拷貝檔案

練習: 使用字元流拷貝一個文本檔案(java檔案).

接着使用字元流拷貝一個圖檔(觀察圖檔的大小變化,思考為什麼會這樣子??)

何時使用字元流,何時使用位元組流?依據是什麼?

使用字元流的應用場景: 如果是讀寫字元資料的時候則使用字元流。

使用位元組流的應用場景: 如果讀寫的資料都不需要轉換成字元的時候,則使用位元組流。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//使用字元流拷貝檔案
public class Copy {
	public static void main(String[] args) throws IOException {
		BufferedReader bufferedReader = new BufferedReader(new FileReader("F:\\Test.txt"));
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("E:\\Test.exe"));
		String line=null;
		while((line = bufferedReader.readLine())!=null){
		bufferedWriter.write(line);
		}
		bufferedWriter.close();
		bufferedReader.close();
	}
}
使用位元組流讀取中文
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;

//使用位元組流讀取中文
public class Demo2 {

	public static void main(String[] args) throws IOException {
		File file = new File("F:\\a.txt");
		FileInputStream fileInputStream = new FileInputStream(file);
		byte[] buf = new byte[1024];
		int length = 0;
		while((length = fileInputStream.read(buf))!=-1){
			System.out.println(new String(buf,0,length)); //借用字元串的解碼功能。
		}
	}
}
           

4.緩沖輸入字元流

輸入字元流:

-------| Reader 所有輸入字元流的基類。 抽象類

----------| FileReader 讀取檔案字元串的輸入字元流。

----------|BufferedReader   緩沖輸入字元流  。 緩沖 輸入字元流出現的目的是為了提高讀取檔案 的效率和拓展了FileReader的功能。  其實該類内部也是維護了一個字元數組

記住:緩沖流都不具備讀寫檔案的能力。

BufferedReader的使用步驟:

   1.找到目标檔案

   2 .建立資料的輸入通道。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
public class Demo1 {
	public static void main(String[] args) throws IOException {
//		 readTest1();
		File file  = new File("F:\\ buffered\\Demo1.java");
		//建立資料的輸入通道。
		FileReader fileReader = new FileReader(file);
		String line =  null;
		while((line = myReadLine(fileReader))!=null){
			System.out.println(line);
		}
	}
	//自己去實作readLine方法。
	public static String myReadLine(FileReader fileReader) throws IOException{
		//建立一個字元串緩沖類對象
		StringBuilder sb = new StringBuilder();  //StringBuilder主要是用于存儲讀取到的資料
		int content = 0 ;
		while((content = fileReader.read())!=-1){
			if(content=='\r'){
				continue;
			}else if(content=='\n'){
				break;
			}else{
				//普通字元
				sb.append((char)content);
			}
		}
		//代表已經讀取完畢了。
		if(content ==-1){
			return null;
		}
		
		return sb.toString();  
	}
	public static void readTest1() throws IOException{
		//找到目标檔案
		File file  = new File("F:\\a.txt");
		//建立資料的輸入通道。
		FileReader fileReader = new FileReader(file);
		//建立緩沖輸入字元流
		BufferedReader bufferedReader = new BufferedReader(fileReader);
		//讀取資料
		/*int content = bufferedReader.read();  //讀到了一個字元。 讀取到的字元肯定也是從Bufferedreader内部的字元數組中擷取的到。是以效率高。
		System.out.println((char)content);*/
		//使用BUfferedReader拓展的功能,readLine()  一次讀取一行文本,如果讀到了檔案的末尾傳回null表示。
		String line =  null;
		while((line = bufferedReader.readLine())!=null){ // 雖然readLine每次讀取一行資料,但是但會的line是不包含\r\n的、
			System.out.println(Arrays.toString("aaa".getBytes()));
		}
		//關閉資源
		bufferedReader.close();
	}
}
           

5. 緩沖輸出字元流

輸出字元流

----------| Writer  所有輸出字元流的基類, 抽象類。

--------------- | FileWriter向檔案輸出字元資料的輸出字元流。

----------------|BufferedWriter 緩沖輸出字元流        

緩沖輸出字元流作用: 提高FileWriter的寫資料效率與拓展FileWriter的功能。

BufferedWriter内部隻不過是提供了一個8192長度的字元數組作為緩沖區而已,拓展了FileWriter的功能。

BufferedWriter如何使用?

   1. 找到目标檔案

   2. 建立資料的輸出通道

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo2 {
	public static void main(String[] args) throws IOException {
		//找到目标檔案
		File file = new File("F:\\a.txt");
		//建立資料的輸出通道
		FileWriter fileWriter = new FileWriter(file,true);
		//建立緩沖輸出流對象
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 
		//寫出資料
//		bufferedWriter.newLine(); //newLine() 換行。 實際上就是想檔案輸出\r\n.
		bufferedWriter.write("\r\n");
		bufferedWriter.write("前兩天李克強來蘿崗!!");
		//關閉資源
		bufferedWriter.flush();
//		bufferedWriter.close();
		
	}
}
           

6.緩沖輸入輸出字元流登入

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

import java.util.Scanner;
public class Login {
    static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        while (true) {
            System.out.println("請選擇功能: A(注冊)   B(登陸)");

            String option = scanner.next();
            if ("a".equalsIgnoreCase(option)) {
                //注冊
                reg();
            } else if ("b".equalsIgnoreCase(option)) {
                //登陸
                login();
            } else {
                System.out.println("你的輸入有誤,請重新輸入...");
            }
        }
    }
    //登陸
    public static void login() throws IOException {
        System.out.println("請輸入使用者名:");

        String userName = scanner.next();
        System.out.println("請 輸入密碼:");

        String password = scanner.next();
        String info = userName + " " + password;
        //讀取檔案的資訊,檢視是否有該使用者的資訊存在,如果存在則登陸成功。
        //建立資料的輸入通道
        //建立緩沖輸入字元流
        BufferedReader bufferedReader = new BufferedReader(new FileReader(
                    "F:\\users.txt"));
        String line = null;
        boolean isLogin = false; // 用于記錄是否登陸成功的辨別, 預設是登陸失敗的。
//不斷的讀取檔案的内容
        while ((line = bufferedReader.readLine()) != null) {
            if (info.equals(line)) {
                isLogin = true;
                break;
            }
        }
        if (isLogin) {
            System.out.println("歡迎" + userName + "登陸成功...");
        } else {
            System.out.println("不存在該使用者資訊,請注冊!!");
        }
    }
    //注冊
    public static void reg() throws IOException {
        System.out.println("請輸入使用者名:");
        String userName = scanner.next();
        System.out.println("請 輸入密碼:");
        String password = scanner.next();
        String info = userName + " " + password;
        //把使用者的注冊的資訊寫到檔案上
        File file = new File("F:\\users.txt");
        FileWriter fileWriter = new FileWriter(file, true);

        //建立緩沖輸出字元流
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        //把使用者資訊寫出
        bufferedWriter.write(info);
        bufferedWriter.newLine();
        //關閉資源
        bufferedWriter.close();
    }
}
           

7.裝飾者模式1

裝飾者設計模式:增強一個類的功能,而且還可以讓這些裝飾類互相裝飾。

 BufferedReader是不是拓展了FileReader的功能。

 BuferedWriter 也是拓展了FileWriter的功能。

 需求1: 編寫一個類拓展BufferedReader的功能,增強readLine方法傳回 的字元串帶有行号。

  需求2:編寫一個類拓展BufferedReader的功能,增強readLine方法傳回 的字元串帶有分号。

  需求3: 編寫一個類拓展BufferedReader的功能,增強readLine方法傳回 的字元串帶有雙引号。

需求4: 編寫一個類拓展BufferedReader的功能, 增強readLine方法傳回 的字元串帶有行号+ 分号。

需求5: 編寫一個類拓展BufferedReader的功能, 增強readLine方法傳回 的字元串帶有分号+ 雙引号。

 需求6: 編寫一個類拓展BufferedReader的功能,增強readLine方法傳回 的字元串帶有雙引号+ 行号。

需求7: 編寫一個類拓展BufferedReader的功能, 增強readLine方法傳回 的字元串帶有行号+ 分号+雙引号。

----| Reader

-----------| BufferedReader

---------------|BufferedLineNum  帶行号

---------------|BufferedSemi    帶分号

---------------|BufferedQuto   帶雙引

---------------| 子類..

---------------|

增強一個類的功能時候我們可以選擇使用繼承:

   通過繼承實作增強一個類的功能優點:   代碼結構清晰,通俗易懂。

   缺點: 使用不靈活,會導緻繼承的體系過于龐大。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

class BufferedLineNum extends BufferedReader {
    //行号
    int count = 1;

    public BufferedLineNum(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();

        if (line == null) {
            return null;
        }

        line = count + " " + line;
        count++;

        return line;
    }
}


//帶分号的緩沖輸入字元流
class BufferedSemi extends BufferedReader {
    public BufferedSemi(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();

        if (line == null) {
            return null;
        }

        line = line + ";";

        return line;
    }
}


//帶雙引号的緩沖輸入字元流
class BufferedQuto extends BufferedReader {
    public BufferedQuto(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();

        if (line == null) {
            return null;
        }

        line = "\"" + line + "\"";

        return line;
    }
}


public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("F:\\Demo1.java");

        //建立資料的輸入通道
        FileReader fileReader = new FileReader(file);

        //建立帶行号的緩沖輸入字元流
        BufferedLineNum bufferedLineNum = new BufferedLineNum(fileReader);

        //帶有分号的緩沖輸入字元流
        BufferedSemi bufferedSemi = new BufferedSemi(fileReader);

        //帶有雙引号的緩沖輸入字元流
        BufferedQuto bufferedQuto = new BufferedQuto(fileReader);

        String line = null;

        while ((line = bufferedQuto.readLine()) != null) {
            System.out.println(line);
        }
    }
}
           
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
/*
裝飾者設計模式:增強一個類的功能,而且還可以讓這些裝飾類互相裝飾。

裝飾者設計模式的步驟:
        1. 在裝飾類的内部維護一個被裝飾類的引用。
        2. 讓裝飾類有一個共同的父類或者是父接口。
繼承實作的增強類和修飾模式實作的增強類有何差別?
        繼承實作的增強類:
                優點:代碼結構清晰,而且實作簡單.
                缺點:對于每一個的需要增強的類都要建立具體的子類來幫助其增強,這樣會導緻繼承體系過于龐大。
修飾模式實作的增強類:
                優點:内部可以通過多态技術對多個需要增強的類進行增強, 可以是這些裝飾類達到互相裝飾的效果。使用比較靈活。
                缺點:需要内部通過多态技術維護需要被增強的類的執行個體。進而使得代碼稍微複雜。
*/
import java.io.IOException;

//帶行号的緩沖輸入字元流
class BufferedLineNum2 extends BufferedReader {
    //在内部維護一個被裝飾類的引用。
    BufferedReader bufferedReader;
    int count = 1;

    public BufferedLineNum2(BufferedReader bufferedReader) {
        super(bufferedReader); // 注意: 該語句沒有任何的作用,隻不過是為了讓代碼不報錯。
        this.bufferedReader = bufferedReader;
    }

    public String readLine() throws IOException {
        String line = bufferedReader.readLine();

        if (line == null) {
            return null;
        }

        line = count + " " + line;
        count++;

        return line;
    }
}
//帶分号緩沖輸入字元流
class BufferedSemi2 extends BufferedReader { //為什麼要繼承?  是為了讓這些裝飾類的對象可以作為參數進行傳遞,達到互相裝飾 的效果。

    //在内部維護一個被裝飾類的引用。
    BufferedReader bufferedReader;

    public BufferedSemi2(BufferedReader bufferedReader) { // new BuffereLineNum();
        super(bufferedReader); // 注意: 該語句沒有任何的作用,隻不過是為了讓代碼不報錯。
        this.bufferedReader = bufferedReader;
    }

    public String readLine() throws IOException {
        String line = bufferedReader.readLine(); //如果這裡的ReadLine方法是調用了buffereLineNum的readLine方法,問題馬上解決。
        if (line == null) {
            return null;
        }
        line = line + ";";
        return line;
    }
}

//緩沖類帶雙引号
class BufferedQuto2 extends BufferedReader {
    //在内部維護一個被裝飾的類
    BufferedReader bufferedReader;

    public BufferedQuto2(BufferedReader bufferedReader) { //new  BufferedSemi2();
        super(bufferedReader); //隻是為了讓代碼不報錯..
        this.bufferedReader = bufferedReader;
    }

    public String readLine() throws IOException {
        String line = bufferedReader.readLine(); //如果這裡的ReadLine方法是調用了buffereLineNum的readLine方法,問題馬上解決。
        if (line == null) {
            return null;
        }
        line = "\"" + line + "\"";
        return line;
    }
}
public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("F:\\Demo1.java");
        FileReader fileReader = new FileReader(file);

        //建立緩沖輸入字元流
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        //建立帶行号的緩沖輸入字元流
        BufferedLineNum2 bufferedLineNum = new BufferedLineNum2(bufferedReader);

        //帶分号的緩沖輸入字元流
        BufferedSemi2 bufferedSemi2 = new BufferedSemi2(bufferedLineNum);

        //帶雙引号的緩沖輸入字元流
        BufferedQuto2 bufferedQuto2 = new BufferedQuto2(bufferedSemi2);

        String line = null;

        while ((line = bufferedQuto2.readLine()) != null) {
            System.out.println(line);
        }
    }
}
           

8. 裝飾者設計模式的作業

一家三口每個人都會工作,兒子的工作就是畫畫,母親的工作就是在兒子的基礎上做一個增強,不單止可以畫畫,還可以上塗料。

        爸爸的工作就是在媽媽基礎上做了增強,就是上畫框。

interface Work {
    public void work();
}
class Son implements Work {
    @Override
    public void work() {
        System.out.println("畫畫...");
    }
}

class Mather implements Work {
    //需要被增強的類。
    Work worker;

    public Mather(Work worker) {
        this.worker = worker;
    }

    @Override
    public void work() {
        worker.work();
        System.out.println("給畫上顔色..");
    }
}


class Father implements Work {
    //需要被增強的類的引用
    Work worker;

    public Father(Work worker) {
        this.worker = worker;
    }

    @Override
    public void work() {
        worker.work();
        System.out.println("上畫框...");
    }
}


public class Demo3 {
    public static void main(String[] args) {
        Son s = new Son();

        //		s.work();
        Mather m = new Mather(s);

        //		m.work();
        Father f = new Father(s);
        f.work();
    }
}
           

繼續閱讀