【问题标题】:Java8 Supplier that is an optional Consumer作为可选消费者的 Java8 供应商
【发布时间】:2015-03-26 07:39:32
【问题描述】:

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

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

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

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

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

可以这样写:

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

这对我来说有点难看,想知道是否有更好的方法来做到这一点?到目前为止,这里有一些想法......

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

依赖项是使用 setter 定义的。所以我们在 sudo 中有类似(AppServer 内部)的内容:

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 实例,该实例与AppServer 在同一时间Consumer。比如:

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?

【问题讨论】:

  • 看起来您正在尝试实现自己的依赖注入框架。为什么不使用已建立的依赖注入框架之一,例如 Spring 或 Google Guice?
  • @Jesper 我不会使用框架来替换一个衬里。恕我直言,这太过分了。
  • 即使我使用像Petite 这样的最小ioc,也将是一个极端的矫枉过正。只需要连接几个组件,仅此而已。

标签: java functional-programming java-8


【解决方案1】:

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

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

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

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

这是迄今为止最简单且最难出错的方法。例如您不能将参数传递 0 次或多次,或者尝试在 Supplier 初始化之前使用它。

【讨论】:

  • 在等式两边都使用app 会不会打扰您?我们告诉app 使用一些实例(由Supplier 提供),数据已经在app 中 - 这似乎是不必要的步骤...... wdyt?
  • @игор 不是真的,但如果它打扰你,你可以使用一个局部变量,如果值没有改变。
【解决方案2】:

向供应商提供上下文信息并不罕见。您遇到的问题是您固定在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 的解决方案的原始功能。

【讨论】:

    猜你喜欢
    • 2018-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多