链接不同类实例和对象共享的方法

时间:2017-07-16 17:08:30

标签: java

以下示例代码......

  1. 有没有办法chain instances of different classes?提供的示例是尝试连接属于不同类实例的方法失败。

  2. 此外,在同一示例中,Client2正在与Client3共享错误对象。什么是sharing objects between subclasses and unassociated classes的更有效方式?

  3. 为清楚起见,我也在内联评论。

    感谢您的时间和帮助。

    示例代码

    public class StubRunner
    {
        public run(){
            ClientFactory client = new ClientFactory();
    
            //not correct. But, this is how i want to finally chain methods 
            //belonging to different class instances. Please advise.
            client.getClient1().testClient1().getClient2().testClient2().assert(...);
        }
    }
    public class ClientFactory
    {
        public Client1 getClient1(){return new Client1();}
        public Client2 getClient2(){return new Client2();}
    }
    public class BaseClient
    {
        public Errors errors = null; 
    }
    public class Client1 extends BaseClient
    {
        public void testClient1(){...}
    }
    public class Client2 extends BaseClient
    {
        public void testClient2()
        {
            //here i am directly passing the error object
            //what is a better way?
            //is there a more efficient way to make the SAME error object
            //available to Client3
            new Client3(this.errors).testClient3();
            ...
        }
    }
    public class Client3 extends BaseClient
    {
        public Client3(Errors errors){this.errors = errors;}
        public void testClient3(){...}
    }
    

5 个答案:

答案 0 :(得分:1)

当我想编写一个方法调用的短链时,我通常会使用lambda表达式,但我希望方法相对于任何类型的状态进行更改。至于你的场景,你的每个测试都是一个lambda表达式,这意味着我将testClient4方法传递给testClient3方法,testClient3方法传递给testClient2方法等等。但是,代码变得越来越丑陋您的方法调用链变长。

=>您可以使用Fluent接口:您可以让每个方法执行一些逻辑,然后返回一个实例,您可以在该实例上调用要执行的下一个内联方法。

  • ClientFactory.getClient1():Client1
  • Client1.testClient1():Client1(即返回此内容)
  • Client1.getClient2():Client2
  • Client2.testClient2()Client2(即返回此内容)
  • ...

显然,每个实例都需要引用下一个内联实例,知道它将调用的实例(Client1将引用Client2,Client2引用Client3等)。

这样可行,但在这种情况下,我不是粉丝!我说它比干净的编码更具诀窍。您应该单独使用每个客户端的流畅接口,除非您的某个方法实际上返回另一个实例:

  

client1.testClient1()。testClient2()。testClient3()   如果有充分的理由,每个测试方法返回下一个客户端的实例

但是在测试方法之间插入getClient方法是没有意义的......

答案 1 :(得分:0)

  

有没有办法链接不同类的实例?提供的示例是尝试连接属于不同类实例的方法失败。

client.getClient1().testClient1().getClient2().testClient2().assert(...);

为了链接这样的方法,每个方法必须返回一个对象的引用,该对象支持您要调用的方法。但是,每个测试方法都会返回void

在这种情况下,方法链接似乎非常值得怀疑,因为您在不同的类型上运行。像这样的链中的方法通常只是return this;,因此可以在启动链的完全相同的对象上调用另一个方法。

此外,您的方法名称表明您正在尝试对代码进行一些自动化测试。您应该了解已建立的测试技术和库。特别是,JUnit通常用于Java和其他语言的变体。在诸如此类的框架中编写测试时,某些技术被认为是很好的做法。

要明确这一点,你当然不应该将测试代码与生产代码混合在一起。

  

此外,在同一示例中,Client2与Client3共享错误对象。什么是在子类和非关联类之间共享对象的更有效方法?

//here i am directly passing the error object
//what is a better way?
//is there a more efficient way to make the SAME error object
//available to Client3
new Client3(this.errors).testClient3();

将对象发送到类的唯一方法是将参数传递给构造函数或方法。这就是Java的工作原理。

请注意,由于您传递的是引用变量,因此开销很小。您没有复制整个对象。这意味着Client2的当前实例和Client3的新实例都引用了相同的错误对象

答案 2 :(得分:0)

我并没有真正得到你真正需要的东西,但是在代码的实际状态下它甚至无法编译,因为你试图从"客户端" void方法返回的对象。

如果您不知道有多少客户端以及您将从哪种类型获得,我只需使用一个列表。

如果您想使用' testClient'来链接客户端。方法,然后首先这个方法应该返回下一个客户端(这是一种非常笨拙的方式链接对象),然后你应该开始使用更多的抽象和重写技术。

基本上,只要它是" BaseClient",就没有必要知道你正在处理什么对象,但如果你命名子方法" testClient1" ," testClient2"等等...你基本上打破它,你需要开始考虑你实际得到的东西,并相应地调整你的代码。

最后,这里不需要工厂,但如果你想要工厂,它应该是静态的。

这是一个有效的例子,我并不真正理解你想做什么,所以它可能无法解决你的问题,但它是一个有效的解决方案,以及#34;链接实例":

主要

public class Foo
{
    // arguments are passed using the text field below this editor
    public static void main(String[] args)
    {
        StubRunner stub = new StubRunner();
        stub.run();
    }

}

<强> Stubrunner:

public class StubRunner implements Runnable
{
    public void run(){

        Object clients = ClientFactory.getClient1();

        while (null!= clients && clients instanceof BaseClient) {

            clients = ((BaseClient) clients).test();            
        }
    }
}

<强>基

public abstract class BaseClient
{
    public Exception errors = null; 



    public BaseClient() {};
    public BaseClient(Exception errors) {
        this.errors = errors;
    }

    public abstract BaseClient test();

    public void checkErrors() {
        System.out.println(this.toString());
        assert null == errors;
    }
}

客户1:

public class Client1 extends BaseClient
{
    public BaseClient test(){
        checkErrors();
        return new Client2();      
    }
}

客户2:

public class Client2 extends BaseClient
{
    public BaseClient test()
    {
        checkErrors();
        return new Client3(this.errors);

    }
}

客户3:

public class Client3 extends BaseClient
{
    public Client3(Exception errors) {
        super(errors);
    }

    public BaseClient test() {
        checkErrors();
        return null;
    }
}

<强>工厂:

公共最终类ClientFactory {     private ClientFactory(){};

public static Client1 getClient1(){return new Client1();}
public static Client2 getClient2(){return new Client2();}

}

这输出以下内容:

  

test.Client1@15db9742   test.Client2@6d06d69c   test.Client3@7852e922

答案 3 :(得分:0)

现在testClient1()可以返回客户端工厂等。但这很复杂。

另一种监管语法是覆盖上下文提供类。

   new ClientFactory() {{
       getClient1().testClient1();
       getClient2().testClient2().assert(...);
   }};

这里的初始化块(&#34;匿名构造函数&#34;)将提供上下文。 然后,当testClient2返回Client2时,可以进行一些链接。

它可以是一个干净而有用的设计,例如我在sourceforge.net上的模糊语法分析器AnyParser(纯粹是一种精湛的工艺)。

答案 4 :(得分:0)

谢谢大家的帮助。您的建议使我能够达成以下工作解决方案。也许它不是最好的,所以寻求宝贵的时间和专业知识来指导更好的解决方案。

鉴于一些评论我的命名惯例是可疑的,我试图在一定程度上修改它们。请耐心等待。

目标是:

  • chain instances of different classes
  • share objects between subclasses and unassociated classes

问题描述:

  • 要执行4个任务:Task1到Task4。
  • 每项任务都是独一无二的。但有时,为了完成一项任务,我们需要执行混合任务:参考Task3&gt;&gt; performMixedTasks()
  • 要完成一项工作,我们需要完成一组任务。

<强> State.java

public class State {
    public Boolean ISAUDITED = false;
    public int ERRORCODE = 0;
    public String ERRORTEXT = "";

    public void raise(int code, String msg){
        this.ERRORCODE = code;
        this.ERRORTEXT = msg;
    }
}

<强> BaseClient.java

public abstract class BaseClient {

    public State state;

    public BaseClient(){
        this.state = new State();
    }
    public BaseClient(State state){
        this.state = state;
    }
    public ClientFactory getTest(){
        return new ClientFactory(state);
    }
    public Boolean Assert(){
        if(state.ERRORCODE == 0){
            System.out.println("Parsing was successful.");
            return true;
        }
        else{
            System.out.println("Parsing was not successful.");
            return false;
        }
    }
    public abstract BaseClient GoTo();
}

<强> Task1.java

public class Task1 extends BaseClient {
    public Task1(){ GoTo(); }
    public Task1(State state){ super(state); GoTo(); }  
    public Task1 performTask1(){
        if(!state.ISAUDITED)
        {
            System.out.println("perform Task1");
            state.ISAUDITED = true;
        }
        return this;
    }

    @Override
    public BaseClient GoTo() {
        if(state.ISAUDITED){
            new Task2(state).performTask2();
        }
        return this;
    }
}

<强> Task2.java

public class Task2 extends BaseClient{
    public Task2(){ GoTo(); }
    public Task2(State state){ super(state); GoTo(); }      
    public Task2 performTask2(){
        if(state.ISAUDITED)
        {
            System.out.println("perform Task2");
            state.ISAUDITED = false;
        }
        return this;
    }

    @Override
    public BaseClient GoTo() {
        if(!state.ISAUDITED){
            new Task1().performTask1();
        }
        return this;
    }
}

<强> Task3.java

public class Task3 extends BaseClient {
    public Task3(){ }
    public Task3(State state){ super(state); }
    public Task3 GoTo(){
        if(!state.ISAUDITED) {new Task1(state).performTask1();}
        System.out.println("Opening Task3");
        return this;
    }
    public Task3 performTask3(){
        try
        {
            this.GoTo();
            System.out.println("Submitted Task3 Data");
        }
        catch(Exception e){
            state.raise(1, e.getMessage());
        }
        return this;
    }
    public Task3 performMixedTasks(){
        new Task4(state).performTask4();        
        this.performTask3();        
        return this;
    }
}

<强> Task4.java

public class Task4 extends BaseClient {
    public Task4(){ }
    public Task4(State state){ super(state); }

    public Task4 GoTo(){
        if(!state.ISAUDITED) {new Task1(state).performTask1();}
        System.out.println("Opening Task 4");
        return this;
    }
    public Task4 performTask4(){
        try
        {
            this.GoTo();
            System.out.println("Submitted Task 4 Data");
        }
        catch(Exception e){
            state.raise(1, e.getMessage());
        }
        return this;
    }
}

<强> ClientFactory.java

public class ClientFactory {
    State state;
    public ClientFactory(){
        state = new State();
    }
    public ClientFactory(State state){
        this.state = state;
    }
    public Task3 loadTask3(){return new Task3(state);}
    public Task4 loadTask4(){return new Task4(state);}
}

<强> StubRunner1.java

public class StubRunner1 {

    public static void main(String[] arg)
    {
        ClientFactory test = new ClientFactory();
        test.loadTask3()
                .performTask3()
                .getTest()
            .loadTask4()
                .performTask4()
            .Assert();
    }
}
**RESULT IS**
perform Task1
Opening Task3
Submitted Task3 Data
Opening Task4
Submitted Task4 Data
Parsing was successful.

<强> StubRunner2.java

public class StubRunner2 {

    public static void main(String[] args) {
        ClientFactory test = new ClientFactory();
        test.loadTask3()
                .performMixedTasks()
                .Assert();
    }

}
**RESULT IS**
perform Task1
Opening Task4
Submitted Task4 Data
Opening Task3
Submitted Task3 Data
Parsing was successful.