web-dev-qa-db-ja.com

コールバックをサポートする柔軟なAPIの設計

私はJava http GET && POSTリクエストを行う必要のあるライブラリです。このライブラリには2種類のユーザーがいます:

  1. callbacksを理解し、それらの使用方法を知っている人。
  2. あれは……。

したがって、次の2つの方法を検討してください。

_public void methodWithCallback(ServiceCallback callback) {
    try {
        // GET && POST code that cannot really be abstracted to a separate method
    } catch (IOException e) {
        callback.onError(e);
        callback = null;
    }
    callback.onSuccess(response);
    callback = null;
}

public Response methodWithoutCallback() throws IOException {

    try {
        // again, GET && POST code that cannot really be abstracted to a separate method
    } catch (IOException e) {
        logger.log(e);
        throw e;
    }
    return response;
}
_

上記のコードは、主にリクエストを送信するためのコードの複製があるため、私には汚れているようです。また、私がそのような種類のメソッドをたくさん書いていれば、私のコードはすぐにdouble upになり、保守の難しいスパゲッティになります。

setCallback(Callback callback)のようなメソッドを提供することでクライアントにコールバックを設定を許可し、それがnullでない場合にコールバックを通知する1つの一般的なmethodを許可することを検討しました。しかし、私はlotの_if null_チェックを書き込むので、これも汚いようです!

どう思いますか?ここで、あなたが推奨する望ましい設計パターンは何ですか?

4
Joel Min

私の意見では、(サービス関数ごとに)1つの方法を使用し、nullコールバックを渡すことを許可することでcallbackfulcallbacklessバージョンを区別できます(アイデア#1)または、コールバックを使用して、2番目のアイデアのようにsetCallbackによって登録されます(アイデア#2)。

引数としてのコールバック(アイデア#1)

public Response method(ServiceCallback callback) throws IOException {
    try {
        // GET && POST code that cannot really be abstracted to a separate method
        /* In your code you handle the response outside the try block,
           it can raise NullPointerException because you set callback 
           to null, and onSuccess is also called even it is an error. */
        return handleSuccess(response, callback);
    } catch (IOException e) {
        /* Return statement is needed because the method signature requires it. */
        return handleError(e, callback);
        /* If you use this two line version below, you can make handleError 
           return void. */
        // handleError(e, callback);
        // return null;
    }
}

private Response handleSuccess(Response response, ServiceCallback callback) {
    if (callback != null) {
        callback.onSuccess(response);
    }
    /* I personally prefer to also return the result even the callback exists;
       otherwise just move the line below into if block and return null here. */
    return response;
}

private Response handleError(IOException e, ServiceCallback callback) throws IOException {
    if (callback != null) {
        callback.onError(e);
    } else {
        logger.log(e); /* because I assume you want to log it */
        throw e;
    }
    /* I assume there is no response if error occurred. */
    return null;
}

フィールドとしてのコールバック(アイデア#2)

public Response method() throws IOException {
    try {
        // GET && POST code that cannot really be abstracted to a separate method
        return handleSuccess(response);
    } catch (IOException e) {
        return handleError(e);
    }
}

private Response handleSuccess(Response response) {
    if (this.callback != null) {
        this.callback.onSuccess(response);
    }
    return response;
}

private Response handleError(IOException e) throws IOException {
    if (this.callback != null) {
        this.callback.onError(e);
    } else {
        logger.log(e);
        throw e;
    }
    return null;
}
2
fikr4n