移動端SDK接口設計心得體會

接口設計注意點

對於SDK而言,接口是鏈接SDK與客戶產品的紐帶,接口設計的優劣是衡量SDK產品易用性的重要指標。糟糕的SDK接口不只僅給開發者帶來的難用的主觀印象,更有可能增長客戶的開發成本,甚至影響產品質量。
筆者在從事SDK開發的幾年起初並不重視,在一次次填坑的過程當中也逐漸意識到優秀的SDK接口設計必需要思考如下幾點:java

  1. 風格統一
    統一的接口設計風格不只僅是爲了給開發者留下專業的印象。更進一步的,它能夠傳遞給開發者SDK的設計理念。開發者經過這種風格上的暗示,能夠更直觀,不易犯錯的調用SDK功能。
    舉例來講,咱們能夠設計SDK全部接口都經過init方法初始化,uninit方法反初始化。開發者一旦接受了這種設定,會潛意識的注意有沒有調用過uninit釋放資源。android

  2. 平臺慣例
    一款SDK產品底層一般是跨平臺實現,上層則是針對不一樣平臺作一層封裝,封裝層特別要考慮的是平臺的開發慣例。因爲對接SDK的開發者一般是專一於某一特定平臺的開發,不符合本平臺接口命名風格,設計慣例的接口會給他們帶來額外的學習成本,增長對接難度。c++

  3. 升級擴展
    接口設計考慮升級擴展這一點對每個負責持續迭代的產品的程序員來說都是基本的要求。可是對於SDK產品,這一點顯得尤其重要。緣由在於,通常接口設計若是不合理能夠經過後期迭代重構來補救,而SDK一旦發佈以後,想要客戶修改代碼來升級SDK的成本是很高的。接口兼容性若是作的很差,客戶就不會願意升級,隨之帶來的問題是維護多個版本給咱們自身帶來的巨大的支撐壓力。程序員

  4. 註釋說明
    註釋和接口是SDK的一體兩面,它在SDK中有着和接口同等重要的做用。SDK沒有一個接口是多餘的,一樣,沒有一個接口是能夠被容許沒有註釋的。咱們在開發SDK時,始終要預設這樣一個前提:開發者不會看咱們的集成文檔。所以,咱們只有儘量的豐富註釋,纔有可能最大程度將問題消滅在開發者翻閱文檔或是提問以前。api

SDK接口設計規範

針對上述幾個注意點,咱們基於通用編碼規範,平臺命名規範,以及行業通用慣例制定了本身的SDK接口設計規範。目前尚未特別完善和細化,但有了一個統一的標準以後,相信對將來的接口設計會有一個原則性的指導。咱們的SDK主要是針對移動端iOS/android平臺,採用的語言主要是oc/java,其餘平臺的設計規範能夠作一個參考。數組

類/接口

類/接口的命名必須使用名詞。多線程

  • android
    接口須要加I字符來區分。
// good case
public interface AliyunIRecorder;   // android; 接口加I區分

// bad case
public interface AliyunIImport;     // android; import不是名詞
複製代碼

方法/函數

方法/函數名足夠清晰易懂,除了行業內通用的專有名詞,其餘狀況下不能使用縮寫。異步

// good case
void setExposureCompensationRatio(float value); // android; 方法名即解釋


// bad case
- (int)removeTransitionAtIndex:(int)clipIdx;    // iOS; 參數名應該使用全稱clipIndex
複製代碼

參數儘量少,超多4個參數須要考慮採用結構體/類封裝。ide

採用結構體/類封裝的好處除了減小方法長度,更重要的意義在於將來版本接口功能升級只須要新增配置屬性,而不用提供新的接口。函數

// bad case
void setMusic(String path,long startTime,long duration);        // android; 使用music類封裝
複製代碼

能採用同步接口的儘可能不要用異步,異步接口須要在註釋裏說明。

設計同步接口的行爲是明確的,設計異步接口可能讓開發者誤覺得接口行爲已經完成,從而作出一些錯誤調用。異步接口必須強調說明,並註明對應的回調方法是什麼。

// bad case
int finishRecording();     // android; 異步接口須要說明對應的回調方法
複製代碼

一個接口只作一件事,使用doSomething命名。

// bad case
int editCompleted();            // android; 改成stopEdit/finishEdit
複製代碼

枚舉

  • iOS
    採用平臺慣例的駝峯命名法,使用typedef NS_ENUM()語法定義。
// good case
typedef NS_ENUM(NSInteger, AVCaptureFlashMode) {
    AVCaptureFlashModeOff  = 0,
    AVCaptureFlashModeOn   = 1,
    AVCaptureFlashModeAuto = 2,
}                        //iOS; 系統api命名

// bad case
typedef enum : NSUInteger {
    DIRECTION_LEFT = 0,
    DIRECTION_RIGHT = 1,
    DIRECTION_TOP = 2,
    DIRECTION_BOTTOM
} DIRECTION_TYPE;        //iOS; 沒有使用駝峯命名,枚舉值命名不規範,未使用oc聲明規範
複製代碼
  • android
    採用平臺慣例的命名方法,枚舉成員名稱須要全大寫,單詞間用下劃線隔開。
// good case

public enum FormatStyle {
    FULL,
    LONG,
    MEDIUM,
    SHORT;
}              // android; 系統api命名方法

// bad case
public enum AlivcLogLevel {
    AlivcLogLevelDebug(0),
    AlivcLogLevelInfo(1),
    AlivcLogLevelWarn(2),
    AlivcLogLevelError(3),
    AlivcLogLevelFatal(4);
}              // android; 枚舉值命名不規範
複製代碼

成員變量/屬性

  • iOS
    只有在同時須要getter/setter方法的時候暴露屬性,不然使用方法代替。
    使用oc基本數據類型,不要使用c/c++的基本數據類型。

  • android
    不要直接暴露屬性,提供getter/setter方法。
    Param類必須有構造器。

// bad case
public int videoWidth;                          // android; 提供getter/setter方法
@property (nonatomic, assign) int bitrate;      // iOS; 使用NSInteger代替int
複製代碼

命名慣例

獲取已經存在的對象使用get命名。

// bad case
AliyunICanvasController obtainCanvasController(Context var1, int var2, int var3);  // android; 使用get代替obtain
複製代碼

獲取一個new的新對象使用create命名。

create能夠給開發者暗示資源的是被建立出來的。

// good case
public static AliyunIEditor createAliyunEditor();  // android; 工廠方法使用create建立新實例

// bad case
AnimPlayerView newPasterPlayer();              // android; 使用create代替new
複製代碼

參數設置類/結構體命名須要聲明用途,以Param結尾。

後綴能夠是Config,Setting等等,一旦肯定好須要全部接口保持統一。

// good case
public class AliyunVideoParam;    // android; 命名符合規範

// bad case
public class CropParam;         // android; 沒有前綴
public class MediaInfo;         // android; 沒有聲明是錄製參數,沒有以Param結尾
複製代碼

設置效果:setXxx,移除效果:clearXxx

// bad case
int addAnimationFilter(EffectFilter var1);                  // android; 不符合規範
- (void)deletePaster:(AliyunEffectPaster *)paster;          // iOS; 不符合規範
複製代碼

新增:addXxx,刪除:removeXxx,清空:clearXxx

// good case
int addMediaClip(AliyunClip clip);        // android; 替換爲clearPartList

// bad case
void deletePart();                        // android; 替換爲removePart
void deleteAllPart();                     // android; 替換爲clearPartList
複製代碼

數組/字典命名使用變量名+List/Map/Array/Dictionary

之因此不用複數形式定義變量名,主要考慮到咱們開發團隊對名詞的複數形式並無深刻掌握。與其命名不專業的變量名,不如用這種方式更爲直觀。

// good case
public List<Frame> getFrameList();         // android; 符合命名規範 

// bad case
@property (nonatomic, copy) NSArray<AliyunFrameItem *> *frameItems;  // iOS; 替換爲frameItemArray
複製代碼

回調

回調方法除非特殊需求通常在主線程回調,回調接口註釋必須說明在哪一個線程。

保證開發者的全部接口調用都在主線程執行能夠避免不少線程問題。
有一些回調須要在特定線程如渲染回調等須要註釋說明。

  • iOS
    回調類統一以Delegate結尾,會調方法以回調類名+Did開始,一個回調對應一個delegate屬性。

  • android
    回調類統一以Callback結尾,會調方法以on+回調類名開始。

// bad case
@protocol AliyunIPlayerCallback 

@end                              //iOS; 不能使用callback結尾 
複製代碼

初始化/反初始化

主要模塊必須經過init方法並使用Param配置參數初始化。

統一的初始化方式能讓開發者快速熟悉SDK調用方式。

  • iOS
    oc類不該提供反初始化方法。有可能的條件下,儘可能按如下優先級,在特定位置構造與析構native資源:
  1. 調用關鍵方法時構造native資源,完成回調後內部析構native資源。
    例如:調用transcode方法構造資源,transcode完成回調後析構資源。

  2. 對外提供成對方法處構造與析構native資源。
    例如:startPreview與stopPreview,startEdit與stopEdit,open與close。

  3. 以上都不合適,考慮在dealloc處內部析構native資源。

// bad case
- (void)destroyRecorder;              // iOS; 考慮是否能夠經過1,2,3條避免
複製代碼
  • android
    主要模塊類必定要有release方法,release刪除底層資源與java同生命週期。
// bad case
void dispose();             // android; 沒有使用release()方法
複製代碼

前綴

類,接口,結構體,枚舉值必須加前綴。

java雖然有包名區分不一樣類,但仍是建議加前綴,這樣可讓開發者更容易區分SDK接口。

包名

安卓全部SDK接口必須在統一的包名內。

註釋

對外接口使用/** */註釋,不要使用//註釋。

不少接口須要多行註釋才能解釋清楚,因此在這裏統一使用多行註釋。

來源:本文爲第三方轉載,若有侵權請聯繫小編刪除。

相關文章
相關標籤/搜索