Lou*_*man 12 java design-patterns
正如我一直都理解的那样,一个instanceof合适的主要案例是:
Object.equals(Object).因此,如果我正在编写一个List类,而不是AbstractList出于任何原因进行扩展,我将equals(o)通过首先测试o instanceof List,然后比较元素来实现.Collections.binarySearch进行instanceof RandomAccess测试,并使用稍微不同的二进制搜索RandomAccess和非RandomAccess列表.instanceof在这两种情况下,我认为不代表代码气味.但是有没有其他情况下使用它是明智的instanceof?
回答你的问题的一种方法是回答"一个可靠的Java库何时使用instanceof?" 如果我们假设Guava是一个设计良好的Java库的例子,我们可以看看它instanceof用来决定何时可以接受.
如果我们提取Guava源代码jar并grep它,我们看到instanceof提到439次,跨122个文件:
$ pwd
/tmp/guava-13.0.1-sources
$ grep -R 'instanceof' | wc -l
439
$ grep -Rl 'instanceof' | wc -l
122
Run Code Online (Sandbox Code Playgroud)
看看其中一些案例我们可以看到几种模式出现:
检查是否平等
这是最常见的用法.这在某种程度上是特定于实现的,但假设您确实希望根据它扩展/实现的类/接口来测量相等性,您可以使用它instanceof来确保您正在使用的对象.但是,如果子类重写equals()并且不遵守与instanceof父级相同的要求,则可能会导致奇怪的问题.例子无处不在,但一个简单的一个是Lists.equalsImpl()其使用ImmutableList.
短路不必要的对象构造
您可以使用instanceof检查传入的参数是否可以安全地使用或返回而无需进一步转换它,例如,如果它已经是所需类的实例,或者我们知道它是不可变的.见例子CharMatcher.forPredicate(),Suppliers.memoize(),ImmutableList.copyOf(),等.
访问实现细节而不暴露不同的行为
这可以在Guava中的所有位置看到,但特别是在com.google.common.collect包中的静态实用程序类中,例如在可能的情况Iterables.size()下调用它的位置Collection.size(),否则O(n)及时计算迭代器中的项数.
为了避免打电话 toString()
我怀疑这个优点是在很少的情况下完成的,但假设你确定你做的是正确的事情,你可以避免不必要地将CharSequence对象转换成Strings instanceof,就像在做的那样Joiner.toString(Object).
要做复杂的异常处理
显然,"正确"的事情是使用一个try/catch块(尽管实际上,它instanceof已经在进行检查),但有时候你有更复杂的处理逻辑,值得使用条件块或将处理传递给单独的方法,例如拉出原因或具有特定于实现的处理.可以在中找到一个例子SimpleTimeLimiter.throwCause().
看待这种行为突出的一件事就是几乎所有这些都在解决我不应该解决的问题.它们在库代码中非常有用,例如在Iterables,但如果我实现这种行为,我应该问自己是否没有库或实用工具可以解决这个问题.
在所有情况下,我都会说instanceof检查应该只在内部用作实现细节 - 也就是说任何依赖于instanceof检查的方法的调用者都不应该(轻易地)告诉你你做了什么.例如,ImmutableList.copyOf()总是返回一个ImmutableList.作为一个实现细节,它用于instanceof避免构造新的ImmutableLists,但这不是可接受地提供预期行为所必需的.
顺便说一句,当我在挖掘Guava的源代码时,看到你的名字路易斯很有趣.我发誓我不知道!
您控制之外的旧代码或API是合法的用例instanceof.(即便如此,我宁愿在它上面写一个OO层,但时间安排有时会排除这样的重新设计.)
特别是,基于外部类层次结构的工厂似乎是常见的用法.