【问题标题】:Objective-C wrapper API design methodologyObjective-C 包装 API 设计方法
【发布时间】:2011-01-28 16:10:48
【问题描述】:

我知道这个问题没有一个答案,但我想了解人们对如何处理这种情况的想法。

我正在为 C 库编写一个 Objective-C 包装器。我的目标是:

1) 包装器使用 Objective-C 对象。例如,如果 C API 定义了 char *name 这样的参数,Objective-C API 应该使用 name:(NSString *)。

2) 使用 Objective-C 包装器的客户端不必了解 C 库的内部工作原理。

速度不是问题。

使用简单的参数就可以轻松搞定。拿一个 NSString 转成 C 字符串传给 C 库当然没问题。

当涉及到复杂的结构时,我就会犹豫不决。

假设你有:

struct flow
{
    long direction;
    long speed;
    long disruption;
    long start;
    long stop;
} flow_t;

And then your C API call is:

void setFlows(flow_t inFlows[4]);

因此,一些选择是:
1) 向客户端公开 flow_t 结构并让 Objective-C API 获取这些结构的数组
2) 构建包含属性的四个 NSDictionaries 的 NSArray,并将其作为参数传递
3) 创建一个包含结构属性的四个“Flow”对象的 NSArray,并将其作为参数传递

我对方法的分析:
方法1:最简单。但是,它不符合设计目标
方法2:出于某种原因,在我看来,这似乎是最“Objective-C”的做法。但是,NSDictionary 的每个元素都必须包装在一个 NSNumber 中。现在似乎我们做了很多工作只是为了传递一个结构的等价物。
方法 3:从面向对象的角度来看,对我来说似乎是最干净的,额外的封装以后可能会派上用场。然而,就像 #2 一样,现在我们似乎做了很多事情(创建数组、创建和初始化对象)只是为了传递一个结构。

那么,问题是,您将如何处理这种情况?还有其他我没有考虑的选择吗?我所介绍的方法是否还有其他我没有考虑的优点或缺点?

【问题讨论】:

  • 框架本身包含结构。 NSRange 等。我认为在结构上没有一刀切的决定。这取决于。

标签: objective-c


【解决方案1】:

我认为方法 3 将是做事的首选方式。当你包装一个库时,你会想要围绕用户期望处理的任何对象或结构创建包装器。

如果您封装了所有内容,那么您可以在以后随意更改类的内部工作方式,而不会影响用户已经习惯的接口。例如,将来您可能会意识到您想添加某种类型的错误检查或更正...也许设置早于startstop 会导致一些计算错误,您可以更改@如果 stop 小于 start,则在 Flow 包装器中使用 987654323@ 方法将 start 设置为等于 stop(我承认,这是一个非常糟糕的例子)。

【讨论】:

  • 我同意。毕竟初始化 4 个对象,然后放到一个数组里,和初始化 4 个结构体,然后放到一个数组里其实并没有太大区别,所以我觉得我操心太多了。
【解决方案2】:

我会坚持方法 3。您“只是传递一个结构”现在,但 Flow 对象将来可能会扩展得更多。你说速度不是问题,所以我想内存消耗也不是问题,否则你还是会坚持使用 C。

【讨论】:

    【解决方案3】:

    我的答案不是你要问的,但它仍然是我“将如何处理这种情况”。

    我要问的第一个问题是,“这个包装器增加了什么价值?”如果答案是“使用 Objective-C 语法”,那么答案就是“不要改变任何东西,按原样使用库,因为 C 是 Objective-C 语法。”

    我不知道您要包装哪个库,所以我将使用 SQLite 作为我头脑中的示例。使用分层方法,我会做这样的事情:

    A) 高级对象(订单、客户、供应商...)

    B) 基类(记录)

    C) SQLite

    因此,基类被编写为直接调用 SQLite,然后其他类作为常规 Objective-C 类工作。

    这与:

    1) 高级对象(订单、客户、供应商...)

    2) 基类(记录)

    3) SQLite Wrapper (Objective-C)

    4) SQLite

    创建了相同的应用程序,但创建、维护和调试级别 3 的额外工作很少显示。

    在第一个版本中,B 层包装了 SQLite,因此它上面的任何东西都没有直接调用 SQLite,并且它没有尝试提供所有 SQLite 功能。它只是提供了 A 层需要的功能,并使用 SQLite 来实现所需的功能。它“包装”SQLite,但以更特定于应用程序的方式。以后可以在另一个应用程序中重用相同的 Record 类,并对其进行扩展以满足当时两个应用程序的需求。

    【讨论】:

      【解决方案4】:

      既然 Objective-C 使用结构体,为什么不将其保留为像 NSRect 这样的结构体?

      【讨论】:

      • 因为将结构体作为实际对象通常会更好,因为如果不先将结构体放入 NSValue 对象中,就不能将结构体放入集合(如 NSArrays)中。
      猜你喜欢
      • 2015-11-06
      • 2011-05-17
      • 2015-11-26
      • 2014-08-26
      • 1970-01-01
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多