道阻且長,行則將至。埋頭苦幹,不鳴則已,一鳴驚人!加油,騷年!
目錄及資源索引
1 處理流使用實例
參考老師課件,具體解釋內容如下圖:
全稱:字符輸入處理流;使用這個類的時候,大部分都是爲了使用其中這個方法:如上圖所示,讀取一行。
比如有一個類似這樣的文件需要處理,每一行都是一個用戶的信息
張三 F 20
李四 M 21
王五 F 22
趙六 M 23
這個時候,讀取這個文件怎樣最方便?當然是一次讀取一行;這樣就可以利用上述函數;
那麼具體的使用方法是怎麼樣的呢?生成方法,接收的是一個 Reader 類的對象,下邊用代碼實驗如下:
import java.io.*;
class Test
{
public static void main(String args[])
{
FileReader fileReader = null;
BufferedReader bufferedReader = null;
try
{
fileReader = new FileReader("users.txt");
bufferedReader = new BufferedReader(fileReader);
String line = bufferedReader.readLine();
System.out.println(line);
}
catch(Exception e)
{
System.out.println(e);
}
finally
{
try
{
fileReader.close();
bufferedReader.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
}
上述代碼,編譯運行後結果如下:
可以看到第一次出現了亂碼,即使之前是加上了編譯所使用的字符集,還是不可以。後來發現,
- 第一次出現亂碼,users.txt 文本的編碼爲 UTF-8 編碼;
- 第二次正常顯示,是此文本編碼修改爲 ANSI 後,恢復正常;
- 具體原因暫時未知。
如何把這幾行內容,全部打印出來呢?修改部分代碼如下,我們只需要增加一個 while 循環即可
import java.io.*;
class Test
{
public static void main(String args[])
{
FileReader fileReader = null;
BufferedReader bufferedReader = null;
try
{
fileReader = new FileReader("users.txt");
bufferedReader = new BufferedReader(fileReader);
String line = null;
while(true)
{
line = bufferedReader.readLine();
if(null == line)
{
break;
}
System.out.println(line);
}
}
catch(Exception e)
{
System.out.println(e);
}
finally
{
try
{
fileReader.close();
bufferedReader.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
}
上述代碼,編譯運行後的結果如下:
這個函數什麼時候返回 NULL 呢?當讀到末尾的時候,就返回 NULL ;
上述就是所謂的處理流,凡是要使用處理流的,都必須首先有一個節點流。
2 “裝飾者(Decorator)”模式
2.1 示例演示
老師舉了一個例子,先來一步一步深入,具體如下:
疑問:當工人的類別,及工人所屬的公司,越來越多時,怎麼辦呢?
此時可以先定義一個 Worker 的接口,代碼如下:
interface Worker
{
public void doSomeWork();
}
接着定義一個修水管的類,Plumber,此類繼承 Worker 接口,需要實現父類中的函數,具體代碼如下:
class Plumber implements Worker
{
public void doSomeWork()
{
System.out.println("修水管");
}
}
接着定義一個木工類,修門窗的,Carpenter,同樣繼承 Worker 接口,需要實現父類中的函數,具體代碼如下:
class Carpenter implements Worker
{
public void doSomeWork()
{
System.out.println("修門窗");
}
}
然後定義一個子類 AWorker,繼承 Worker ,相當於是 A 公司的員工,同樣需要實現父類中的函數,還需要加上一個構造函數(參數類型爲父類 Worker),此時代碼如下:
class AWorker implements Worker
{
private Worker worker;
public AWorker(Worker worker)
{
this.worker = worker;
}
public void doSomeWork()
{
System.out.println("你好");
worker.doSomeWork();
}
}
最後定義一個有主函數的類,生成一個 A 公司修水管的工人,此時需要向上轉型,具體代碼如下:
class Test01
{
public static void main(String args[])
{
// 生成一個A公司水管工對象
Plumber plumber = new Plumber();
AWorker aWorker = new AWorker(plumber); // 向上轉型
aWorker.doSomeWork();
}
}
最後代碼編譯運行結果如下:
分析一下,在 AWorker 中有一個 Worker 的引用,其實這是一個面向對象的思想,不使用繼承,而是在 A 公司這個類中,有 Worker 的一個成員變量;好處是什麼呢?通用性;假如此時要生成一個 A 公司的木匠工,此時就可以使用這個通用的類,只是傳進去的參數類型爲木匠工向上轉型後的類型。
上代碼看一下,就一目瞭然了,如下:
class Test01
{
public static void main(String args[])
{
// 生成一個A公司水管工對象
Plumber plumber = new Plumber();
AWorker aWorker = new AWorker(plumber); // 向上轉型
aWorker.doSomeWork();
Carpenter carpenter = new Carpenter();
AWorker aWorker2 = new AWorker(carpenter);
aWorker2.doSomeWork();
}
}
上述代碼,編譯運行後,結果如下,可以看到木匠的修門窗,也打印出來了。
2.2 示例分析
上述示例,已經演示完畢,那麼我的疑問來了,感覺有很多不理解的地方,比如:
- 爲什麼要這麼設計?好處是什麼?
- 目前看來定義了很多類,感覺很複雜呀,可是我目前不需要這麼複雜、這麼多的類,就能實現功能了呀?
別慌,我們仔細理解,分析一下就很容易得出結論,面向對象編程的終極目標是什麼?消除程序中的重複代碼;好了,這就讓我們來解答之前的問題:
- 這樣設計,便於後續擴展,便於消除重複代碼!
- 不要被目前的需求侷限了思維,目前只是舉這麼簡單一個例子,如果我們寫出來一個程序,後續隨着用戶量增加,產品需求增加,需要改變時,還要重構一遍代碼,那就很麻煩了。就像天宮一號空間站一樣,每次送上去的肯定是留有一個或多個對接下次設備的接口,如果你直接就封死了,後續再要發射設備,怎麼辦???哈哈,道理就是這麼個樣子。
那麼先消除上邊這些疑問,再來分析一下這樣寫的意義,個人感覺的有如下幾個方面
- 雖然剛開始看起來要定義很多類,很複雜,但其實不然;
- 把共同的部分,一層一層的抽出來,比如最抽象的,大家都是工人;其次再分水管工、木匠工;接着可以再分 A 公司的水管工、木匠工,B 公司的水管工、木匠工;等等
- 這樣把公共的抽出來,最抽象的就可以作爲父類,就像大家交流的一個通道似的;舉個例子,我在深圳,就是深圳人,你在鄭州就是鄭州人;深圳是廣東省的,鄭州是河南省的;而廣東又是中國的,河南也是中國的,你看,我們倆的聯繫/共同點不就出來了嗎?這樣我們對外,就可以一致的說,我是中國人!
- 在進一步的分析,你在河南省new出一個對象,我在廣東省new出來一個對象;這樣你的就是中國河南省的對象,我的就是中國廣東省的對象,哈哈哈哈;
3 總結
- 上述示例,都是自己根據自己的理解想象出來的,如果有誤,還望多多指教~
- 裝飾者模式:把類似 AWorker 這種類稱爲裝飾者,把木匠等稱爲被裝飾者;
- 壓縮流,實現壓縮和解壓縮文件;
- 裝飾者模式,理解還不夠深入,後續有時間,要進一步深入瞭解一下,或者結合實踐,多多練習!加油啦~
如果文章內容有誤,麻煩評論/私信多多指教,謝謝!如果覺得文章內容還不錯,留個讚唄,您的點贊就是對我最大的鼓勵,謝謝您嘞!