Files
endorphin-tabularium-docs/content/docs/smalltalk/04-object-protocol.md
T

2.6 KiB
Raw Blame History

对象协议:身份、复制与依赖

原书依据:第 7 章,印刷页 31–39,PDF 页 42–50。

Object 提供许多基础协议。阅读子类时,既要看它新增了什么,也要看它重写了什么。

身份与相等

== 判断是否为同一对象;= 表达由类定义的相等关系。两个内容相同的集合可以是两个不同对象。修改其中一个是否影响另一个,还取决于它们内部引用是否共享。

class 返回所属类。isMemberOf: 针对确切的类;isKindOf: 包含继承关系。检查 nil 通常使用 isNil 或 notNil。面向协议设计时,不必为了发送每条消息都先做具体类判断。

浅复制复制的是哪一层

原容器 ──→ 可变子对象
副本   ──→ 同一个可变子对象

浅复制产生新的外层对象,内部引用仍可指向相同子对象。给副本的某个槽位重新赋值,与修改该槽位所指子对象,是两种不同操作:前者改变副本自己的引用,后者可能被原对象观察到。

原书还讨论 deepCopy 和可被子类重写的 copy。深复制不应简单等同于“任意对象图都可以安全递归复制”:循环、共享关系和外部资源需要实现策略。本文没有对这些情况做运行验证。

表示与动态发送

消息 主要意图
printString 得到便于人阅读的表示
storeString 得到用于重建对象的源文本表示
perform: 用符号指定要发送的消息
perform:with: 动态发送带一个参数的消息

可读表示不等于持久化格式。动态发送也不是解析任意源代码:perform: 选择一个消息,而编译器求值会解释完整表达式。

用依赖通知连接对象

原书的依赖协议包含 addDependent:、removeDependent:、changed: 和 update:。模型改变后通知依赖者,让视图自行读取需要显示的状态。

视图注册到模型
    ↓
模型状态修改 → changed: 某方面
    ↓
依赖者收到 update: → 重新读取模型 → 更新显示

通知描述“需要更新”,并不天然携带完整的新状态。实现时要明确通知粒度、订阅解除和是否可能形成递归更新。原书的键盘互斥示例说明对象之间可以靠依赖关系协调状态;最后的 MVC 案例继续使用这套机制。

阅读检查点

对一个复制操作,画出复制前后的引用箭头;对一次通知,列出谁订阅、谁修改、谁通知、谁重绘。这两张简图往往比逐个记忆方法名更能暴露误解。