Java I/O通用api設計 (一)

來源:互聯網
上載者:User

原文A
generic input/output API in Java(by Rickard Öberg)中給出了一個通用Java IO API設計,並且有API的Demo代碼。更重要的一點是,這篇文章給出實現這個API設計本身的步驟和過程,這讓API設計實現過程有了條理。文中示範了從
普通簡單實現 整理成 正確分解、可以複用、可擴充的API設計 的過程。這個很值得理解和學習! PS: 設計偏向是藝術,一個賞心悅目的設計,尤其是API設計,旁人看來多是妙手偶得的感覺,如果有些章可循真是一件好事。給出 減少藝術的藝術工作量的方法的人是大師。

大家應該都寫過java的IO代碼,我覺得那些代碼都醜的不行,充斥了很多業務無關的代碼,很多的try catch。但是想要抽象的時候往往又無從下手。讓我們看一個讀檔案然後寫入另一個檔案的典型情境,看看能不能從中發現包含了哪幾個部分。

1: File source = new File( getClass().getResource( "/iotest.txt" ).getFile() );1: File destination = File.createTempFile( "test", ".txt" );1: destination.deleteOnExit();2: BufferedReader reader = new BufferedReader(new FileReader(source));3: long count = 0;2: try2: {4:    BufferedWriter writer = new BufferedWriter(new FileWriter(destination));4:    try4:    {2:        String line = null;2:        while ((line = reader.readLine()) != null)2:        {3:            count++;4:            writer.append( line ).append( '\n' );2:        }4:        writer.close();4:    } catch (IOException e)4:    {4:        writer.close();4:        destination.delete();4:    }2: } finally2: {2:     reader.close();2: }1: System.out.println(count)

行左邊的數字是我標識的4個部分。

  1. 客戶代碼,初始化了傳輸,要知道輸入和輸出的源。
  2. 從輸入中讀的代碼。
  3. 輔助代碼,用於跟蹤整個過程。這些代碼我希望能夠重用,而不管是何種傳輸的類型。
  4. 最後這個部分是接收資料,寫資料。這個代碼,我要批量讀寫,可以在第2第4部分修改,改成一次處理多行。
API

一旦明確上面劃分的內容,剩下就只是為每個部分整理成一個介面,並保證在各種情境能方便使用。結果如下。 首先要有輸入,即Input介面:

public interface Input<T, SenderThrowableType extends Throwable>{    <ReceiverThrowableType extends Throwable> void transferTo( Output<T,ReceiverThrowableType> output )        throws SenderThrowableType, ReceiverThrowableType;}

Input,如Iterables,可以被多次使用,用於初始化一處到另一處的傳輸。因為我泛化傳輸的資料類型為T,所以可以是任何類型(byte[]、String、EntityState、MyDomainObject)。為了讓寄件者和接收者可以拋出各自的異常,介面上把各自己的異常聲明成了型別參數。比如:在出錯的時,Input拋的可以是SQLException,Output拋的是IOException。異常是強型別的,並且在出錯時發送和接收雙方都必須知道的,這使的雙方做合適的恢複操作,關閉他們開啟了的資源。

在接收端的是Output介面:

public interface Output<T, ReceiverThrowableType extends Throwable>{    <SenderThrowableType extends Throwable> void receiveFrom(Sender<T, SenderThrowableType> sender)            throws ReceiverThrowableType, SenderThrowableType;}

當receiveFrom方法被Input調用時(通過調用Input的transferTo方法觸發),Output應該開啟好了它所需要的資源,然後期望資料從Sender發送過來。Input和Output必須要有類型T,兩者對要發送的內容達到一致。後面我們可以看到如何處理不一致的情況。

接下來是Sender介面:

public interface Sender<T, SenderThrowableType extends Throwable>{    <ReceiverThrowableType extends Throwable> void sendTo(Receiver<T, ReceiverThrowableType> receiver)        throws ReceiverThrowableType, SenderThrowableType;}

Output調用sendTo方法,傳入一個Receiver,Sender使用這個Receiver來發送一個一個的資料。Sender在這個時候發起傳輸,把類型資料T傳輸到Receiver,一次一個。Receiver介面如下:

public interface Receiver<T, ReceiverThrowableType extends Throwable>{    void receive(T item)        throws ReceiverThrowableType;}

當Receiver從Sender收到資料時,即可以馬上寫到底層資源中,也可以分批寫入。Receiver知道傳輸什麼時候結束(sendTo方法返回了),所以正確寫入剩下的分批資料、關閉持有的資源。

這個簡單的模式在發送方和接收方各有2個介面,並保持了以可伸縮、高效能和容錯的方式傳輸資料的潛能。

標準化I/O

上文的API定義了資料發送和接收的契約,然後可以制定幾個輸入輸出(I/O)的標準。比如:從文字檔中讀取文本行後再寫成文字檔。這個操作可以靜態方法中,方便的重用。最後,拷貝文字檔可以寫成:

File source = ...File destination = ...Inputs.text( source ).transferTo( Outputs.text(destination) );

一行代碼處理了讀檔案、寫檔案、資源清理和其它零零碎碎的操作。真心的贊!transferTo方法會拋出IOException,要向使用者顯示Error可以catch這個異常。但實際處理這些Error往往是,關閉檔案,把沒有寫成功的檔案刪除,而這些Input、Output已經處理好了。我們再也不需要關心檔案讀寫的細節!

下面是實現的代碼

Input的實現:

public  class FileInput implements Input<String,IOException> {    final File source;    final Reader reader;    public FileInput(File source) throws IOException {        this.source = source;        reader = new FileReader(source);    }    public <ReceiverThrowableType extends Throwable> void transferTo(Output<String, ReceiverThrowableType> output)            throws IOException, ReceiverThrowableType {        final StringSender sender = new StringSender(reader);        output.receiveFrom(sender);        try {            reader.close();        } catch (Exception e) {            // ignore close exception          }    }}

Output的實現:

public class FileOutput implements Output<String, IOException> {    final File destination;    final Writer writer;    public FileOutput(File destination) throws IOException {        this.destination = destination;        writer = new FileWriter(destination);    }    public <SenderThrowableType extends Throwable> void receiveFrom(Sender<String, SenderThrowableType> sender)            throws IOException, SenderThrowableType {        final StringReceiver receiver = new StringReceiver(writer);        sender.sendTo(receiver);        receiver.finished();        try {            writer.close();        } catch (Exception e) {            // ignore close exception        }    }}

Sender的實現:

public class StringSender implements Sender<String,IOException> {    final Reader reader;    BufferedReader bufferReader;    public StringSender(Reader reader) throws FileNotFoundException {        this.reader = reader;        this.bufferReader = new BufferedReader(reader);    }    @Override    public <ReceiverThrowableType extends Throwable> void sendTo(Receiver<String, ReceiverThrowableType> receiver)            throws ReceiverThrowableType, IOException {        String readLine;        while((readLine = bufferReader.readLine()) != null) {            receiver.receive(readLine + "\n");        }    }}

Receiver的實現:

public class StringReceiver implements Receiver<String, IOException> {    final Writer writer;    public StringReceiver(Writer writer) throws IOException {        this.writer = writer;    }    @Override    public void receive(String item) throws IOException {        writer.write(item);    }    public void finished() throws IOException {    }}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.