【问题标题】:Object hierarchies in Objective-CObjective-C 中的对象层次结构
【发布时间】:2012-09-27 02:42:51
【问题描述】:

我已经了解了一个包含约 50,000 个 LoC 的 Objective-C 代码库,我估计其中 25% 左右是重复代码。不幸的是,到目前为止,代码库中的 OO 原则大多被忽略,而倾向于复制和粘贴逻辑。耶!

我来自 Java 背景,很多这种重复可以通过老式的面向目标的编程来解决。在很多情况下,将共享逻辑提取到基类中感觉像是正确的解决方案。

然而,在我着手创建一堆基类并在派生类之间共享公共逻辑之前,我想我应该停下来看看是否还有其他可用的选项。从 2011 年开始观看 Ken Kocienda 的“Writing Easy-To-Change Code”WWDC 会议后,他建议我尽可能保持对象层次结构的浅层。他没有提供任何确切的统计数据来说明他为什么有这种观点,所以我想知道我是否错过了一些东西。

无论如何,我都不是 Objective-C 专家,所以我想知道在决定对象层次结构时是否有任何最佳实践。基本上,当您决定停止创建基类并开始使用组合而不是继承作为类之间共享代码的一种方式时,我想征求意见。

另外,从运行时性能的角度来看,有什么可以让我远离创建对象层次结构吗?

【问题讨论】:

  • 在任何面向对象的语言中,使层次结构尽可能平坦并倾向于组合而不是继承是很好的做法,但是,就像在 Java 中一样,如果那是什么,该语言不会阻止您创建天高的层次结构你想做。与 Java 不同的是,Objective-C 添加了类别的概念,这应该有助于扁平化层次结构。还有类集群模式有助于保持私有类的私有性并仅公开某个公共接口,其方式与 Java 提供的方式截然不同。
  • @protocol 类似于 Java 中的 interfaceid 几乎是 Objectid <protocol> 类似于在 Java 中实现指定协议(接口)的对象。
  • 测试,测试,测试,然后是更多的测试——如果你认为你可以删除 90% 的代码库,那么我希望你的测试能够确保你不会破坏它跨度>
  • @seanoshea,如果您正在寻找大型重构工作,我建议您查看AppCode,它在重构方面比 Xcode 好得多。至于由于深层层次结构对性能的影响,它基本上应该与 Java 没有什么不同。不同之处在于 Java 使用静态绑定,因此它比使用消息传递的 Objective-C 有更多的优化选项,因此总是进行后期绑定。
  • 感谢 AppCode 推荐 Radu。我一定会看看的。感觉就像在争论 Objective-C 中的深层层次结构从性能角度来看是一个糟糕的主意,正在进入令人毛骨悚然的领域(特别是如果我可以将其保持在 2-3 级)。我将仅从教育的角度研究后期绑定。干杯。

标签: iphone objective-c ios design-patterns inheritance


【解决方案1】:

我不久前在coming to iOS from other backgrounds 上写了一些想法,包括Java。由于ARC,有些事情发生了变化。特别是,内存管理不再那么重要。也就是说,您过去为简化内存管理所做的所有事情(使用访问器、使用访问器、使用访问器)在 ARC 中仍然同样有效。

@Radu 是完全正确的,你应该经常保持你的类层次结构相当简单和浅薄(如你所读)。在 Cocoa 中,组合通常是比扩展子类化更好的方法(这在 Java 中可能也是如此,但在 ObjC 中是常见的做法)。 ObjC 也没有抽象方法或类的概念,这使得某些类型的子类化有点尴尬。与其将共享逻辑提取到基类(尤其是抽象基类)中,不如将它们提取到单独的策略对象中。

查看UITableView 及其对委托和数据源的使用。看看NSAttributedString 之类的东西,它有NSString 而不是IS-A。这很常见,并且经常使事情变得更清洁。与所有大型对象层次结构一样,请始终牢记LSP。当有人忘记a square is not a rectangle 时,我看到很多 ObjC 设计都偏离了方向。同样,这适用于所有语言,但在设计时值得记住。

只要您可以使用不可变(值)对象,它们就是真正的胜利。

你会很快发现的另一部分是很少有像“final”或“protected”这样的“安全装饰”(有一个@protected,但实际上它在实践中并没有那么有用并且很少使用)。具有 Java 和 C++ 背景的人往往会担心编译器对各种访问规则的强制执行。 ObjC 没有编译器强制执行大多数保护(您始终可以在运行时向任何对象发送您想要的任何消息)。您只需使用一致的命名约定,不要到处寻找私有方法。程序员纪律取代了编译器的强制执行。实际上,在绝大多数情况下,它都可以正常工作。

也就是说,ObjC 有很多警告,您绝对必须消除所有警告。大多数 ObjC 警告实际上都是错误。

我有点偏离对象层次结构的具体问题,但希望它有用。

【讨论】:

    【解决方案2】:

    Objective-C 中深层层次结构的一个主要问题是 Xcode 根本无法帮助您理解/管理它们。另一个原因很简单,Objective-C 中的任何东西都比 Java 中的复杂度高出两倍,所以你需要更加努力地保持简单。

    但我发现 Objective-C 中的组合很尴尬(虽然我不能确切地说出原因),所以没有“完美”的答案。

    我观察到,在 Objective-C 与 Java 中,小的子例程要少得多,而且更有可能看到代码在大部分相同的视图控制器等之间重复。我认为其中很大一部分只是开发工具和创建新类的相对尴尬。

    PS:我不得不重新设计一个包含大约 55K 行的应用程序,我们可以数得差不多了。正如您所发现的,可能有大约 25% 的重复,但还有另外 25% 左右的完全死代码。 (谢天谢地,从那以后,该应用几乎被废弃了。)

    【讨论】:

    • “另一个简单的说法是,Objective-C 中的任何东西都比 Java 中的东西复杂大约两倍,所以你需要更加努力地保持简单。”这是一个非常奇怪的评论。几乎我与 Java 团队的每一次谈话都包含很多“好吧,我们不能在 Java 中这么容易地做 X”(这与我在其中开发的经验非常吻合)。我从来没有遇到过创建新课程的麻烦。如果你有复杂的继承,我只会遇到麻烦(但 Cocoa 设计不鼓励这样做;语言匹配有利于组合的设计选择)。
    • 我绝对不是说 ObjC 不能在继承方面使用一些改进(受保护方法的语言结构通常很有用,并且在类别周围有几个小“陷阱”肯定是改进了。我在 Android 团队的经验表明,完全定制或 100% 库存(完全按照 API 开发人员的想法做)更容易,但如果你想稍微定制,Cocoa 似乎更简单灵活由于它大量使用委托。只是我在那里的经验;我没有写很多 Android 代码。
    • @RobNapier -- 我说的是语言,而不是 UI 平台。而且 Android 是一个糟糕的设计,与选择 Java 作为主要语言完全无关。
    猜你喜欢
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多