如何在Java 8中使用子类进行方法链接

时间:2017-10-10 09:49:41

标签: java generics java-8 method-chaining

我跟着this pattern在Java中用子类实现方法链接。目标是我在超类上有一个方法,但可以分配子类,如:

interface Screen {
    <T extends Screen> T setBrightness(int value);
    <T extends Screen> T setContrast(int value);
}

class CrtScreen implements Screen {

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Screen> T setBrightness(int value) {
        // ...
        return (T) this;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Screen> T setContrast(int value) {
        // ...
        return (T) this;
    }
}

class ColorCrt extends CrtScreen { /* ... */ }

public static void main(String[] args) {
    ColorCrt cc = new ColorCrt().setBrightness(50).setContrast(50);
}

现在我还有我想要添加对象的容器对象,例如:

class Stuff {
    Stuff add(Screen s) {
        // ...
        return this;
    }

    Stuff add(String s) {
        // ...
        return this;
    }

    Stuff add(int i) {
        // ...
        return this;
    }
}

public static void main(String[] args) {
    new Stuff().add(new ColorCrt().setBrightness(50).setContrast(50)).add(25).add("...");
}

现在不再适用于Java 8,给我方法add(Screen)对于Stuff 类型是不明确的。我理解为explained here的原因。我目前只看到两个选项:

  • 我不使用<T extends,而只使用Screen setBrightness(value)。我需要选择将我的实现类分配给一个相应的变量,当我想执行一个特定于实现的方法时,我必须抛出它。

  • 我必须在方法链中添加强制转换或类型参数。这非常难看 阅读并难以修复必须从Java 7移植的大型构造(许多级别的装箱)。

有没有办法在Java 8中实现方法链接,这样我仍然有两个功能?如果没有,那么这两种方法中的一种是否可以被更多地考虑?

2 个答案:

答案 0 :(得分:0)

在您的代码中:

class CrtScreen implements Screen {

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Screen> T setBrightness(int value) {
        // ...
        return (T) this;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Screen> T setContrast(int value) {
        // ...
        return (T) this;
    }
}

您的成员函数setContrast和setBrightness不需要是通用的,如果它是通用的,您需要指定类型(在调用站点)。我使用这种方法,而不是使接口通用,这意味着方法不需要:

interface Screen<T extends Screen> {
    T setBrightness(int value);
    T setContrast(int value);
}

class CrtScreen implements Screen<CrtScreen> {
    @SuppressWarnings("unchecked")
    @Override
    public CrtScreen setBrightness(int value) {
        // ...
        return this;
    }

    @SuppressWarnings("unchecked")
    @Override
    public CrtScreen setContrast(int value) {
        // ...
        return this;
    }
}

如果您想按照自己的方式进行操作,则需要指定哪种类型适用于通用(见下文):

public static void main(String[] args) {
    new Stuff()
     .add(new ColorCrt().<ColorCrt>setBrightness(50))
     .add(25).add("...");
}

答案 1 :(得分:0)

最后,我找到了一个适用于interfaceabstract class的解决方案。这似乎足以满足Java 8编译器。

概念证明:

static abstract class Screen {
    abstract <T extends Screen> T setBrightness(int value);
    abstract <T extends Screen> T setContrast(int value);
}

static class CrtScreen extends Screen {

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Screen> T setBrightness(int value) {
        // ...
        return (T) this;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Screen> T setContrast(int value) {
        // ...
        return (T) this;
    }
}

static class ColorCrt extends CrtScreen { /* ... */ }

static class Stuff {
    Stuff add(Screen s) {
        return this;
    }

    Stuff add(String s) {
        return this;
    }

    Stuff add(int i) {
        return this;
    }
}

public static void main(String[] args) {
    ColorCrt cc = new ColorCrt().setBrightness(50).setContrast(50);
    new Stuff().add(new ColorCrt().setBrightness(50).setContrast(50)).add(25).add("...");
}