The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:
类型转换是一种非常有用的技术,当没有时间或意愿去仔细思考和设计对象时,它可以派上用场。类型转换(或类转换)可以帮助我们根据对象所属的类或实现的接口,以不同的方式处理提供的对象。类转换可以帮助我们对贫穷的对象进行区分,并根据它们的种族、性别和宗教分开它们。这是否是一种好的实践呢?
这是一个非常典型的类型转换示例(例如,Google Guava中充满了这种技术,比如Iterables.size()
)。
sizeOf()
方法用于计算可迭代对象的大小。然而,它足够智能,能够理解如果 items
也是 Collection
的实例,就无需实际迭代它们。将它们转换为 Collection
并调用 size()
方法会更快。这看起来很合理,但这种方法有什么问题呢?我认为有两个实际问题。
首先,sizeOf()
和 Collection
之间存在 隐藏的耦合。这种耦合对于 sizeOf()
的客户端是不可见的。他们不知道 sizeOf()
方法依赖于接口 Collection
。如果我们明天决定更改这个接口,sizeOf()
将无法工作。而且我们会感到非常惊讶,因为它的签名对这种依赖没有任何说明。当然,这在 Collection
中不会发生,因为它是 Java SDK 的一部分,但在自定义类中,这种情况可能会发生,而且确实会发生。
第二个问题是 sizeOf()
方法的 不可避免的复杂性增加。它必须处理越来越多的特殊类型,它的复杂性也会随之增加。这种 if/then
分支是不可避免的,因为它必须检查所有可能的类型并给予它们特殊处理。这种复杂性违反了单一责任原则。该方法不仅计算 Iterable
的大小,还执行类型转换并根据该转换进行分支。
那么有什么替代方案呢?有几种选择,但最明显的是方法重载(在 Ruby 或 PHP 等非完全面向对象的语言中不可用)。
那不是更优雅吗?
从哲学角度来看,类型转换是对进入方法的对象的歧视。该对象遵守方法签名提供的合同。它实现了Iterable
接口,这是一个合同,它期望与进入同一方法的所有其他对象受到平等对待。但是,该方法通过对象的类型来区分它们。该方法基本上在询问对象属于什么种族。黑色对象向右走,白色对象向左走。这就是instanceof
的作用,也是歧视的本质。
通过使用instanceof
,该方法将进入的对象按照它们所属的特定组别进行分离。在这种情况下,有两个组别:集合和其他所有对象。如果你是一个集合,你会得到特殊待遇。即使你遵守了Iterable
的合同,我们仍然会特别对待某些对象,因为它们属于一个被称为Collection
的“精英”组。
你可能会说Collection
只是另一个对象可能遵守的合同。这是对的,但在这种情况下,那些按照该合同工作的对象应该通过另一扇门进入。你宣布sizeOf()
接受所有遵守Iterable
合同的对象。我是一个对象,我按照合同做事。我进入方法,并期待与进入同一方法的其他所有对象一样受到平等对待。但是,显然,一旦进入方法,我意识到一些对象有一些特权。那不是歧视吗?
总之,我认为instanceof
和类转换是反模式和代码异味。一旦你发现需要使用它们,就应该开始考虑重构。
Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 17:10