Google首席软件工程师Joshua Bloch谈如何设计一款优秀的API【附PPT】

时间:2014-02-18 18:00:51   收藏:0   阅读:836

编者按】随着近来软件规模的日益庞大,API编程接口的设计变的越来越重要。良好的接口设计可以降低系统各部分之间的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合度,从而提高系统的维护性和稳定性。

Joshua Bloch是美国著名程序式设计师。他为Java平台设计并实现了许多的功能,是Google的首席Java架构师(Chief Java Architect)。他也是《Effective Java Programming Language Guide》一书的作者,就是人们常说的Effective Java。本文翻译自Joshua Bloch所发表的一个PPT: How to Design a Good API and Why it Matters

随着大数据、公共平台等互联网技术的日益成熟,API接口的重要性日益凸显,从公司的角度来看,API可以算作是公司一笔巨大的资产,公共API可以捕获用户、为公司做出许多贡献。对于个人来说,只要你编程,你就是一个API设计者,因为好的代码即是模块——每个模块便是一个API,而好的模块会被多次使用。此外,编写API还有利于开发者提高代码质量,提高自身的编码水平。

优秀API所具备的特征


 

 

了解了一款优秀API所具备的特征后,一起再来看看如何设计优秀的API,有哪些流程和规则可循,开发者在设计时需要注意哪些事项。

API设计流程中的注意事项


征集需求 

在开始之前,你可能会收到一些解决方案,它们不一定会比现有的方案好,而你的任务是以用例的形式提取真实需求,并制定真正合适的解决方案,这样构建出来的东西就会更加有价值。

从简短的说明开始

这时,编写简短的说明最为合适,编写时需要考虑的因素有:

 

 

 

 

尽早编写API

 

 

 

 

编写SPI尤为重要

 

 

 

维护切实可行的期望

 

 

 

API设计原则


每个API接口应该只专注一件事,并做好:如果它很难命名,那么这或许是个不好的征兆,好的名称可以驱动开发、并且只需拆分与合并模块即可

 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. if (car.speed() > 2 * SPEED_LIMIT)  
  2.  generateAlert("Watch out for cops!");  

重视文档

开发API时要意识到文档的重要性。组件重用不是纸上谈兵的东西,既需要好的设计,也需要优秀的文档,这二者缺一不可,即使我们看到了良好的设计而未见文档,那么组件重用也是不妥的。

——摘自 D. L. Parnas 在1994年第16届国际软件开发大会上的演讲内容

文档应包含每个类、接口、方法、构造函数、参数和异常,此外,还要小心对待文档的状态空间。

API设计决策对性能的影响

 

 

API与平台和平共处

 

 

API中类的设计


最小化可变性

 

 

子类只存在有意义的地方

 

 

用于继承的设计和文档或者直接禁止继承(Design and Document for Inheritance or Else Prohibit it

 

 

API中的方法设计


模块能做到的,客户端就不要做

 

 

减少模板代码的使用: 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. import org.w3c.dom.*;  
  2.  import java.io.*;  
  3.  import javax.xml.transform.*;  
  4.  import javax.xml.transform.dom.*;  
  5.  import javax.xml.transform.stream.*;  
  6.  // DOM code to write an XML document to a specified output stream.  
  7.  private static final void writeDoc(Document doc, OutputStream out)throws IOException{  
  8.  try {  
  9.  Transformer t = TransformerFactory.newInstance().newTransformer();  
  10.  t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId());  
  11.  t.transform(new DOMSource(doc), new StreamResult(out));  
  12.  } catch(TransformerException e) {  
  13.  throw new AssertionError(e); // Can’t happen!  
  14.  }  
  15.  }  

遵守最小惊讶原则

 

 

用户API只需根据需求来设计即可,不必让客户感到惊讶,小心弄巧成拙: 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public class Thread implements Runnable {  
  2.  // Tests whether current thread has been interrupted.  
  3.  // Clears the interrupted status of current thread.  
  4.  public static boolean interrupted();  
  5.  }  

故障快速报告应尽快生成

 

 

 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. // A Properties instance maps strings to strings  
  2.  public class Properties extends Hashtable {  
  3.  public Object put(Object key, Object value);  
  4.  // Throws ClassCastException if this properties  
  5.  // contains any keys or values that are not strings  
  6.  public void save(OutputStream out, String comments);  
  7.  }  

以String形式对所有可用数据提供编程式访问

 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public class Throwable {  
  2.  public void printStackTrace(PrintStream s);  
  3.  public StackTraceElement[] getStackTrace(); // Since 1.4  
  4. }  
  5. public final class StackTraceElement {  
  6.  public String getFileName();  
  7.  public int getLineNumber();  
  8.  public String getClassName();  
  9.  public String getMethodName();  
  10.  public boolean isNativeMethod();  
  11. }  

方法重载要细心

 

 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public TreeSet(Collection c); // Ignores order  
  2. public TreeSet(SortedSet s); // Respects order  

使用合适的参数和返回类型

 

 

[cpp] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. #include <string.h>  
  2.  char *strcpy (char *dest, char *src);  
  3.  void bcopy (void *src, void *dst, int n);  
java.util.Collections – first parameter always collection to be modified or queried 
 java.util.concurrent – time always specified as long delay, TimeUnit unit

避免使用长参数列表

 

 

 

 

最好避免这种情况出现:

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. // Eleven parameters including four consecutive ints  
  2. HWND CreateWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName,  
  3.  DWORD dwStyle, int x, int y, int nWidth, int nHeight,  
  4.  HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);  

返回值勿需进行异常处理

比如,返回零长度字符串或者空集合

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. package java.awt.image;  
  2.  public interface BufferedImageOp {  
  3.  // Returns the rendering hints for this operation,  
  4.  // or null if no hints have been set.  
  5.  public RenderingHints getRenderingHints();  
  6.  }  

API中的异常设计

 


 

抛出异常来说明异常状况;不要强迫客户端使用异常来控制流。

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. private byte[] a = new byte[BUF_SIZE];  
  2.  void processBuffer (ByteBuffer buf) {  
  3.  try {  
  4.  while (true) {  
  5.  buf.get(a);  
  6.  processBytes(tmp, BUF_SIZE);  
  7.  }  
  8.  } catch (BufferUnderflowException e) {  
  9.  int remaining = buf.remaining();  
  10.  buf.get(a, 0, remaining);  
  11.  processBytes(bufArray, remaining);  
  12.  }  
  13.  }  

Conversely, don’t fail silently 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. ThreadGroup.enumerate(Thread[] list)  

支持Unchecked Exceptions

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. try {  
  2.  Foo f = (Foo) super.clone();  
  3.  ....  
  4. catch (CloneNotSupportedException e) {  
  5.  // This can‘t happen, since we’re Cloneable  
  6.  throw new AssertionError();  
  7. }  

异常中应该包含捕获错误的(Failure-Capture)信息

 

 

 

 

重构API设计

 

 


 

 

 

 

 

 

 

在Vector中进行Sublist操作 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public class Vector {  
  2.  public int indexOf(Object elem, int index);  
  3.  public int lastIndexOf(Object elem, int index);  
  4.  ...  
  5. }  

分析:

 

 

 

 

 

重构Sublist操作 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public interface List {  
  2.  List subList(int fromIndex, int toIndex);  
  3.  ...  
  4. }  

分析:

 

 

 

 

线程局部变量 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. // Broken - inappropriate use of String as capability.  
  2. // Keys constitute a shared global namespace.  
  3. public class ThreadLocal {  
  4. private ThreadLocal() { } // Non-instantiable  
  5. // Sets current thread’s value for named variable.  
  6. public static void set(String key, Object value);  
  7. // Returns current thread’s value for named variable.  
  8. public static Object get(String key);  
  9. }  

线程局部变量重构1

 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public class ThreadLocal {  
  2. private ThreadLocal() { } // Noninstantiable  
  3. public static class Key { Key() { } }  
  4. // Generates a unique, unforgeable key  
  5. public static Key getKey() { return new Key(); }  
  6. public static void set(Key key, Object value);  
  7. public static Object get(Key key);  
  8. }  

可以运行,但是需要使用模板代码。 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. static ThreadLocal.Key serialNumberKey = ThreadLocal.getKey();  
  2.  ThreadLocal.set(serialNumberKey, nextSerialNumber());  
  3.  System.out.println(ThreadLocal.get(serialNumberKey));  

线程局部变量重构2

 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. public class ThreadLocal {  
  2.  public ThreadLocal() { }  
  3.  public void set(Object value);  
  4.  public Object get();  
  5.  }  

从API和客户端代码中删除了无用代码。 

 

 

[java] view plaincopybubuko.com,布布扣bubuko.com,布布扣
 
  1. static ThreadLocal serialNumber = new ThreadLocal();  
  2.  serialNumber.set(nextSerialNumber());  
  3.  System.out.println(serialNumber.get());  

总结

 

API设计是一件非常高端大气上档次的工艺,对程序员、终端用户和公司都会有所提升。不要盲目地去遵守文中所提及的规则、说明等,但也不要去侵犯他们,API设计不是件简单的工艺,也不是一种可以孤立行动的活。当然完美永远无法实现,但我们要努力去追求完美。

附上Joshua Bloch的PPT:

来自: How to Design a Good API and Why it Matters

http://www.csdn.net/article/2014-02-18/2818441-How-to-design-a-good-API

原文:http://www.cnblogs.com/bmate/p/3554133.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!