我正在为iPhone设计一个API。设计带有许多参数的API函数(最多20个变量)的最佳方法是什么。是否更好地传入一个定义了必要字段的自定义对象,一个通用的键值字典(Obj-C中的NSDictionary),或者只是将它们全部列出来?还有哪些其他建议?
我倾向于为每个API声明一个对象,但由于我需要定义许多API,所以我对使用这种方法持谨慎态度。
答案 0 :(得分:2)
大多数API设计者都同意,如果可能的话,你应该避免使用长参数列表,例如,Joshua Bloch(Effective Java)表明5个或更多是太多。避免这种情况的一些方法包括:
创建一个结构来保存参数并将该单个结构传递给该函数。这通常称为普通旧数据(POD)类型。您可能希望添加辅助函数来创建设置默认值的结构(或者如果您使用的是Objective-C ++,则可以为结构定义构造函数以执行相同操作)。如果您认为参数列表可能随时间而变化,并且二进制兼容性对您很重要,则可以添加版本字段并让构造函数对其进行适当设置。这样,您的代码可以检查版本号以了解可用的字段。
传递值词典。这实际上是一个数据驱动的API,其中参数及其值在支持具有任意类型值的键的结构中传递。在C / C ++中,您必须自己创建此结构或使用boost :: any或Qt的QVariant。但是,正如您所注意到的,NSDictionary允许您保存id类型的对象,以便您可以使用它。关于这一点的好处是更改参数列表不会破坏您的界面 - 它只是由实现来检测新密钥并支持旧密钥。虽然这意味着您的编译器不会为您捕获错误的密钥 - 这取决于您的代码。主要的缺点是,仅仅查看您的API并不会告诉用户支持哪些密钥,因此这种方法必须得到良好的文档支持。
创建一个对象并将参数转换为方法调用。这样做的好处是能够以任何顺序指定参数,基本上命名参数,并仍然处理可选参数(通过简单地不调用给定方法)。添加新参数也向后兼容,因为它解决了向对象添加新功能。
在3.的基础上,你可以使用命名参数成语(NPI),其中每个函数返回一个指向对象的指针或引用,从而允许你将调用链接在一起。此选项具有3.的所有优点,但也允许更简洁的语法,例如,MyObject()。setValue(100).setName(“Hello”)。setEnabled(true);
听起来你已经考虑了大部分这些选项,所以我可能不会告诉你任何新的东西。对于我自己的偏好,我更倾向于NPI风格,因为它避免了长参数列表,强类型,命名每个参数,向后兼容,并且仍然提供相对紧凑的语法。与NSDictionary方法相比,它更适合您的输入,但重要的是,您的用户可以轻松使用它,即使没有任何文档,它也可以通过头文件显示(并始终正确)支持的“参数”集,这与NSDictionary解决方案不同
答案 1 :(得分:1)
你需要20个参数才能初始化对象?您需要一些参数来将对象初始化为默认状态。然后使用属性来更改状态。
在内部,您可以在NSDictionary中存储20个参数/状态,以便于维护。
答案 2 :(得分:1)
如果您的API确实需要20个参数,请使用20个参数。如果将这些参数中的部分或全部聚合到自定义对象中是有意义的,那么这样做但不要仅仅为了使参数列表更小而创建自定义对象。举一个简单的例子,如果一个方法采用一个点(x,y,z)的坐标,那么创建一个对象来建模一个点并将其作为单个参数传递是合法的。您不应该创建其唯一目的是为API参数列表建模的对象。
在我确实拥有一组可扩展的键值对的情况下,我只会使用NSDictionary方法,所有这些键值对都是可选的。在其他情况下不使用它的原因是,如果使用API的程序员省略了必需参数,则在运行时才能检测到错误。显式命名每个参数的参数列表允许编译器检测遗漏。
API的参数数量必须限制为任意小值的想法完全是假的。 API应该根据需要采用尽可能多的参数。
答案 3 :(得分:0)
这取决于您正在创建的API的类型。
如果它适用于具有通常理解的信息模型的服务,那么拥有自定义模型对象可能是一个好主意,因为它们倾向于简化对API的整体理解。
OTOH,如果它更像是一个通用API,相当多的参数是可选的,或者模型对象对于每个方法都是唯一的,你可能更好地使用NSDictionary,清楚地记录你的密钥期待(以及在功能开始时的正确检查)。
关于互联网的主题还有广泛的信息,请参阅"How to Design a Good API and Why it Matters"以获取好的想法,ProgrammableWeb获取良好的示例,"Top Ten ways to create a great API"获得前十名的列表风格建议。
祝你好运!答案 4 :(得分:0)
我现在能想到的最复杂的方法是将NSDictionary作为参数。我会这样做的。