微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何为多接口继承启用类似构建器的模式?

如何解决如何为多接口继承启用类似构建器的模式?

首先,让我们定义我们的接口:

public interface Transformable<T> {
    <R extends Transformable<T>> R registerTransformation(Function<T,T> transformation);
    T process(T entity);
}
public interface HttpService<T> {
    T execute(URL url);
}

如接口 Transformable<T> 所示,我们可以创建一个简单的构建器模式来注册转换并在一行中执行所有转换,例如:

new DefaultTransformableImpl<Integer>(){}
    .registerTransformation(number -> number * 2)
    .registerTransformation(number -> number - 1)
    .registerTransformation(number -> number * number)
    .process(109845)

好的,现在我们已准备好创建 HttpService 的实现。这样做的想法是可以在实际将请求发送到服务器之前修改连接实例的标头、HTTP 方法...,而无需为 org.jsoup.Connection 接口指定方法适配器:

import java.util.function.Function;
import java.util.List;
import java.net.URL;
import org.jsoup.Connection;
import org.jsoup.helper.httpconnection;
import org.jsoup.nodes.Document;
import lombok.SneakyThrows;

public class JsoupHttpService implements HttpService<Document>,Transformable<Connection> {
    private final List<Function<Connection,Connection>> fns = new LinkedList<>();

    @Override public <R extends Transformable<Connection>> R registerTransformation(Function<Connection,Connection> transformation) {
        this.fns.add(transformation);
        return (R) this;
    }

    @Override public Connection process(Connection connection) {
        return fns.stream().reduce(Function.identity(),Function::andThen).apply(connection);
    }

    @SneakyThrows
    @Override public Document execute(URL url) {
        return this.process(httpconnection.connect(url)).execute().parse();
    }
}

这只是实际实现的简化,只关注问题的必要部分,可以通过尝试将 JsoupHttpService方法链接一起使用来看出:

public Document doSomething() {
    return new JsoupHttpService(){}
        .registerTransformation(connection -> connection.method(Connection.Method.GET))
        .registerTransformation(connection -> connection.userAgent("fake user-agent"))
        .execute("https://www.google.com")
        .parse();
}

如果你在你的 IDE 中尝试这个,它会说接近于 Cannot resolve method 'execute' in 'Transformable'...所以我想知道你们是否知道我该如何解决这个问题无需修改两个接口。 创建另一个扩展 HttpService 的接口并尝试在其中调整 Transformable 中定义的方法是我唯一的选择吗?

解决方法

问题是 registerTransformation 返回一个 TransformableTransformable 不是 HttpService

你可以通过这个实现你想要的:

JsoupHttpService service = new JsoupHttpService();
service.registerTransformation(connection -> connection.method(Connection.Method.GET));
service.registerTransformation(connection -> connection.userAgent("fake user-agent"));
service.execute();

似乎 Transformable 接口的作者没有正确理解何时适合使用 extends。对 (R) 的未经检查的强制转换应该是一个线索。

,

我建议几乎任何使用多重继承,甚至是接口,都是一个坏主意。此外,将泛型与类型继承混合会导致噩梦般的混乱 - 看看围绕 ComparableEnum 的怪异结构。

显然这不会阻止我修复代码。

如果你有一个类型参数只用于返回类型的方法,该方法的选项是:返回null,抛出异常,执行堆类型污染,不打扰返回或更糟.

对于构建器这类问题的解决方案是使用递归定义的类型参数混乱地参数化构建器类型,并可能添加一个抽象的“get this”方法(如果 Transformable 是抽象的,则更常见,因此可以有字段。

public interface Transformable<THIS extends Transformable<THIS,T>,T> {
    THIS registerTransformation(Function<T,T> transformation);
    T process(T entity);
}

public class JsoupHttpService implements HttpService<Document>,Transformable<Connection> {
    private final List<Function<Connection,Connection>> fns = new LinkedList<>();

    @Override public JsoupHttpService registerTransformation(Function<Connection,Connection> transformation) {
        this.fns.add(transformation);
        return this;
    }

对于“get this”,假设 Transformable 有一个通用的默认实现方法

    // Silly example.
    default THIS setSomethingWhichUsuallyHasNoEffect() {
        // In an abstract class,could assign fields here.
        return getThis(); // Cannot inline within source.
    }
    abstract THIS getThis(); // Would be protects in abstract class.

然后在 JsoupHttpService 中:

    @Override public JsoupHttpService getThis() {
        return this;
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。