java退行_我想要的程序开发语言特性——之“面向对象”——之“退化”

本文探讨了Java 1.7中Iterator接口的remove方法问题,提出Java 8引入的接口默认实现作为解决方案。作者分析了接口退化的需求、现有挑战以及Java 8如何通过默认方法部分解决。同时,讨论了接口设计和里氏替换原则的关系,并展示了动态语言如Groovy和Python的灵活性。
摘要由CSDN通过智能技术生成

先从一个例子开始讲起,以下是jdk1.7中的迭代器接口的代码(去掉了注释的部分):

public interface Iterator {

boolean hasNext();

E next();

void remove();

}

程序开发的老油条们都不太喜欢这个接口的remove方法,原因可能是:

我们为自己实现Iterator接口时,基本不需要这个方法,但我们却不得不@Override它,此时通常我们会直接在方法体中写一行throw new UnsupportedOperationException();来搞定它。

这个方法的性能通常不太好,对ArrayList的迭代器频繁的做这个操作的性能远不如创建一个新的ArrayList对象。

或许,这个接口没有remove方法会更好,但这个接口已经这样了,要保持向上兼容的话,就不可能修改jdk去掉这个方法。

那么我们在不改变原有类的情况下,如何“退化”掉原有类中的方法呢?

当我们自己的类需要迭代器时,我们是否可以直接使用自己的接口,而不使用jdk自带的接口呢:

public interface MyIterator {

boolean hasNext();

E next();

}

这样当然是可以的,但这样就无法直接适配到jdk自带的集合框架了。

所以通常我们会这样做:

class MyIteratorImp implements Iterator {

private Iterator itr;

public MyIteratorImp(Iterator itr){

this.itr = itr;

}

public boolean hasNext() {

return itr.hasNext();

}

public Object next() {

return itr.next();

}

public void remove() {

throw new UnsupportedOperationException();    }

}

这里我们根本不需要remove方法,但我们不得不去实现它,因为这是Java的语法(这样实现多少会让人有点不爽)。

我们可能非常希望实现这样一个接口:

interface MyIterator extends Iterator {

不要这个方法: void remove();

}

这样,我们实现自己的迭代器时不需要再override remove方法,同时又是jdk标准接口Iterator的实现,这样基本上满足了我们要求。

不过遗憾的是,我们没有这样的语法。

或许有人认为这样做也是可以的(使用抽象类):

abstract class MyIteratorImp implements Iterator {

public void remove() {

throw new UnsupportedOperationException();

}

}

但抽象类相对于接口却有一个缺点:在一些不支持多重继承的语言中(例如Java),我们继承了抽象类之后就没有继承其它类的可能性了。

或许我们可以考虑在一门语言中实现一个“退化”的语法,这样就可以:

实现接口或类时可以从某接口或类中去掉一部分方法

在某些对象中去掉一部分方法。

在一些动态类型语言中已经有这样的功能了,比如Groovy和Python。

上面的第1点其实并非必须是动态语言才能实现的(但到现在我还没有看到哪个静态类型语言有这样的功能),但第2点就一定是动态语言才行了(因为有些情况下,不到运行时,我们无法确定对象会什么时候被创建出来,甚至创建对象的代码我们都不知道在哪里,我们只是使用这个对象)。

Java进化到Java8之后,有了一个不错的选择:接口默认实现。

实际上Jdk1.8中的Iterator接口的实现已经是这个样子了:

public interface Iterator {

boolean hasNext();

E next();

default void remove() {

throw new UnsupportedOperationException("remove");

}

default void forEachRemaining(Consumer super E> action) {

Objects.requireNonNull(action);

while (hasNext())

action.accept(next());

}

}

接口默认实现使“接口”在很大程度上变成了“抽象类”——Java本来不支持的多重继承在Java8开始已经在某种程度上打破了。

从设计模式的角度来看,对类或接口的退化能力似乎又违反“里氏替换原则”,不过既然一开始就是个错误,而且退化能力可以在一定程度上抹掉“先辈的罪”,那么有时候也不要太讲原则了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值