Java8 作为可选消费者的供应商
Java8 Supplier that is an optional Consumer
我只能用例子来解释这个。
我们有主要的 class、AppServer
。它还包含几个应用程序范围的组件。
AppServer app = new AppServer(config, ...);
现在我们需要提供一个供应商,作为一些 Foo
实例的工厂。该供应商将在循环中被多次调用以创建一定数量的 Foo
实例。通过使用供应商,我们允许用户提供他们自己的 Foo
实现。请注意,Foo
不是我们的 class,我们无法更改它。
唯一的问题是 Foo
需要应用程序中的某些组件。他们需要 injected/provided 到 FooImpl
。
可以这样写:
app.setFooSupplier(() -> new FooImpl(app.component()));
这对我来说有点难看,想知道是否有更好的方法来做到这一点?到目前为止,这里有一些想法...
(1) 使用 supplier 后注入依赖(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
实例,它与 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?
我总是赞成通过构造函数(或静态工厂方法)传递强制设置我更喜欢的 IoC 风格是
app.setFooSupplier(() -> new FooImpl(app.component()));
或者如果 app.component()
returns 每次都是同样的事情,你可以写下面的内容。
Component comp = app.component();
app.setFooSupplier(() -> new FooImpl(comp));
这是迄今为止最简单也是最难出错的。例如您不能传递一个参数 0 次或多次,或者在 Supplier 初始化之前尝试使用它。
向供应商提供上下文信息并不罕见。您遇到的问题是您固定在 Supplier
界面上,这会分散您对简单解决方案的注意力。与其尝试将 Supplier
与 Consumer
结合使用,不如使用 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
。您可以使用 Supplier
、Function
、BiFunction
或自定义 interface
,只要合适即可。
现在指定的提供者使用它的参数并且不从其周围的上下文中捕获值,这使得它不变(并且在当前的实现中它将是一个单例)。
请注意,仍然可以实现仅忽略参数的提供程序函数,因此不会丢失基于 Supplier
的解决方案的原始功能。
我只能用例子来解释这个。
我们有主要的 class、AppServer
。它还包含几个应用程序范围的组件。
AppServer app = new AppServer(config, ...);
现在我们需要提供一个供应商,作为一些 Foo
实例的工厂。该供应商将在循环中被多次调用以创建一定数量的 Foo
实例。通过使用供应商,我们允许用户提供他们自己的 Foo
实现。请注意,Foo
不是我们的 class,我们无法更改它。
唯一的问题是 Foo
需要应用程序中的某些组件。他们需要 injected/provided 到 FooImpl
。
可以这样写:
app.setFooSupplier(() -> new FooImpl(app.component()));
这对我来说有点难看,想知道是否有更好的方法来做到这一点?到目前为止,这里有一些想法...
(1) 使用 supplier 后注入依赖(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
实例,它与 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?
我总是赞成通过构造函数(或静态工厂方法)传递强制设置我更喜欢的 IoC 风格是
app.setFooSupplier(() -> new FooImpl(app.component()));
或者如果 app.component()
returns 每次都是同样的事情,你可以写下面的内容。
Component comp = app.component();
app.setFooSupplier(() -> new FooImpl(comp));
这是迄今为止最简单也是最难出错的。例如您不能传递一个参数 0 次或多次,或者在 Supplier 初始化之前尝试使用它。
向供应商提供上下文信息并不罕见。您遇到的问题是您固定在 Supplier
界面上,这会分散您对简单解决方案的注意力。与其尝试将 Supplier
与 Consumer
结合使用,不如使用 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
。您可以使用 Supplier
、Function
、BiFunction
或自定义 interface
,只要合适即可。
现在指定的提供者使用它的参数并且不从其周围的上下文中捕获值,这使得它不变(并且在当前的实现中它将是一个单例)。
请注意,仍然可以实现仅忽略参数的提供程序函数,因此不会丢失基于 Supplier
的解决方案的原始功能。