Java8供应商是可选的消费者



我只能用这个例子来解释这一点。

我们有主类AppServer。它还包含几个应用程序范围内的组件。

AppServer app = new AppServer(config, ...);

现在,我们需要提供一个供应商,作为一些Foo实例的工厂。该供应商将在循环中被多次调用,以创建一定数量的Foo实例。通过使用供应商,我们允许用户提供他们自己的Foo实现。注意,Foo不是我们的类,我们不能更改它。

唯一的问题是Foo需要应用程序中的一些组件。它们需要被注入/提供给FooImpl

可以这样写:

app.setFooSupplier(() -> new FooImpl(app.component()));

这对我来说有点丑陋,我想知道是否有更好的方法来做到这一点?以下是迄今为止的一些想法。。。

(1)使用供应商后注入依赖关系(IoC方式)。

依赖关系是用setter定义的。因此,我们有类似于(AppServer内部)的东西,在sudo中:

Foo foo = fooSupplier.get();
maybeInject(foo, component1);
maybeInject(foo, component2);
...

注入什么组件取决于setter是否存在。或者,我们可以使用Component1Aware接口,并执行以下操作:

Foo foo = fooSupplier.get();
if (foo instanceof Component1Aware) {
    ((Component1Aware)foo).setComponent1(component1);
}
...

这基本上是相同的。

我想在构造函数中有依赖项,所以为了表达它们需要设置。

(2)使用可选的消费者

FooImpl创建一个Supplier实例,该实例与AppServerConsumer处于同一时间。类似于:

public class FooImplSupplier implements Supplier<Foo>, Consumer<AppServer> {
    ...
}

然后我们可以很容易地注册这个供应商:

app.setFooSupplier(new FooImplSupplier());

供应商创建实例(在AppServer中)后,我们执行以下操作:

Foo foo = fooSupplier.get();
if (foo instanceof Consumer) {
    ((Consumer)foo).accept(this);
}

Wdyt?

我总是喜欢通过构造函数(或静态工厂方法)传递强制性设置。我更喜欢的IoC风格是

app.setFooSupplier(() -> new FooImpl(app.component()));

或者,如果app.component()每次都返回相同的内容,则可以编写以下内容。

Component comp = app.component();
app.setFooSupplier(() -> new FooImpl(comp));

这是迄今为止最简单也是最难出错的。例如,您不能传递参数0或多次,也不能在初始化之前尝试使用"供应商"。

向供应商提供上下文信息并不罕见。您遇到的问题是,您被固定在Supplier接口上,这会分散您对简单解决方案的注意力。与其尝试将SupplierConsumer组合,不如使用Function:

void setFooProvider(Function<AppServer,Foo> f) {
  this.fooProvider=Objects.requireNonNull(f);
}
// …
// in a method within the same class:
    Foo foo=fooProvider.apply(this);

来电者:

app.setFooProvider(appArg -> new FooImpl(appArg.component()));

我将方法的名称从…Supplier更改为…Provider,以明确所提供的参数的作用并不局限于特定的interface。您可以使用SupplierFunctionBiFunction或自定义interface,只要合适即可。

现在,指定的提供程序使用它的参数,而不从其周围的上下文中捕获值,这使它保持不变(对于当前的实现,它将是一个单例)。

请注意,仍然可以实现忽略参数的提供程序函数,这样就不会丢失基于Supplier的解决方案的原始功能。

最新更新