简体   繁体   English

Java8 Supplier是可选的使用者

[英]Java8 Supplier that is an optional Consumer

I can explain this one only with the example. 我只能用示例来解释这一点。

We have the main class, AppServer . 我们有主类AppServer It holds also several application-wide components. 它还包含几个应用程序范围内的组件。

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

Now we need to provide a supplier that will act as a factory for some Foo instances. 现在,我们需要提供一个供应商,该供应商将充当某些Foo实例的工厂。 This supplier will be called several times in the loop to create some amount of the Foo instances. 该供应商将在循环中多次调用,以创建一定数量的Foo实例。 By using the supplier, we allow users to provide their own implementation of the Foo . 通过使用供应商,我们允许用户提供他们自己的Foo实现。 Note that Foo is NOT our class and we can NOT change it. 请注意, Foo不是我们的课程,我们无法对其进行更改。

The only problem is that Foo requires some of the components from the application. 唯一的问题是Foo需要应用程序中的某些组件。 They need to be injected/provided to the FooImpl . 需要将它们注入/提供给FooImpl

This can be written like this: 可以这样写:

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

This is kind of ugly for me and wonder if there is a better way to do this? 这对我来说有点丑陋,想知道是否有更好的方法可以做到这一点? Here are some ideas so far... 到目前为止,这里有一些想法...

(1) Inject dependencies after supplier is used (IoC way). (1)在使用供应商后注入依赖关系(IoC方式)。

Dependencies are defined with the setters. 依赖项由设置器定义。 So we have something like (inside of AppServer ), in sudo: 所以我们在sudo中有类似(在AppServer内部):

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

What component is injected depends if the setter is there. 注入什么成分取决于设置器是否在那里。 Alternatively, we can have Component1Aware interfaces and do the same like: 另外,我们可以拥有Component1Aware接口,并执行类似的操作:

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

which is basically the same. 基本上是一样的

I would like to have dependencies in constructor, so to express they need to be set. 我想在构造函数中具有依赖项,因此要表达它们需要进行设置。

(2) Use optional Consumer (2)使用可选的使用者

Create a Supplier instance for FooImpl that is in the same time Consumer of the AppServer . FooImpl创建一个Supplier实例,同时将其作为AppServer Consumer Something like: 就像是:

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

and then we can register this supplier very easily: 然后我们可以很容易地注册该供应商:

app.setFooSupplier(new FooImplSupplier());

and after the supplier creates an instance (in AppServer ) we do the following: 在供应商创建实例(在AppServer )之后,我们执行以下操作:

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

Wdyt? Wdyt?

I always favour passing mandatory settings via the constructor (or a static factory method) The IoC style I prefer is 我总是喜欢通过构造函数(或静态工厂方法)传递强制设置,我更喜欢的IoC样式是

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

or you could write the following if app.component() returns the same thing each time. 或者,如果app.component()每次返回相同的内容,则可以编写以下内容。

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

This is by far the simplest and the hardest to get wrong. 到目前为止,这是最简单,最难弄错的。 eg you can't pass an argument 0 or multiple times, or try to use the Supplier before it is initialised. 例如,您不能传递参数0次或多次,或尝试在初始化之前使用Supplier。

It is not unusual to provide context information to a supplier. 向供应商提供上下文信息并不罕见。 The problem you have is that you are fixed on the Supplier interface which distracts you from the simple solution. 您遇到的问题是您已固定在“ Supplier界面上,这使您无法使用简单的解决方案。 Instead of trying to combine the Supplier with a Consumer you should use a Function : 与其尝试将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);

Caller: 呼叫者:

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

I changed the method's name from …Supplier to …Provider to make clear that the role of the provided argument is not tight to a particular interface . 我将方法的名称从…Supplier更改为…Provider ,以表明所提供参数的作用并不特定于某个interface You may use Supplier , Function , BiFunction , or a custom interface , whatever fits. 您可以根据需要使用SupplierFunctionBiFunction或自定义interface

Now the specified provider uses it's argument and doesn't capture values from its surrounding context which makes it invariant (and with the current implementation it will be a singleton). 现在,指定的提供程序将使用它的参数,并且不会从其周围的上下文中捕获值,这使其保持不变(并且对于当前的实现,它将是单例)。

Note that it is still possible to implement provider functions which simply ignore the argument so the original functionality of the Supplier based solution is not lost. 请注意,仍然可以实现仅忽略参数的提供程序功能,从而不会丢失基于Supplier的解决方案的原始功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM