繁体   English   中英

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

[英]Chaining methods of different class instances and object sharing

对于下面的示例代码...

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

  2. 同样,在同一示例中, Client2Client3共享错误对象。 sharing objects between subclasses and unassociated classes的更有效方法是什么?

为了清楚起见,我也做了内联评论。

感谢您的时间和帮助。

样例代码

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(){...}
}

当我想编写一小段方法调用但我希望方法相对于任何一种状态进行更改时,通常会使用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方法插入测试方法之间是没有意义的...

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

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的新实例都引用了相同的错误对象

我并没有真正得到您真正需要的东西,但是在代码的实际状态下,它甚至无法编译,因为您正尝试从void方法返回的“ Client”对象中执行方法。

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

如果要使用“ testClient”方法链接客户端,则首先此方法应返回下一个客户端(这是顺便链接对象的一种非常尴尬的方式),然后应开始使用更多的抽象和替代技术。

基本上,只要是“ BaseClient”,就不需要知道要处理的对象,但是如果您将子方法命名为“ testClient1”,“ testClient2”等……则基本上是在破坏它,您需要启动考虑实际得到的内容并相应地修改代码。

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

这是一个可行的示例,再次我并没有真正理解您的意愿,因此可能无法解决您的问题,但这是“链接实例”的有效解决方案:

主要:

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

现在, testClient1()可以返回客户端工厂等。 但这非常令人费解。

另一种法规语法是覆盖提供上下文的类。

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

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

它可以是一种干净有用的设计,例如,对于我在sourceforge.net上的模棱两可的语法解析器AnyParser(纯粹是一项精湛的工作)。

谢谢大家的大力帮助。 您的建议已使我得出以下可行的解决方案。 也许这不是最好的,所以请寻找宝贵的时间和专业知识,以寻求更好的解决方案。

考虑到我的命名约定有些陈词滥调,我试图在一定程度上对它们进行修改。 请多多包涵。

目的是:

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

问题描述:

  • 有4个任务要执行:Task1到Task4。
  • 每个任务都是唯一的。 但有时,要完成一项任务,我们需要执行混合任务:请参阅Task3 >> 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.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM