成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

API設計的一些心得總結

開發 開發工具
如何設計更容易使用的API?對于不同的語言,這個答案是不一樣的,因為不同語言有著不同的語言特性。本文總結了一些API設計時需要考慮的事項,其中包括語言特性的影響。

你做過API設計么?不管你是否做過API設計,都不妨看看老趙的這篇博文。在這篇文章中,老趙總結了自己進行API設計的一些心得。

我平時的主要工作之一,便是編寫一些基礎及通用的類庫,能夠在項目中大量復用。換句話說,我的工作目的,是讓其他開發人員可以更好地完成工作。因此,如何設計更容易使用的API是我經常要考慮的東西,偶爾也會有一些體會。而現在這些內容,是我在為Functional Reactive Programing寫“參考答案”的時候忽然“總結”出來的想法。可能比較簡單,但我想也是設計API是需要考慮的一些內容。

在那篇文章里,我們是在為IEvent< T>對象提供一些封裝,其中會有MapEvent和FilterEvent等類型,為了方便調用,我們還定義了對應的擴展方法:

  1. public class MapEvent< TIn, TOut> : InOutEventBase< TIn, TOut>  
  2. {  
  3.     public MapEvent(Func< TIn, TOut> mapper, IEvent< TIn> inEvent)  
  4.         : base(inEvent)  
  5.     {  
  6.         ...  
  7.     }  
  8. }  
  9.  
  10. public class FilterEvent< TEventArgs> : InOutEventBase< TEventArgs, TEventArgs>  
  11. {  
  12.     public FilterEvent(Func< TEventArgs, bool> predicate, IEvent< TEventArgs> inEvent)  
  13.         : base(inEvent)  
  14.     {  
  15.         ...  
  16.     }  
  17. }  
  18.  
  19. public static class EventExtensions  
  20. {  
  21.     public static MapEvent< TIn, TOut> Merge< TIn, TOut>(  
  22.         this IEvent< TIn, TOut> ev, Func< TIn, TOut> mapper)  
  23.     {  
  24.         ...  
  25.     }  
  26.  
  27.     public static FilterEvent< TEventArgs> Filter< TEventArgs>(  
  28.         this IEvent< TEventArgs> ev, Func< TEventArgs, bool> predicate)  
  29.     {  
  30.         ...  
  31.     }  
  32. }  
  33.  

MergeEvent和FilterEvent都是對另一個Event對象的封裝,您可以當作一種裝飾器模式來考慮。不知您觀察到沒有,這個“待封裝”的Event對象在不同的地方(構造函數或擴展方法),出現的位置是不同的。在擴展方法中,它是作為第一個參數出現在參數列表中,而在構造函數中它則是第二個參數。對于擴展方法來說,它是由語言規范強制得出的。但是在構造函數中,這出現的順序完全可有由我們“自由”確定。那么,我們能否將待封裝的Event對象作為構造函數的第一個參數呢?

自然是可以的,只是我在這里傾向于放在最后。原因在于這有利于API使用時的清晰。

假如我們沒有擴展方法,也就是說只能使用構造函數進行“裝飾”,那么使用現在則是:

  1. var ev =  
  2.     new MapEvent< intstring>(  
  3.         i => i.ToString(),  
  4.         new FilterEvent< int>(  
  5.             i => i <  10,  
  6.             new MapEvent< DateTime, int>(  
  7.                 d => d.Millisecond,  
  8.                 ...)));  
  9.  

有的時候,我會將Lambda表達式寫在上一行,這樣可以讓代碼更為緊湊。那么如果MapEvent和FilterEvent都把待封裝的Event對象作為構造和函數的第一個參數,又會怎么樣呢?

  1. var ev =  
  2.     new MapEvent< intstring>(  
  3.         new FilterEvent< int>(  
  4.             new MapEvent< DateTime, int>(  
  5.                 ...,  
  6.                 d => d.Millisecond),  
  7.             i => i <  10),  
  8.         i => i.ToString());  
  9.  

對比這兩者,在我看來它們的信息“呈現方式”是有顯著差距的。對于第一種情況(Event作為構造函數最后一個參數),用戶看到這個定義時,從上到下的閱讀順序是:

  1. 構造一個MapEvent對象,映射方式是XXX
  2. 包含一個FilterEvent對象,過濾條件是YYY
  3. 包含一個MapEvent對象,映射方式是ZZZ

而對于第二種情況(Event作為構造函數的第一個參數):

  1. 構造一個MapEvent對象
  2. 包含一個FilterEvent對象
  3. 構造一個MapEvent對象
  4. 最內層MapEvent的映射方式為ZZZ
  5. 上一層FiterEvent……
  6. ……

第一種情況,API體現出的信息是流暢的,而第二種情況信息的體現是回溯的。第一種信息如“隊列”,而第二種如“棧”。第一種API閱讀起來用戶視線是單向的,而第二種API用戶可能會去努力尋找某個Lambda表達式到底對應著哪個對象——就像我們為什么提倡if/for不應該嵌套太深,因為找匹配的大括號的確是件比較麻煩的事情。我想,應該沒有會選擇把Event對象放在構造函數參數列表的中間吧(如果有3個及參數),因為這會讓API調用看起來成“鋸齒狀”,實在不利于閱讀。

因此,在各種需要“裝飾”的場合,我往往都把“被裝飾者”作為構造函數的最后一個參數。例如我在構造DomainRoute的時候,便也是把innerRoute作為構造函數的最后一個參數,由于DouteRoute所需要的參數較多,因此如果把innerRoute作為第一個參數,看起來會更加不便一些。同樣的,在之前設法“拯救C# 2.0”的時候也使用了這個做法。

當然,這些是我個人的看法,并非所有人都是這樣做的。例如在.NET Framework中負責GZip壓縮的GZipStream對象,它的構造函數便是將innerStream作為第一個參數出現。幸好,C# 3.0中已經有了擴展方法,如果使用構造函數的話,即使信息再流暢,我想也不如擴展方法來的直觀。因此,我一般都會利用擴展方法,讓開發人員可以編寫這樣的API:

  1. dateEvent.Map(d => d.Millisecond).Filter(i => i <  10).Map(i => i.ToString())  
  2. route.WithDomain("http://www.{*domain}/blogs"new { ... });  
  3. stream.GZip(CompressionMode.Compress).Encrypt(...);  
  4.  

其實許多高級語言都會為了讓代碼寫的更易懂更清晰,因而提供一些看似“語法糖”的東西。例如F#中的|>操作符:

  1. let form = new Form(Visible = true, TopMost = true, Text = "Event Sample")  
  2. form.MouseDown  
  3.     |> Event.merge form.MouseMove  
  4.     |> Event.filter (fun args -> args.Button = MouseButtons.Left)  
  5.     |> Event.map (fun args -> (args.X, args.Y))  
  6.     |> Event.listen (fun (x, y) -> printfn "(%d, %d)" x y)  
  7.  

其實|>操作符的目的只是把函數的最后一個參數調到之前來,但它能讓我們寫出“易讀”的代碼。例如FsTest類庫允許我們這樣寫:

  1. "foo" |> should equal "foo" 
  2.  

但其實,從理論上說,這種寫法完全等價于:

  1. should equal "foo" "foo" 
  2.  

正是因為有了|>操作符,F#在這種情況下會將待封裝的Event對象作為函數的最后一個參數。這便是語言特性對API設計的影響。此外,F#中的“>>”以及Haskell的“.”可用“`”把一個函數作為中綴操作符來使用。但如果是Java這樣的語言,由于缺乏一些靈活的語法特性,開發人員就只能靠框架和類庫來構建“Fluent Interface”來度過難關了(如Google Collections)。《卓有成效的程序員》一書中舉了這么一個例子,它們為一個Car對象的構造編寫了流暢接口:

  1. Car car = Car.describedAs().  
  2.              .box()  
  3.              .length(50.5)  
  4.              .type(Type.INSULATED)  
  5.              .includes(Equipment.LADDER)  
  6.              .lining(Lining.CORK);  
  7.  

以代替呆板的Java語法:

  1. Car car = new CarImpl();  
  2. MarketingDescription desc = newMarketingDescriptionImpl();  
  3. desc.setType("Box");  
  4. desc.setSubType("Insulated");  
  5. desc.setAttribute("length""50.5");  
  6. desc.setAttribute("ladder""yes");  
  7. desc.setAttribute("lining type""cork");  
  8. car.setDescription(desc)  
  9.  

似乎程序員永遠不會放棄這方面追求:編寫更清晰,更易懂的代碼。

【編輯推薦】

  1. C# 3.0新語言特性淺析
  2. 利用Visual C#和C#語言特性
  3. Jython入門指導:語言特性簡介
  4. 比較幾個JDK版本的新增語言特性
  5. 哪種語言將統治多核時代 再看函數式語言特性
責任編輯:yangsai 來源: 博客園
相關推薦

2011-09-19 10:15:10

移動界面設計

2025-05-09 09:10:00

2014-08-14 09:25:31

Linux串口

2011-06-16 20:35:34

SEO

2009-06-22 15:36:00

如何學好java

2011-07-12 09:47:53

WebService

2011-11-28 15:57:26

MySQL數據庫主從配置

2011-07-13 09:13:56

Android設計

2015-12-08 09:05:41

Java內部類

2009-07-15 16:16:22

JDBC下載

2009-11-25 10:08:41

Cisco無線路由

2020-09-28 06:45:42

故障復盤修復

2009-11-26 10:32:57

PHP代碼優化

2019-08-19 14:56:07

設計模式javascript

2020-04-10 08:50:37

Shell腳本循環

2020-05-19 14:35:42

Shell腳本循環

2012-07-03 13:55:00

ASP.NET

2013-12-24 14:50:39

Ember.js框架

2012-06-07 10:17:55

軟件設計設計原則Java

2012-01-09 16:02:19

JavaJVM
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩视频在线观看中文字幕 | 久久99精品久久久久久国产越南 | 奇米四色在线观看 | 韩日精品在线观看 | 亚洲一区二区三区四区五区中文 | 国产午夜视频 | 99久久精品免费看国产免费软件 | 亚洲精品久| 国产成人免费观看 | 玖玖在线免费视频 | 国产一在线观看 | 九九亚洲 | 欧美日韩不卡合集视频 | 伊人久操| 97avcc| 天堂网avav| 国产成人福利在线观看 | 欧美11一13sex性hd | 日韩在线不卡 | 日日天天 | 国产精品久久 | 麻豆视频在线免费观看 | 久久久精品综合 | 日本一区二区三区免费观看 | 欧美日韩一卡二卡 | 免费国产黄网站在线观看视频 | 欧美日韩国产一区二区三区 | 久久久国产一区二区三区 | 国产精品18久久久久久白浆动漫 | 亚洲性视频在线 | 欧美精品一区二区三区四区 在线 | 乱码av午夜噜噜噜噜动漫 | 久久中文字幕av | 九色.com| 欧美日韩成人影院 | 视频一区二区三区中文字幕 | 日本色综合 | 国产成人精品一区二区三区在线 | 超碰97在线免费 | 精品一区二区三区在线观看国产 | 亚洲精美视频 |