在Objective C中定义不可变类的最佳方法

时间:2010-04-05 01:15:41

标签: objective-c immutability

我是Objective C的新手,我想知道是什么 在Objective-C中定义不可变类的最佳方法(例如NSString)。

我想知道让一个类不可变的基本规则是什么。

我认为:

  • 不应提供setter
  • 如果使用属性,则应该只读
  • 要“禁用”键值编码,accessInstanceVariablesDirectly必须覆盖并返回NO

我忘记了什么吗?

由于

2 个答案:

答案 0 :(得分:13)

首先要做的是在.h文件中包含用法注释,说明这是一个不可变类,以及类的用途和一般用法指南。很多时候,人们会竭尽全力尝试用编译器“强制执行”,只需告知调用者即可实现。

如果您希望类是不可变的,那么您当然不应该提供公共setter或readwrite属性(但是当然提供私有setter以便您可以在类中使用访问器;您应该始终避免,甚至在内部,直接搞乱ivars,除了在一些地方)。我猜你可以添加你的accessInstanceVariablesDirectly覆盖,如果你认为这可能是调用者的错误。

但理解Objective-C的关键是理解并接受调用者不是敌人的事实。被调用的代码不需要被调用者“保护”。需要保护呼叫者免受可能的错误。每个人都站在同一边;调用者和调用者希望程序正常工作。

来电者是客户,应该这样对待。客户并不总是正确的,但客户始终是客户。有时这意味着如果他可能犯的一个容易的错误,保护客户免受他自己的伤害。 NSAssert()对此特别有用。将公共设置者提供给一个不可变的类几乎是欺骗调用者犯错误,这对每个人都是坏事。

无论如何,你不应该让你的班级过于复杂,试图强制执行不变性。调用者几乎(*)总是通过直接访问结构(object->ivar)来违反封装。打电话的人这样做是愚蠢的,但你试图阻止它会更加愚蠢。注意不变性,隐藏你的二传手并只读标记你的属性,几乎在所有情况下你应该没事。

(*)是的,通过将私有结构/对象嵌套为ivar,可以更加隐藏数据,但是调用者仍然可以使用指针算法修改数据,因此它仍然没有“强制执行”。总是问问自己,你真正想解决的问题是什么。

答案 1 :(得分:6)

我相信他们实现这一目标的方法是让头文件只包含公开所需的信息。其余的将进入源文件以限制可能的覆盖曝光。

由于Objective-C显然没有明确的方法将类定义为final(密封等),所以你能做的一切并不是真的包罗万象。

我很久以前得出结论,你真的不能使用Objective-C,就像你使用Java,C ++或C#一样。 Objective-C太不同了。事实上,我认为存在严重的范式差异,例如静态与动态方法调度/调用。

我提到这个的原因是因为Objective-C中的类可能不是真正的最终。也许这是通过语言设计而不是你应该试图绕过的东西。如果你这样做,你最终会不必要地使你的代码复杂化。