如何在调用任何函数之前在Fluent API中传递参数?

时间:2015-11-16 09:48:44

标签: java

我有这种类

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

的内容

enter image description here

我的问题是什么

如何在variable列表之前将choices传播到之前调用任何其他函数的所有对象(在上面的简单示例中调用execute之前) ,因为这个函数使用(并且可以修改)这个变量。)

我尝试了什么

  • 我无法使用构造函数执行此操作,因为我没有对变量的引用

    public AImpl(String variable) {
        this.variable = variable;
    }
    
  • 此代码无效,因为变量将在所有函数

    之后设置
    @Override
    public A choice(A... choices) {
        for(A a : choices) {
            a.setVariable(variable);
        }
    }
    
  • 我尝试使用Builder(例如,设置所有值,仅在选择函数中创建最后的实例)。但链接函数executechoice...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();
        }
    }
    

2 个答案:

答案 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();
        }
    }