我有这种类
public class AImpl implements A {
private String variable = "init";
@Override
public A choice(A... choices) {
return this;
}
@Override
public A execute() {
variable = "execute";
return this;
}
}
我可以像这样使用它(简单的例子)
new AImpl().choice(
new AImpl[] {
new AImpl().execute(),
new AImpl()
};
)
或者像这样(更复杂的例子,具有可变的期望值)
new AImpl().choice( //variable == "init"
new AImpl[] {
new AImpl().execute(), //variable == "init". Set to "execute"
new AImpl().choice( //variable == "init"
new AImpl[] {
new AImpl() //variable == "init"
}
),
new AImpl().execute().choice( //variable == "init". Set to "execute"
new AImpl[] {
new AImpl(), //variable == "execute"
new AImpl() //variable == "execute"
}
),
};
)
我想要实现的目标
每次有选择时,我都希望将variable
的最后一个值传播到每个新实例。这是复杂示例的图形版本,其中我圈出了我称之为 propagation
我的问题是什么
如何在variable
列表之前将choices
传播到之前调用任何其他函数的所有对象(在上面的简单示例中调用execute
之前) ,因为这个函数使用(并且可以修改)这个变量。)
我尝试了什么
我无法使用构造函数执行此操作,因为我没有对变量的引用
public AImpl(String variable) {
this.variable = variable;
}
此代码无效,因为变量将在所有函数
之后设置@Override
public A choice(A... choices) {
for(A a : choices) {
a.setVariable(variable);
}
}
我尝试使用Builder
(例如,设置所有值,仅在选择函数中创建最后的实例)。但链接函数execute
或choice
(...execute().execute().choice()...
)是有意义的。因此,建造者变得难以创造并且可能变得非常大。
我还尝试将变量移动到context
类,但如果在choices
我有另一种选择(更复杂的例子的情况),它就无法工作。这是我当前的上下文类
public class Context {
private static Context instance = null;
private String variable;
private Context(){};
public String getVariable() {
return variable;
}
public void setVariable(String variable) {
this.variable = variable;
}
public static void set(String variable) {
if(Context.instance == null)
Context.instance = new Context();
Context.instance.setVariable(variable);
}
public static String get() {
if(Context.instance == null)
throw new NullPointerException();
return Context.instance.getVariable();
}
}
答案 0 :(得分:1)
问题是新的AImpl实例需要继承其父母"的上下文。简单实例,即调用choice()
的实例。您无法使用new
运算符执行此操作。您应该使用一个方法来创建具有继承variable
的实例。
public A[] createChoices(int count, A optionalDefaultValues...) {
// return an array of clones of itself (possibly with adjusted defaults)
}
答案 1 :(得分:0)
我终于找到了一种基于Context
方法的工作解决方案(参见我尝试了什么?)
主要想法
有两个主要想法。第一个是用Stack
这样的变量替换(在上下文对象内)单个变量
Stack<String> variables = new Stack<>();
我在第一个构造函数中推送第一个变量,我可以使用pop/push
函数访问和修改它
String variable = Context.pop();
//Do something with variable
Context.push("anotherValue");
第二个主要想法是每次创建新选项时重复堆栈顶部的值和在每次选择结束时删除它。
我的代码
这是我的代码,如果它可以帮助别人。我确信有很多事情要做,以改善它,但它解决了我原来的问题。
TestSo.java
public class TestSo {
@Test
public void testSo() {
AImpl.create().choice(
new ChoiceList()
.add(AChoice.create().execute())
.add(AChoice.create().choice(
new ChoiceList().add(AChoice.create())
))
.add(AChoice.create().execute().choice(
new ChoiceList()
.add(AChoice.create())
.add(AChoice.create())
))
);
}
}
A.java
public interface A {
A choice(ChoiceList choices);
A execute();
}
AAbstract.java
public class AAbstract implements A {
@Override
public A choice(ChoiceList choices) {
return this;
}
@Override
public A execute() {
String variable = Context.get();
//...
Context.set("execute");
return this;
}
}
AImpl.java
public class AImpl extends AAbstract {
private AImpl() {
Context.set("init");
}
public static AImpl create() {
return new AImpl();
}
}
AChoice.java
public class AChoice extends AAbstract {
private AChoice() {
Context.duplicate();
}
public static AChoice create() {
return new AChoice();
}
@Override
public AChoice choice(ChoiceList choices) {
super.choice(choices);
return this;
}
@Override
public AChoice execute() {
super.execute();
return this;
}
}
ChoiceList.java
public class ChoiceList {
private List<AChoice> choices = new ArrayList<>();
public ChoiceList add(AChoice choice) {
Context.remove();
choices.add(choice);
return this;
}
}
Context.java
public class Context {
private static Context instance = null;
private Stack<String> variables = new Stack<>();
private Context(){};
public String peek() {return variables.peek();}
public String pop() {return variables.pop();}
public void fork() {variables.push(variables.peek());}
public void push(String variable) {variables.push(variable);}
public static void set(String variable) {
if(Context.instance == null)
Context.instance = new Context();
Context.instance.push(variable);
}
public static String get() {
if(Context.instance == null)
throw new NullPointerException();
return Context.instance.pop();
}
public static void remove() {
if(Context.instance == null)
throw new NullPointerException();
Context.instance.pop();
}
public static void duplicate() {
if(Context.instance == null)
throw new NullPointerException();
Context.instance.fork();
}
public static String read() {
if(Context.instance == null)
throw new NullPointerException();
return Context.instance.peek();
}
}