Objective-C 的 API 设计 已翻译 100%

魏涛 投递于 2013/01/15 17:17 (共 30 段, 翻译完成于 03-07)
阅读 7192
收藏 97
11
加载中

我最常做的开发任务是设计一个可重用的API组件。组件通常为iOS(尽管有时它们是OS X) 设计的,且总是GUI控件或某种视图。

多年来,我为客户开发了很多API组件,其中包括像Apple这样的客户,而且我已经很了解这个过程。我也定期发布开源组件,并且我把曾经对我有帮助的资料和API设计指南放在一起与大家分享。

这是一个重要的主题,无论你是一个开源贡献者,或作为团队的一员参与开发大型的应用,或者只是设计自己的软件。正如开发一个应用的过程,API接口是使用你代码的开发者对你代码的第一印象,将严重影响着开发者决定是使用或扔掉它。

APIs是开发者的用户体验。我一直惊讶,具体到这个流行平台上没有很多的资料是写我们这方面工作的。

当我们阅读一些设计指南时,必要的时候,我将要用我最近发布的开源GUI组件MGTileMenu作为一个例子。你可以在这里先阅读所有关于MGTileMenu的信息,如果你喜欢。

hyaicc
翻译于 2013/01/16 15:34
2

如何令人满意

应用程序接口(API)设计和用户界面、用户体验设计很相像。你的目标用户有不同的需求和特点,但归根结底他们的目标还是把需求完成而已。就像一个设计友好、易用的应用程序的用户界面一样,你需要让你的API有以下的特点:

  1. 直观性
  2. 容错性
  3. 易用性

如同人们设计的其它的软件一样,我们首先需要考虑的是使用案列。我们的设计需要使最经常被用到的的功能简单易用,不需要过度的配置。在默认配置下软件就应该是可用的,并且具有一定的可配置性。软件的设计应该具有可探索性,而且应该允许用户从已知的的范例中推广到其他应用场景。这和我们创建一个用户界面的规则非常的相像。

WangWenjing
翻译于 2013/02/07 09:43
2

开发者的界面

用于和开发者交互的元素使用四个主要的显示意味着:

  1. 类界面:暴露的属性和方法。
  2. 委托规则,相关的
  3. 数据源规则,适当的
  4. 任何可以提供的通知

我们需要把每一个都设计成:明智和慎重的,用于人类使用。这里有2个问题当你设计API的时候需要考虑:

  • 什么是控制?
    这将会影响到界面和便利的方法。这是一个按钮?一个滑动器?你的界面是很明显的。你的便利的方法将会遵循这些标准的语义控制
  • 控制长什么样?
    这影响到委托和/或数据源模型和通知。如果这是一个新类型的控制,这个是不是在基本原则上会和其他东西很像?一个大纲性的概念是一个线性表。一个日期的小工具是一个日期的选择器。在一个同一标准下的命令的集合是一个菜单。

我们的核心原则是让已有的类和模型保持一致性,以用来保证我们可以把一个开发者不熟悉的控制让他很轻松的在他可以理解的平台上使用。使用标准APIs,模型,和模式无论是不是可能(并且这个应该是总用的)。对于终端用户,熟悉和直觉性是和代码层级一样重要的。

让我们看看我们之前提到的这四个元素:

周荣冰
翻译于 2013/01/16 16:01
1

类接口

Here’s the interface file for MGTileMenu.

在我们讨论具体的接口之前,这有一些涵盖范围比较广泛的规则:

Rule 1: 使用方言

我所看到最常见的错误是API的设计利用了外来的约定。APIs 属于固定平台和固定的开发者生态系统。你根本无法使用任何习语和你用过的其他平台的架构,这样做会污染您当前的代码库,并对其他开发人员的效率造成损害。

在coding之前要了解你目标平台的约定,比如,在iOS 或者 OS X,不使用异常对待control的流程 。以适当的方式命名你的方法(通常指有足够详细,但也应该有足够的简洁)。

了解协议,和委托,类别分别是什么。在你的代码中使用他们。学习相关的构造函数和析构函数的命名方案。请遵守内存管理规则。词汇和语法是不可分割的,你要么发展为一个固定的的平台,或者你跨平台。

魏涛
翻译于 2013/01/17 08:34
1

规则 2:解耦的设计

任何一个组件都应该被设计成不和它所服务的工程相耦合,并且如果它是GUI控件或者是View,它至少应该默认情况下显示一些东西。利用已经存在的框架作为指导,利用代理协议维持松耦合,精心设计/命名API的方法,还有合时合处的通知。

为了达到松耦合显而易见但却是高效的方法是为每一个组件创建一个新的工程,独立地开发这个组件。强制你自己用你自己的API。远离将一些不相干的类放到一起的诱惑。开始并继续你想做的。

依据这种观点,让我们深度的讨论一下接口类。初始化方法是接口中最重要的部分之一,因为它们展示了人们如何开始你的组件。你的类为了初始化配置当然会需要一些设置。所以,一个显而易见的规则如下:

李远超
翻译于 2013/03/04 13:20
2

Rule 3: 必须设置初始化参数

如果有什么需要设置的,不要等待 -需要它了就去做,如果你没有得到的东西的立即返回nil。

- (id)initWithDelegate:(id<MGTileMenuDelegate>)theDelegate; // required parameter; cannot be nil.

Rule 4: 允许访问初始化参数Allow access to initializer parameters

这个前一个结果的必然结果: 记住不要仅仅传入参数,应该可以通过属性或者赋值来访问他们,如果他们可以通过任何方式来一场“按摩”(修改,重写等)

@property (nonatomic, weak, readonly) id<MGTileMenuDelegate> delegate; // must be specified via initializer method. 
前两个例子阐述了这个观点。
魏涛
翻译于 2013/01/17 08:40
1

Rule 5: 注释你的header文件 (包含默认值)

实际上,你不总为component提供单独的文档。如果你不提供文档,你的.h文件(包括demo app)就是你的文档。他们应该适当的描述,我的意思是:

  1. 足以描述,但是不是特别多,要简洁。
  2. 一切是提供给专业人士,所以适当的描述别描述无关的事情。

特别是,你应该简要注释在属性或访问器旁边;头文件扫描比在初始化实例的时候更容易。

@property (nonatomic) CGGradientRef tileGradient; // gradient to apply to tile backgrounds (default: a lovely blue)
@property (nonatomic) NSInteger selectionBorderWidth; // default: 5 pixels
@property (nonatomic) CGGradientRef selectionGradient; // default: a subtle white (top) to grey (bottom) gradient
魏涛
翻译于 2013/01/17 08:44
1

Rule 6: 习惯于运行3行代码

你的类应该设计成只需要最少的代码来集成(包括后续将用到的委托/数据源协议)。但不包括委托方法,你应该着手于用3行代码就可以达到测试的目的。

这3行代码如下:

  1. 实例化你的类
  2. 基本配置,使之能够展示一些信息
  3. 展示或激活它(类的示例)
就这样。任何实质上更繁杂的就会导致代码坏味(code smell)。下面是 MGTileMenu’s demo app中 相关的几行代码:

// Instantiate.
tileController = [[MGTileMenuController alloc] initWithDelegate:self];

// Configure.
tileController.dismissAfterTileActivated = NO; // to make it easier to play with in the demo app.

// Display.
[tileController displayMenuCenteredOnPoint:loc inView:self.view];
h
翻译于 2013/01/18 00:11
2

Rule 7: 臃肿的demo通常意味着组件是糟糕的

另一个推论:您的demo的大小是衡量你component质量的标准,其值越小越好。Demo/Code 应该尽可能的小巧而又精简(用于演示,旨在描述所有组件的定制或功能)。

核心思想是当你的代码从你的空的Xcode项目模板到你的demo中应该保持最小化的修改。这并不是一个好的借口当你需要复制粘贴demo来让你的component运行。

魏涛
翻译于 2013/01/17 08:56
1

Rule 8:分析特定的场景

我对于apps的准则就是:不要让用户去做选择。选择满足多数人的人性化的默认设置,略去参数设置窗口。毕竟,好的软件都是有倾向性的。

由于运用场景不是那么的清晰明确,所以不同的组件面对的情况也有些不同。你当然可以做一个只满足某种特定情况的组件,但是,通常我们都希望有些灵活性。你绝不会准确的知道另一个开发者将会怎样使用你的组件,所以你必须做到有一定的通用性。

认真的选择你的定制点是很重要的。考虑依赖关系更加的重要——不是对编译/链接的理解,而是定制类型之间的逻辑关系。我的方法就是尽量从“方面”的层次上考虑而不是实例变量的层次上。你希望你的组件的那些方面允许被定制化?那么你就知道哪些特定的属性需要暴露。

通过不暴露足够的的配置点,就可以很容易的弱化某个特定的定制类型。例如:
    1.如果没有考虑圆角半径,就不要暴露宽度和高度。
    2.如果没有高亮的背景颜色,就不要暴露背景颜色。

    3.如果没有空间,就不要暴露大小。

具体的情况取决于具体的组件,但是需要从外观或者功能角度来考虑属性之间的关系。学会理解开发者。不要禁止组件的个性化,让它灵活些。

@property (nonatomic) BOOL dismissAfterTileActivated; // automatically dismiss menu after a tile is activated (YES; default)
@property (nonatomic) BOOL rightHanded; // leave gap for right-handed finger (YES; default) or left-handed (NO)

@property (nonatomic) NSInteger tileSide; // width and height of each tile, in pixels (default 72 pixels)
@property (nonatomic) NSInteger tileGap; // horizontal and vertical gaps between tiles, in pixels (default: 20 pixels)
@property (nonatomic) CGFloat cornerRadius; // corner radius for bezel and all tiles, in pixe
让常识来指导你。确定那些能够满足70%左右你所能想到的使用场景的选项,然后提供这些选项。剩下的就让你的授权方法和代码架构来满足吧。
c
翻译于 2013/01/21 16:38
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(7)

雷毅
雷毅
必须收藏
super0555
super0555
必须收藏
wrzs
wrzs
ding!
crossmix
crossmix
类,界面,协议
Duziee
Duziee
翻译那么多啊。不易,顶!!!!
开开心心打酱油
开开心心打酱油
不懂纯帮顶路过
GavinZhang
GavinZhang
受教啊,啧啧
返回顶部
顶部