【问题标题】:Stateless static methods vs. C functions in Objective-C无状态静态方法与 Objective-C 中的 C 函数
【发布时间】:2012-01-03 05:50:43
【问题描述】:

就良好的Objective-C编码实践而言,如果我创建一个没有状态的函数,是写成某个类的静态方法还是写成C函数更好?

例如,我有一个特殊的文件路径检索方法,它会在进入主 NSBundle 之前检查 Caches 目录。我目前将它作为一个静态方法放在一个空的 Utils 类下。这应该是一个 C 函数吗?

我选择使用静态方法(目前)的原因是 a) 它与 Objective-C 语法一致,并且 b) 类有助于对方法进行分类。但是,我觉得我有点作弊,因为我可以很容易地用这些无状态的静态方法填充我的 Util 类,并最终得到一个丑陋的“shell 类”,其唯一目的就是容纳它们。

您使用什么约定?通过某种客观指标,一个比另一个“更好”吗?谢谢!

【问题讨论】:

    标签: objective-c coding-style static-methods


    【解决方案1】:

    如果您能想到一个 现有 类,这可能是一个很好的方法,您可以通过创建一个 Objective-C 类别将您的方法注入其中。这保留了您使用静态方法而不用额外的类污染类空间的两个原因。

    例如:

    @interface NSString (MyStringCategories) 
    - (NSString*) myCoolMethod;
    @end
    
    // [StringCategories.m]
    #import "StringCategories.h"
    
    @implementation NSString (MyStringCategories)
    - (NSString*) myCoolMethod {
        // do cool stuff here
        return whateverYouLike;
    }
    @end
    

    现在您可以将myCoolMethod 发送到任何 字符串。酷!

    在您的特定情况下,听起来 NSBundle 上的方法可能是合适的架构。别忘了,它可以是一个类方法,所以你不需要实例化任何东西来调用你的方法。

    【讨论】:

    • 是的,我会尽可能多地这样做。但是在这种情况下想不出一个——它只在缓存中找不到文件时才搜索包,而且它不是像典型的 pathForResource: 这样的实例方法,所以(在我看来)它不是一个理想的合身。
    • 所以让它成为一个类方法。我的观点是,不能想出一个合适的现有班级不是想象力的失败吗?它可能是 NSBundle,它可能是 NSFileManager,它可能是 NSString(因为它处理路径名),它可能是任何类直观地觉得在正确的范围内。
    • +1 对于类别。我个人认为类的目的是实例化。不要将类用作命名空间。所以如果你只有静态方法,你应该考虑另一种方法。
    • @Macmade - 不过苹果认为你错了。例如,在 WWDC 2011 的一个视频中,他们谈到使用类方法来避免必须创建共享实例。当然还有很多内置类方法,例如 UIFont 的familyNames,它们实际上只是全局函数,它们被放入适当的类中,只是作为一种方式对它们进行分类。错过类方法就是错过 OOP 精神的一部分。
    • @matt 我猜苹果想了很多事情......恕我直言,单例比“静态”类更好。 UIFont 不是一个很好的例子,因为 UIFont 对象可以(并且需要)实例化,因为它需要 iVar。在这种情况下,静态方法很有帮助,因为它们提供了辅助方法的便利构造函数。但最后,你有一个真实的 UIFont 实例。此处提出的问题并非如此。
    【解决方案2】:

    这是一个很难回答的问题,因为对于很多人来说,答案将取决于他们的个人喜好和品味。我个人认为,如果你有一个函数是一个函数,即它与对象无关,它没有内部状态等。请让它成为一个函数,不要试图将所有可能的东西包装到一个对象只是因为您使用的是 OO 语言并且您可以。

    为了让我的回答简短,让我参考一本(imo)相当不错的书:

    http://www.gotw.ca/publications/c++cs.htm

    我知道这是针对 C++ 的,但有很多见解可以与其他语言(尤其是 Objective-C 和 Objective-C++)共享,尤其是来自“类设计和继承”部分。在那里你会找到一个标题为“Prefer writing nonmember nonfriend functions”的项目。

    底线:“非成员非友元函数通过最小化依赖关系改进封装[...]它们还分解了单体类[...] [和]提高通用性[...]”。

    我认为这句话是有道理的。

    【讨论】:

      【解决方案3】:

      如果没有明确地绑定它的类,那么我使用一个函数。我还为这些实用程序位使用函数,因为如果不使用或引用它们可以被剥离。在这方面,使用函数也很有帮助,因为链接错误比运行时错误更好(即使 .m 从构建中意外省略,或者如果从另一个外部更新的方法引用)。 ObjC 符号的一个问题是它们没有被剥离,因此它们自然带有大量的依赖关系——所有的 objc 方法和类,以及所需的类别方法必须存在于最终的二进制文件中。对于非常小的程序或库来说,这不是问题,但对于中型/大型系统和库来说,它很快就会变得重要。

      不需要在@interface 中声明所有内容 - 特别是对于较大的系统,所有这些声明都会真正将您的相互依赖关系变成意大利面。与方法相比,函数更快、更小,编译器或链接期间可能会更好地优化,如果不引用,可能会被剥离。

      如果您需要多态性,它只是为了组织或方便而属于一个类,那么类或实例方法通常是更好的选择。

      出于同样的原因,我也尽量减少声明类别方法。当您使用函数时,您可以轻松地在需要的地方编写一个包装器方法,并获得两全其美的效果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-17
        • 2013-01-29
        • 2010-12-21
        • 1970-01-01
        相关资源
        最近更新 更多