API设计实例分析 通用IO API.

Slides:



Advertisements
Similar presentations
第四章 类、对象和接口.
Advertisements

3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
二十世紀 1940年 組員: 李宛倫 蔡佩君 李致柔 陳佩宜.
檔案處理.
Java的程式架構與基本觀念 Java語言的歷史 Java程式的開發環境 Java程式的架構 輸出與輸入物件之使用 工具使用方法介紹
Java Programming Hygiene - for DIDC
MVC Servlet与MVC设计模式.
算法设计与分析 Algorithm Design and Analysis
TQC+ 物件導向程式認證-JAVA.
第二章 JAVA语言基础.
任务2: 通报的写作.
创意源自激情,技术成就梦想 畅翼创新俱乐部 2012年春俱乐部第三次技术培训 赵程.
Introduction to MapReduce
Homework 4 an innovative design process model TEAM 7
程式設計實作.
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
Java语言程序设计 清华大学出版社 第9章 网络通信.
例外處理(Exception Handling)
Java 第28讲:建立删除文件 主讲教师:李焱 讲师.
Java基础 JavaSE异常.
JSP自定义标签技术的分析与应用 ----Custom Tag 的分析与应用
2018/11/20 第一章 Java概述 武汉大学计算机学院计算机应用系 2018/11/20 14:33.
崑山科技大學資訊管理系 伺服網頁程式設計 系統開發細部流程 教師:游峰碩.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
本單元介紹何謂變數,及說明變數的宣告方式。
西南科技大学网络教育系列课程 高级语程序设计(Java) 第五章 继承、接口与范型.
厦门大学数据库实验室 MapReduce 连接
程式設計實作.
创建型设计模式.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第九章 输入/输出流.
第 14 章 例外處理.
2018/12/3 面向对象与多线程综合实验-网络编程 教师:段鹏飞.
职责链模式.
Java语言程序设计 第五部分 Java异常处理.
Native Development Kit
王豐緒 銘傳大學資訊工程學系 問題:JAVA 物件檔輸出入.
第8章 Service解析.
第一次课后作业 1. C/C++/Java 哪些值不是头等程序对象 2. C/C++/Java 哪些机制采用的是动态束定
9.1 程式偵錯 9.2 捕捉例外 9.3 自行拋出例外 9.4 自定例外類別 9.5 多執行緒
3.1 数据类型 3.2 标识符与关键字 3.3 常量 3.4 变量 3.5 运算符与表达式 3.6 一个编程实例
异常及处理.
Java程序设计 第2章 基本数据类型及操作.
软件测试 第3章 测试用例设计 Kerry Zhu
第5讲 使用类和对象编程(三) 内部类 实例 程序控制结构 选择语句.
PubMed整合显示图书馆电子资源 医科院图书馆电子资源培训讲座.
C/C++/Java 哪些值不是头等程序对象
專題報告p6 組員:吳家齊    江弘喻.
P2P聊天工具.
4.2通讯服务模块线程之间传递信息 信息工程系 向模军 Tel: QQ:
Chapter 5 Recursion.
Wireshark DNS&HTTP封包分析
JAVA 编 程 技 术 主编 贾振华 2010年1月.
第7章 异常处理.
第二章 Java基本语法 讲师:复凡.
Inheritance -II.
Interfaces and Packages
2019/5/3 JAVA Socket(UDP).
第二章 Java语法基础.
第二章 Java基本语法 讲师:复凡.
 隐式欧拉法 /* implicit Euler method */
Java程序设计 第17章 异常和断言.
RecyclerView and CardView
C# 匿名委派 + Lambda + Func 建國科技大學 資管系 饒瑞佶.
助教:廖啟盛 JAVA Socket(UDP) 助教:廖啟盛
第2章 Java语言基础.
第4讲 类和对象、异常处理 ggao.
讀取網路資料及JSON開放資料 靜宜大學資管系 楊子青
東吳大學『樂齡大學』 外雙溪環境與生態 產業 黃顯宗 東吳大學 微生物學系 101.
第二章 Java基础语法 北京传智播客教育
Summary
Presentation transcript:

API设计实例分析 通用IO API

目录 IO API设计实例分析 IO API实现说明 成本收益分析 IO要解决的功能 典型场景,划分功能 接口整理 标准使用方式(客户) 拦截[传输]过程 IO API实现说明 成本收益分析

IO API设计实例分析

IO要解决的功能 多数据类型 String、Byte[]、领域对象 多数据来源 文件、SPI Provider 异常处理、善后虚处理(如资源释放) IO类型转换 附加分析:IO计数等等

典型场景,划分功能 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: try { 4: BufferedWriter writer = new BufferedWriter(new FileWriter(destination)); 4: try { 2: String line = null; 2: while ((line = reader.readLine()) != null) { 3: count++; 4: writer.append( line ).append( '\n' ); 2: } 4: writer.close(); 4: } catch (IOException e) { 4: destination.delete(); 4: } 2: } finally { 2: reader.close(); 2: } 3: System.out.println(count) 典型场景读文件然后写入另一个文件 1. 客户代码,初始化了传输,要知道输入和输出的源。 2. 从输入中读的代码。 3. 辅助代码,用于跟踪整个过程。这些代码我希望能够重用,而不管是何种传输的类型。 4. 最后这个部分是接收数据,写数据。 这个代码,我要批量读写,可以在第2第4部分修改,改成一次处理多行。 明确上面划分的内容,剩下就只是为每个部分整理成一个接口,并保证在各种场景能方便使用。

接口整理(1)——输入 public interface Input<T, SenderThrowableType extends Throwable> { <ReceiverThrowableType extends Throwable> void transferTo( Output<T,ReceiverThrowableType> output ) throws SenderThrowableType, ReceiverThrowableType; } 首先要有输入,即Input接口 Input,如Iterables,可以被多次使用,用于初始化一处到另一处的传输。因为我泛化传输的数据类型为T,所以可以是任何类型(byte[]、String、EntityState、MyDomainObject)。为了让发送者和接收者可以抛出各自的异常,接口上把各自己的异常声明成了类型参数。比如:在出错的时,Input抛的可以是SQLException,Output抛的是IOException。异常是强类型的,并且在出错时发送和接收双方都必须知道的,这使的双方做合适的恢复操作,关闭他们打开了的资源。

接口整理(2)——输出 public interface Output<T, ReceiverThrowableType extends Throwable> { <SenderThrowableType extends Throwable> void receiveFrom( Sender<T, SenderThrowableType> sender) throws ReceiverThrowableType, SenderThrowableType; } 在接收端的是Output接口 当receiveFrom方法被Input调用时(通过调用Input的transferTo方法触发),Output应该打开好了它所需要的资源,然后期望数据从Sender发送过来。Input和Output必须要有类型T,两者对要发送的内容达到一致。后面我们可以看到如何处理不一致的情况。

接口整理(3)——发送者 Sender<T, SenderThrowableType extends Throwable> public interface Sender<T, SenderThrowableType extends Throwable> { <ReceiverThrowableType extends Throwable> void sendTo( Receiver<T, ReceiverThrowableType> receiver) throws ReceiverThrowableType, SenderThrowableType; } 接下来是Sender接口 Output调用sendTo方法,传入一个Receiver,Sender使用这个Receiver来发送一个一个的数据。

接口整理(4)——接受者 public interface Receiver<T, ReceiverThrowableType extends Throwable> { void receive(T item) throws ReceiverThrowableType; } 当Receiver从Sender收到数据时,即可以马上写到底层资源中,也可以分批写入。Receiver知道传输什么时候结束(sendTo方法返回了),所以正确写入剩下的分批数据、关闭持有的资源。 这个简单的模式在发送方和接收方各有2个接口,并保持了以可伸缩、高性能和容错的方式传输数据的潜能。

标准使用方式(客户) 根据契约,然后可以制定几个输入输出(I/O)的标准。 比如:从文本文件中读取文本行后再写成文本文件。 这个操作可以静态方法中,方便的重用。 最后,拷贝文本文件可以写成: File source = ... File destination = ... Inputs.text( source ) .transferTo( Outputs.text(destination) ); 上文的API定义了数据发送和接收的契约,然后可以制定几个输入输出(I/O)的标准。比如:从文本文件中读取文本行后再写成文本文件。这个操作可以静态方法中,方便的重用。最后,拷贝文本文件可以写成: 一行代码处理了读文件、写文件、资源清理和其它零零碎碎的操作。真心的赞! transferTo方法会抛出IOException,要向用户显示Error可以catch这个异常。但实际处理这些Error往往是,关闭文件,把没有写成功的文件删除,而这些Input、Output已经处理好了。 我们再也不需要关心文件读写的细节!

拦截[传输]过程——过滤的API interface Specification<T> { public static <T, ReceiverThrowableType extends Throwable> Output<T, ReceiverThrowableType> filter( final Specification<T> specification, final Output<T, ReceiverThrowableType> output) { // create an Output that filters items // based on the Specification<T> ... } interface Specification<T> { boolean test(T item); 上面处理了基本的I/O传输,我们常常还要做些其它的事。可能要计数一下传输了多少个数据,过滤一下数据,或者是每1000条数据做一下日志,又或者要看一下正在进行什么操作。既然输入输出已经分离,这些事变成在输入输出的协调代码中简单地插入一些逻辑。大部分协调代码有类似的功能,可以放到标准的工具方法中,更方便使用。

拦截[传输]过程——过滤的使用代码 下面的例子删除文件中的空行: File source = ... File destination = ... Inputs.text( source ).transferTo( Transforms.filter(new Specification<String>() { public boolean test(String string) return string.length() != 0; } }, Outputs.text(destination) ); 有了这个简单部件,我可以在传输时轻松地过滤掉那些不要出现在接收者端的数据。

拦截[传输]过程——传输类型转换的API public static <From,To,ReceiverThrowableType extends Throwable> Output<From, ReceiverThrowableType> map( final Function<From,To> function, final Output<To, ReceiverThrowableType> output) {...} interface Function<From, To> { To map(From from); } 第二个常见的操作是把数据从一个类型映射到另一个类型。就是处理要Input和Output的数据类型不同,要有方法把输入数据类型映射成输出的数据类型。下面例子的把String映射成JSONObject,操作方法会是这个样子:

拦截[传输]过程——传输类型转换的使用代码 Input<String,IOException> input = ...; Output<JSONObject,RuntimeException> output = ...; input.transferTo( Transforms.map(new String2JSON(), output); File source = ... File destination = ... Counter<String> counter = new Counter<String>(); Inputs.text( source ).transferTo( Transforms.map(counter, Outputs.text(destination) )); System.out.println("Nr of lines:"+counter.getCount()) String的Input连接到JSONObject的Output String2JSON类实现了Function接口,它的map方法把String转换成JSONObject。 实现前面提到数据计数的例子,可以把计数实现成一个通用的映射,转换前后的类型不变,只是维护了一个计数,在每次调用map方法时更新计数。

IO API实现说明

实现说明 & Demo http://oldratlee.com/493/tech/java/java-api-design- exercise.html https://bitbucket.org/oldrat/io-api

成本收益分析

成本 分析好领域 需要让实现者理解保持一致 适当的文档让其它人了解你的设计 术语约定 分解方式

收效 DRY KISS(客户API简单,实现涉及较多内容) 分离的功能 资源维护 和 操作分离(IO资源维护和IO操作分离) 核心功能 和 修饰性功能 分离功能之间功能方法参数关联起来,即外围功能持 有依赖功能,组合方式(非继承)。 各个功能有明确的接口,且是组合的,所以可以方便 Wrap,方便拦截加入修饰性功能。 同时整理出了API(外围接口)和SPI(内部接口)

引申 客户类不需要继承框架内的类 客户 观察不到的 不要 出现在 API中 API使用方式 是 客户直觉期望使用方式 从框架继承来的代码属于框架 框架应该从客户类提取需要的逻辑拼装运行 客户类不需要从框架继承额外的逻辑 客户 观察不到的 不要 出现在 API中 API使用方式 是 客户直觉期望使用方式

参考资料 How to Design a Good API and Why it Matters(by Joshua Bloch) http://lcsd05.cs.tamu.edu/slides/keynote.pdf The Little Manual of API Design http://chaos.troll.no/~shausman/api-design/api-design.pdf Practical API Design: Confessions of a Java Framework Architect http://www.amazon.com/Practical-API-Design-Confessions-Framework/dp/1430243171 Google Search http://www.google.com.hk/search?&q=api+design Joshua Bloch 是 《Effective Java》作者。 《The Little Manual of API Design》第三章“The Design Process”,可以实际操作: 1 Know the requirements 2 Write use cases before you write any other code 3 Look for similar APIs in the same library 4 Define the API before you implement it 5 Have your peers review your API 6 Write several examples against the API 7 Prepare for extensions 8 Don’t publish internal APIs without review 9 When in doubt, leave it out

The Design Process 《The Little Manual of API Design》第三章“The Design Process”,可以实际操作: Know the requirements Write use cases before you write any other code Look for similar APIs in the same library Define the API before you implement it Have your peers review your API Write several examples against the API Prepare for extensions Don’t publish internal APIs without review When in doubt, leave it out