异步完成创建的 Java 对象 - 对象在构造函数完成后的一段时间内准备就绪

Posted

技术标签:

【中文标题】异步完成创建的 Java 对象 - 对象在构造函数完成后的一段时间内准备就绪【英文标题】:Java object that completes creation asynchronously - object is ready some time after constructor finishes 【发布时间】:2018-07-15 13:46:39 【问题描述】:

我必须将专有的 java api 包装成更有用的东西。中心类是一个“客户”对象 签名是这样的:

public class ProprietaryClient 

    private final IEvents eventHandler;
    private Object one;
    private Object two;

    public ProprietaryClient(ProprietaryClient.IEvents eventHandler)
        this.eventHandler = eventHandler;
    

    //returns immediately
    public void connect(String url)
        //doing nasty stuff that triigers
        //on success
        //will be called from somewhere at anytime
        // eventHandler.onStateChange( State.CONNECTED );
    

    //returns immediately
    public void login(String user, String password)
        //doing nasty stuff that sets fields one and two
        //will be called from somewhere at anytime
        //eventHandler.onStateChange( State.LOGGED_IN );
        //eventHandler.onLogin( one, two );
    

    public interface IEvents 

        void onStateChange(State state);

        void onLogin(Object one, Object two);
    

    public enum State
        CONNECTED,
        LOGGED_IN,
        UNKNOWN;
    

此对象仅在状态“LOGGED_IN”中有用,但该字段没有 getter。知道对象是否可用的唯一方法是:

    调用连接 等待状态更改为 CONNECT 调用登录 等待状态更改为 LOGGED_IN(或调用 onLogin)

我想将它包装到一个类中,该类在构造函数中进行连接和登录,并告诉用户它是否准备好。 我的想法是有一个返回 CompletableFuture 或 Future 的方法: 这就是我到目前为止所拥有的。与事件有关的东西就是这样工作的。 IEvents 的实现将所有事件包装到用户标识的消息中(这部分正在工作)。 但是如何根据到达的事件创建和维护 CompletableFuture(带有 ///???? 的部分) 如果事件发生或满足正确的条件,有没有办法创造我自己的未来?

public class MyClient implements Client, MessageHandler 


    private final String password;
    private final IEvents eventHandler;
    private final SubscribableChannel eventBus;
    private final String user;
    private final ProprietaryClient propClient;

    public SikomClient( String user, String password, IEvents eventHandler, SubscribableChannel eventBus) 
        this.eventHandler = checkNotNull( eventHandler );
        this.eventBus = checkNotNull( eventBus );
        eventBus.subscribe( this );
        this.password = password;
        this.user = user;
        propClient = new ProprietaryClient(eventHandler);
        ///????
        propClient.connect("url");
        //have to wait until message received and state is "CONNECT"
        propClient.login(user, password);

    

    public CompletableFuture<Boolean> amIready()
        //???
    

    @Override
    public void handleMessage( Message<?> message ) throws MessagingException 
        if( message instanceof OnClientStateMessage && belongsToMe( message ))
            // ????
         else if( message instanceof OnLoginMessage && belongsToMe( message )) 
            // ????
            //complete CompletableFuture with true
        
    

    private boolean belongsToMe(Message<?> message)
        return ((AbstractStringJsonMessage) message).getUserId().equals( user );
    

或者没有“未来”有没有更好的方法来解决这个问题。我想让调用者负责等待多长时间,但我的班级应该保持状态并了解它。

【问题讨论】:

你不能让 ProprietaryClient 可观察(或创建一个使其可观察的类)吗? ProprietaryClient 不受我的控制(封闭源代码),它没有获取器知道它的状态。事件总线“观察”所有事件。通过“handleMessage”我正在观察客户端。 听起来你希望MyClient 需要一个已经处于CONNECT 状态的ProprietaryClient,并且有一个Future&lt;MyClient&gt; 的工厂方法,它尝试连接并以@987654327 异步完成@对象一旦建立连接。 没有 MyClient 应该完全处理 ProprietaryClient,包括使 ProprietaryClient 准备就绪所需的所有步骤。未来在“一些”步骤之后完成。 MyClient 将/应该也处理重新连接和连接丢失(下一步) 所以你想要的是PropietaryClient 的包装器,并让你的团队轻松使用这个类。 【参考方案1】:

解决方案相当简单。现在我更好地理解了“CompletableFuture”。

我添加了一个登录方法,一个带有 Completable future 的字段和一个 getter:

private CompletableFuture<ReturnCode> loggedIn = new CompletableFuture<>();
...
private void login() 
    //as per sikom settings each user gets a fixed workplace identified by user name
    if( loggedIn.isDone() ) 
        loggedIn = new CompletableFuture<>();
    
    propClient.login( user, user, password, 0 );


public CompletableFuture<ReturnCode> loggedIn() 
    return loggedIn;

我的 handleMessage 是这样做的:

public void handleMessage( Message<?> message ) throws MessagingException 
    if( message instanceof OnClientStateMessage && belongsToMe( message ) ) 
        state = ( (OnClientStateMessage) message ).getState();
        if( state.equals( ClientState.CONNECT ) ) 
            login();
        
     else if( message instanceof OnLoginMessage && belongsToMe( message ) ) 
        ReturnCode rc = ( (OnLoginMessage) message ).getRc();
        loggedIn.complete( rc );
    

如果消息到达,我只是手动完成未来(因为它没有附加任务 get 永远不会返回)。

该类的用户将实例化它并可以立即调用loginIn。被调用者可以决定等待loggedIn.get()的时间。

不知道这是不是一个好主意:它自己的类可以扩展 CompletableFuture 并可以完成自己?!

【讨论】:

以上是关于异步完成创建的 Java 对象 - 对象在构造函数完成后的一段时间内准备就绪的主要内容,如果未能解决你的问题,请参考以下文章

java 第二次实验

Java中的构造函数Constructor怎么用

新手小白学JAVA 面向对象2 构造函数 构造代码块 this

构造方法

java中类的构造方法和普通的方法在使用上有啥区别?

java中创建对象了,显示初始化值和构造函数初始化对象的区别?先后执行顺序是啥?