其实你说的还不错。
事实是,comb 的“实例”几乎总是一个坏主意(例如,当您进行编组或序列化时会发生异常,在很短的时间间隔内您可能没有手头的所有类型信息。)正如 josh 所说,否则这是一个糟糕的类层次结构的标志。
您知道这是一个坏主意的方式是它使代码变得脆弱:如果您使用它,并且类型层次结构发生变化,那么它可能会在它出现的任何地方破坏该梳子的实例。更重要的是,你会失去强类型的好处;编译器无法通过提前捕获错误来帮助您。(这有点类似于 C 中类型转换引起的问题。)
更新
让我稍微扩展一下,因为从评论看来我不太清楚。您在 C 中使用类型转换的原因,或者instanceof
,您想说“好像”的原因:将其foo
用作bar
. 现在,在 C 中,根本没有运行时类型信息,所以您只是在没有网络的情况下工作:如果您对某些内容进行类型转换,生成的代码将把该地址视为包含特定类型,无论如何,并且您应该只希望它会导致运行时错误,而不是默默地破坏某些东西。
鸭子打字只是将其提升为常态。在像 Ruby、Python 或 Smalltalk 这样的动态弱类型语言中,一切都是无类型引用;你在运行时向它发送消息,看看会发生什么。如果它理解一个特定的信息,它就会“像鸭子一样走路”——它会处理它。
这可能非常方便和有用,因为它允许奇妙的 hack,例如将生成器表达式分配给 Python 中的变量,或将块分配给 Smalltalk 中的变量。但这确实意味着您在运行时容易受到强类型语言在编译时可以捕获的错误的影响。
在像 Java 这样的强类型语言中,您根本不能真正严格地进行鸭式类型:您必须告诉编译器您将要处理的东西是什么类型。您可以通过使用类型转换来获得类似鸭子类型的东西,这样您就可以执行类似的操作
Object x; // A reference to an Object, analogous to a void * in C
// Some code that assigns something to x
((FoodDispenser)x).dropPellet(); // [1]
// Some more code
((MissleController)x).launchAt("Moon"); // [2]
现在在运行时,只要 x 是一种FoodDispenser
at [1] 或MissleController
at [2] 就可以了;否则繁荣。或者出乎意料,没有繁荣。
在您的描述中,您通过使用else if
和instanceof
Object x ;
// code code code
if(x instanceof FoodDispenser)
((FoodDispenser)x).dropPellet();
else if (x instanceof MissleController )
((MissleController)x).launchAt("Moon");
else if ( /* something else...*/ ) // ...
else // error
现在,您可以免受运行时错误的影响,但您有责任稍后在else
.
但是现在假设您对代码进行了更改,因此“x”可以采用“FloorWax”和“DessertTopping”类型。您现在必须检查所有代码并找到该梳子的所有实例并修改它们。现在代码是“脆弱的”——需求的变化意味着大量的代码变化。在 OO 中,您正在努力使代码不那么脆弱。
OO 解决方案是使用多态性,您可以将其视为一种有限的鸭子类型:您定义了可以信任执行的所有操作。你可以通过定义一个高级类来做到这一点,可能是抽象的,它具有低级类的所有方法。在 Java 中,像这样的类最好表示为“接口”,但它具有类的所有类型属性。实际上,您可以将接口视为一种承诺,即可以信任特定类以“就好像”它是另一个类一样。
public interface VeebleFeetzer { /* ... */ };
public class FoodDispenser implements VeebleFeetzer { /* ... */ }
public class MissleController implements VeebleFeetzer { /* ... */ }
public class FloorWax implements VeebleFeetzer { /* ... */ }
public class DessertTopping implements VeebleFeetzer { /* ... */ }
您现在所要做的就是使用对 VeebleFeetzer 的引用,编译器会为您计算出来。如果您碰巧添加了另一个属于 VeebleFeetzer 子类型的类,编译器将选择该方法并检查交易中的参数
VeebleFeetzer x; // A reference to anything
// that implements VeebleFeetzer
// Some code that assigns something to x
x.dropPellet();
// Some more code
x.launchAt("Moon");