我们的代码如下所示:
Service<E,F> pipeline = new MyServiceDecorator2(new MyServiceDecorator1(new MyService()));
然后执行为 F f = pipeline.apply(new E("E"))
我们希望它的内容如下:
Service<A,B> myService = new MyService();
// Service<C,D>
MyServiceDecorator1 myServiceDecorator1 = new MyServiceDecorator1();
// Service<E,F>
MyServiceDecorator2 myServiceDecorator2 = new MyServiceDecorator2();
Service<E,F> pipeline = myServiceDecorator2.andThen(myServiceDecorator1).andThen(myService);
// This should still be doable i.e., the end goal
F f = pipeline.apply(new E("E"));
我们尝试了各种技巧,但无法使返回类型正确排列。上面的代码会抛出一个错误 - 我们只是手动将 andThen
添加到每个 Decorator 类中,只是为了了解流程,如下所示:
public <J,K> Service andThen(Service<J,K> next) {
this.service = next;
return next;
}
这将返回链中“下一项”的类型。我尝试了一些使用 next/prev
引用/指针的技巧来沿着链向上移动,但似乎没有任何效果。这可能吗?
这是一个REPL显示带有打印语句的代码,显示装饰器的进展。
上下文:我们有相当多的代码可以简化为“装饰器”来实现“管道和过滤器”模式,这样我们就可以提供一个基本的“框架”,让开发者能够运用相同的模式/思维来解决相同的问题,而不是复制/面食或重新发明轮子。以上是我们想要实现的目标的“示例”。我们计划将其转换为泛型,但目前存在重复的代码。
最佳答案
编辑:正在研究另一种方法(我认为它有同样的问题......)
嗯,你无法真正获得你想要的东西,你需要在一些东西上进行权衡。
在本例中,它位于 apply
方法上,该方法必须接受 Domain
。
发生这种情况是因为包装的 Service
未在构造时设置,因此无法 100% 键入。
interface Service<A extends Domain, B extends Domain> {
B apply(final Domain a);
Service<A, B> andThen(final Service<? extends Domain, ? extends Domain> service);
}
<小时/>
class MyService implements Service<A, B> {
private Service<? extends Domain, ? extends Domain> wrapped;
@Override
public B apply(final Domain a) {
return new B(a.name + "->B");
}
@Override
public Service<A, B> andThen(final Service<? extends Domain, ? extends Domain> wrapped) {
this.wrapped = wrapped;
return this;
}
}
<小时/>
class MyServiceDecorator1 implements Service<C, D> {
private Service<? extends Domain, ? extends Domain> wrapped;
@Override
public D apply(final Domain input) {
// C->A
Domain a = new A(input.name + "->A");
// get B
Domain b = this.wrapped.apply(a);
// B->D
return new D(b.name + "->D");
}
public Service<C, D> andThen(final Service<? extends Domain, ? extends Domain> wrapped) {
this.wrapped = wrapped;
return this;
}
}
<小时/>
class MyServiceDecorator2 implements Service<E, F> {
private Service<? extends Domain, ? extends Domain> wrapped;
@Override
public F apply(final Domain input) {
// E->C
Domain c = new C(input.name + "->C");
// get D
Domain d = this.wrapped.apply(c);
// D->F
return new F(d.name + "->F");
}
@Override
public Service<E, F> andThen(final Service<? extends Domain, ? extends Domain> wrapped) {
this.wrapped = wrapped;
return this;
}
}
<小时/>
public static void main(String[] args) {
final Service<A, B> myService = new MyService();
MyServiceDecorator1 myServiceDecorator1 = new MyServiceDecorator1();
MyServiceDecorator2 myServiceDecorator2 = new MyServiceDecorator2();
final Service<E, F> efService =
myServiceDecorator2.andThen(myServiceDecorator1)
.andThen(myService);
// This should still be doable i.e., the end goal
F f = efService.apply(new E("E"));
System.out.println(f.name);
}
我无法做得更好,因为 Java 的泛型功能有限。
<小时/>结束语:字节码生成是您的 friend 。
关于java - 如何用方法注入(inject)替换装饰器中的构造函数注入(inject)以获得链接并使现有代码按原样工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55150648/