java - Scanner 为什么要实现 Iterator<String>?

标签 java oop design-patterns java.util.scanner

我只是想知道为什么 java.util.Scanner工具 java.util.Iterator

Scanner 实现了 remove方法并抛出 UnsupportedOperationException .

但是类在实现接口(interface)时不应该履行接口(interface)的契约吗?

实现iterator并添加一个抛出异常的方法有什么用?

为什么不直接避免接口(interface)的实现并保持简单呢?

有人可能会争辩说,它的定义是为了让可能扩展 Scanner 的类可以实现该方法,例如 AbstractList有一个 add抛出 UnsupportedOperationException 的方法。但是 AbstractList 是一个 abstract 类,而 Scanner 是一个 final 类。

这不是一个糟糕的设计实践吗?

最佳答案

我会说是的,这是一个设计缺陷。该缺陷存在于 Iterator 中。此问题可能与尝试创建不可变的 Collection 实现属于同一类别。

它违反了Interface Segregation Principle并强制开发人员包含 corner case进入JavaDocs (臭名昭著的 UnsupportedOperationException)以避免违反 Liskov Subsitution Principle .您会在 Collection#remove 中找到它方法也是如此。


我相信可以通过分解接口(interface)、将 hasNext()next() 分离到一个新的(不可变的)接口(interface)并让(可变的)Iterator 接口(interface)派生自它:

interface Traversable<E> {
    boolean hasNext();
    E next();
}

interface Iterator<E> extends Traversable<E> {
    void remove();
}

final class Scanner implements Traversable<String> {

}

绝对可以使用更好的名称。由于我错误的命名选择,请不要关闭这篇文章。

为什么Scanner首先要实现Iterator

Scanner 不是遍历集合意义上的迭代器。但是 Scanner 的想法是为其提供“scanned”输入,这在某种意义上迭代某些东西(中的字符一个 String)。

我明白为什么 Scanner 会实现 Iterator(您要求的是用例)。例如,如果您想创建自己的 Iterable 类型来迭代指定分隔符的 String:

class ScannerWrapper implements Iterable<E> {
    public Scanner scanner;

    public ScannerWrapper(Scanner scanner) {
        this.scanner = scanner;
    }

    public Iterator<String> iterator() {
        return scanner;
    }
} 

Scanner scanner = new Scanner("one,two,three");
scanner.useDelimiter(",");
ScannerWrapper wrapper = new ScannerWrapper(scanner);

for(String s : wrapper) {
    System.out.println(s);
}

但如果 JDK 支持 Traversable 类型并允许增强循环接受 Traversable 项,这也会起作用,因为以这种方式从集合中删除可能会抛出ConcurrentModificationException,导致改用迭代器。

结论

那么它是好的设计吗?没有。它违反了 ISP 并导致契约(Contract)困惑。这简直就是一种巨大的代码味道。真正的问题是该语言缺乏对不变性的支持,这应该允许开发人员指定行为是否应该改变状态,从而允许行为契约被剥夺其可变性。或者类似的东西..

JDK 充满了这样的东西(糟糕的设计选择,例如为数组公开 length 并尝试我上面提到的 ImmutableMap),现在改变它会导致破坏代码。

关于java - Scanner 为什么要实现 Iterator<String>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31153006/

相关文章:

java - 无法在 Android Studio 中解析符号 'AsyncTask'

objective-c - Objective-C继承中@synthesize/@property的使用

oop - UML设计类图: Class with another class as attribute?

objective-c - 根据维基百科,为什么 "call super"被视为反模式?

oop - 首批第一本丛书中的objectville是什么?

java - 带有 git 的 Intellij - 内容仅在行分隔符上有所不同

java - 使用子类参数隐藏方法

java - 如何从jsp页面使用GMail SMTP服务器发送电子邮件?

java - 在 Java 中使用 OOP 实现 CQRS

wpf - 如果 View 和 View 模型之间不使用数据绑定(bind),MVVM 可以提供任何优势吗?