Java
Android

異なる処理群をシリアルに実行したいときに使うプラクティス

More than 1 year has passed since last update.

概要

Androidに限らずですが異なる処理群をシリアルに実行したいときのプラクティスです。

詳細

処理をEventという概念で取り扱い、Eventを順次実行するマネージャクラスを通して処理実行していく。
ソースコードはGitHubより取得お願いします。
https://github.com/ken-maki/k_commons.eventChain

構成は以下。

com.android.k.commons.eventchain
┣lib
┃┣EventChainManager
┃┃ Eventを順次実行するマネージャクラス、Eventの処理結果が失敗になったらそこで中断するメソッドと、
┃┃ Eventの処理結果関わらずすべてのEventを実行するメソッドをもつ。
┃┣EventChaining
┃┃ Event実装用のインターフェース。
┣events
┃┣EventFoo
┃┃ サンプル用Event、トースト表示するだけ。
┃┣EventBar
┃┃ サンプル用Event、トースト表示してEventの結果をfalse(処理失敗)で返す。
┃┗EventBaz
┃ サンプル用Event、トースト表示するだけ。
┗MainActivity
   Event実行するサンプルActivity。

ソースの解説

ライブラリ部分

EventChainManager.java
public class EventChainManager {

    List<Pair<EventChaining, Boolean>> mEvents = new ArrayList<Pair<EventChaining, Boolean>>();

    /**
     * add event.
     * <p>
     * added event is serial executed.if event failed, break execute.
     * </p>
     *
     * @param event executable event
     * @return this EventChainManager instance
     */
    public EventChainManager chain(final EventChaining event) {
        mEvents.add(Pair.create(event, false));
        return this;
    }

    /**
     * add event.
     * <p>
     * added event is serial executed.if event failed,  forward next event.
     * </p>
     *
     * @param event executable event
     * @return this EventChainManager instance
     */
    public EventChainManager chainForce(final EventChaining event) {
        mEvents.add(Pair.create(event, true));
        return this;
    }

    /**
     * execute chain events.
     * <p>
     * delete the event after execution
     * </p>
     *
     * @return returns true if it event all succeeds.
     */
    public boolean execute() {
        boolean result = executeAndLeave();
        removeAll();

        return result;
    }

    /**
     * execute chain events.
     * <p>
     * leave the event after execution
     * </p>
     *
     * @return returns true if it event all succeeds.
     */
    public boolean executeAndLeave() {
        for (Pair<EventChaining, Boolean> event : mEvents) {
            EventChaining chainEvent = event.first;
            boolean isForced = event.second;
            if (!chainEvent.action() && !isForced) {
                return false;
            }
        }

        return true;
    }

    /**
     * remove all added Event.
     *
     * @param event event to removed
     */
    public void remove(final EventChaining event) {
        mEvents.remove(event);
    }

    /**
     * remove all added Events.
     */
    public void removeAll() {
        mEvents.clear();
    }
}

Eventを実行するクラス。
Eventを追加するメソッドは以下の二つ。
・chainメソッド
 Event処理結果がfalse(失敗)であればそこで処理中止させたいときに使う。
・chainForceメソッド
 Event処理の成否に関わらず処理を継続させたいときに使う。
あとは、executeメソッドでEventの順次処理を開始させる。
Eventの順次処理完了後、追加したEventをそのままにしたい(後でまた順次処理させたいとき)ときは
executeAndLeaveメソッドを使う。

EventChaining.java
public interface EventChaining {

    /**
     * execute an event.
     *
     * @return returns true if it event succeeds.
     */
    boolean action();
}

小さなクラスです、Event実装用のインターフェース。
actionメソッドにEventの実装を書く。Event処理の成否はbooleanで返す。

個々の実装部分

EventFoo.java
public class EventFoo implements EventChaining {
    Context mContext;

    public EventFoo(final Context context) {
        mContext = context;
    }

    @Override
    public boolean action() {
        Toast.makeText(mContext, "EventFoo executed.", Toast.LENGTH_SHORT).show();
        return true;
    }
}

Eventの実装。
EventChainingをimplementsしてactionを実装するだけでございます。

MainActivity.java
public class MainActivity extends AppCompatActivity {

    EventChainManager eventChainManager = new EventChainManager();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Context context = this;
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                eventChainManager
                        .chain(new EventFoo(context))
                        .chainForce(new EventBar(context))
                        .chain(new EventBaz(context))
                        .execute();
            }
        });


        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                eventChainManager
                        .chain(new EventFoo(context))
                        .chain(new EventBar(context))
                        .chain(new EventBaz(context))
                        .execute();
            }
        });
    }
}

使い方はこんな感じです。ポイントは以下。

           eventChainManager
                   .chain(new EventFoo(context))
                   .chainForce(new EventBar(context))
                   .chain(new EventBaz(context))
                   .execute();

使うときはこんな感じに実装すれば、シリアルにEventが実行されるということが読みやすいかと思います。
この場合は、2個目にchainしたEventBarの処理結果によらずEventBazまで処理実行しますよって意味。

メリット

-可読性がよくなる(はず)
 eventChainManager#chainを使ってEventを繋げて書けるので、
 この一連の処理は順次つながっているんです、一塊の処理なんですよって意思表示できる。

補足

書いてて思いましたが、複雑な処理を順次実行するようなケースには向いてないかなぁ。

ソースコード
https://github.com/ken-maki/k_commons.eventChain