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


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


    public interface Iterator<E> {
        boolean hasNext();
        E next();
        void remove();
    }


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

    1. 我们为自己实现Iterator接口时,基本不需要这个方法,但我们却不得不@Override它,此时通常我们会直接在方法体中写一行throw new UnsupportedOperationException();来搞定它。
    2. 这个方法的性能通常不太好,对ArrayList的迭代器频繁的做这个操作的性能远不如创建一个新的ArrayList对象。

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

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

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


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


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

    所以通常我们会这样做:


    class MyIteratorImp implements Iterator<Object> {
        private Iterator<Object> itr;
        public MyIteratorImp(Iterator<Object> 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<T> extends Iterator<T> {
        不要这个方法: void remove();
    }


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

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

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


    abstract class MyIteratorImp<T> implements Iterator<T> {
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }


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

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

    1. 实现接口或类时可以从某接口或类中去掉一部分方法
    2. 在某些对象中去掉一部分方法。

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

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

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

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


    public interface Iterator<E> {
        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开始已经在某种程度上打破了。

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

  • 相关阅读:
    冒泡排序
    pdo 单例类
    php 事物处理
    支付宝支付
    反向代理和负载均衡
    execl导出
    网络层
    OSI 7层 TCP/IP 4层 综合5层
    面试总结
    CMD AMD
  • 原文地址:https://www.cnblogs.com/naturemickey/p/3855403.html
Copyright © 2020-2023  润新知