37

我想请教大家对 Objective C 中的代码异味的看法,特别是 Cocoa Touch。我正在开发一款相当复杂的游戏,并且即将开始 Great December Refactoring。

我的很多类,尤其是模型,都充满了处理内部业务逻辑的方法;我将把它们隐藏在一个私有类别中,在我与大量头文件的战争中。那些私有类别包含大量声明,这让我感到不安……几乎就像 Objective-C 让我对所有这些方法感到内疚一样。

我重构得越多(一件好事!),我就越需要维护所有这些重复(不太好)。就是感觉不对。

在像 Ruby 这样的语言中,社区非常强调非常简短、清晰、漂亮的方法。我的问题是,对于 Objective C(特别是 Cocoa Touch),你的方法有多长,你的控制器有多大,以及每个类有多少方法在你的项目中变得很典型?在 Objective C 中是否有任何由短方法组成的类的特别好、漂亮的例子,或者这根本不是语言文化的重要组成部分?

披露:我目前正在阅读“The Little Schemer”,这应该可以解释我的悲伤,回复:目标 C。

4

3 回答 3

15

Beauty is subjective. For me, an Objective-C class is beautiful if it is readable (I know what it is supposed to do) and maintainable (I can see what parts are responsible for doing what). I also don't like to be thrown out of reading code by an unfamiliar idiom. Sort of like when you are reading a book and you read something that takes you out of the immersion and reminds you that you are reading.

You'll probably get lots of different, mutually exclusive advice, but here are my thoughts.

  • Nothing wrong with private methods being in a private category. That's what it is there for. If you don't like the declarations clogging up the file either use code folding in the IDE, or have your extensions as a category in a different file.
  • Group related methods together and mark them with #pragma mark statements
  • Whatever code layout you use, consistency is important. Take a few minutes and write your own guidelines (here are mine) so if you forget what you are supposed to be doing you have a reference.
  • The controller doesn't have to be the delegate and datasource you can always have other classes for these.
  • Use descriptive names for methods and properties. Yes, you may document them, but you can't see documentation when Xcode applies code completion, where well named methods and properties pay off. Also, code comments get stale if they aren't updated while the code itself changes.
  • Don't try and write clever code. You might think that it's better to chain a sequence of method calls on one line, but the compiler is better at optimising than you might think. It's okay to use temporary variables to hold values (mostly these are just pointers anyway, so relatively small) if it improves readability. Write code for humans to read.
  • DRY applies to Objective-C as much as other languages. Don't be worried about refactoring code into more methods. There is nothing wrong with having lots of methods as long as they are useful.
于 2010-12-09T11:47:47.463 回答
7

The very first thing I do even before implementing class or method is to ask: "How would I want to use this from the outside?"

I never ever, never begin by writing the internals of my classes and methods first. By starting of with an elegant public API the internals tend to become elegant for free, and if they don't then the ugliness is at least contained to a single method or class, and not allowed to pollute the rest of the code with it's smell.

There are many design patterns out there, two decades of coding have taught me that the only pattern that stand the test of time is: KISS. Keep It Simple Stupid.

Some general rules of thumb, for any language or environment:

  • Follow your gut feeling over any advice you have read or heard!
  • Bail out early!
    • If needed, verify inputs early and bail out fast! Less cleanup to do.
  • Never add something to your code that you do not use.
    • An option for "reverse" might feel like something nice to have down the road.
    • In that case add it down the road! Do not waste time adding complexity you do not need.
  • Method names should describe what is done, never how it is done.
    • Methods should be allowed to change their implementation without changing their name as long as the result is the same.
    • If you can not understand what a method does from it's name then change the name!
    • If the how part is complex enough, then use comments to describe your implementation.
  • Do not fear the singletons!
    • If your app only have one data model, then it is a singleton!
    • Passing around a single variable all over the place is just pretending it is something else but a singleton and adding complexity as bonus.
  • Plan for failures from the start.
    • Always use for doFoo:error instead of doFoo: from the start.
    • Create nice NSError instances with end user readable localized descriptions from the start.
    • It is a major pain to retrofit error handling/messages to a large existing app.
    • And there will always be errors if you have users and IO involved!
  • Cocoa/Objective-C is Object* Oriented, not **Class Oriented as most of the popular kids out there that claim to be OOP.
    • Do not introduce a dumb value class with only properties, a class without methods performing actual work could just as well be a struct.
    • Let your objects be intelligent! Why add a whole new FooParser class if a fooFromString: method on Foo is all you need?
  • In Cocoa what you can do is always more important than what you are.
    • Do not introduce a protocol if a target/action can do.
    • Do not verify that instances conforms to protocols, is a kind of class, that is up to the compiler.
于 2010-12-12T11:44:05.047 回答
2

我的 2 美分:

  1. 属性通常比老式的 getter+setter 更好。即使您使用@dynamic 属性 - 使用@property 声明它们,这也会提供更多信息且更短。
  2. 我个人不会模拟类的“私有”方法。是的,我可以在 .m(m) 文件的某处写一个类别,但是由于 Obj-C 没有纯粹的方法来声明私有方法——我为什么要发明一个?无论如何,即使您真的需要类似的东西 - 声明一个带有类别的单独“MyClassPrivate.h”并将其包含在 .m(m) 文件中以避免重复声明。
  3. 绑定。绑定大多数控制器 <-> UI 关系,使用转换器、格式化程序,只是不要编写手动读取/写入控件值的方法。它使代码看起来像 MFC 时代的东西。
  4. C++,很多代码在用 C++ 编写时看起来更好更短。由于编译器理解 C++ 类,因此它是重构的一个好点,尤其是在处理低级代码时。
  5. 我通常拆分大控制器。超过500 行代码对我来说是重构的好候选。例如,我有一个文档窗口控制器,因为它使用图像导入/导出选项扩展了某些版本的应用程序。控制器增长到 1.000 行,其中 1/2 是“图像内容”。这是我制作 ImageStuffController、在 NIB 中实例化它并将所有与图像相关的代码放入其中的“触发器”。

All above make it easier for me to maintain my code. For a huge projects, where splitting the controllers and classes to keep 'em small results big number of files, I usually try to extract some code into a framework. For example, if a big part of the app is communicating with external web-services, there is usually a straight way to extract a MyWebServices.framework from the main app.

于 2010-12-09T11:24:41.793 回答