SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

デザインパターンを置き換えよう! Javaラムダ式によるシンプルコーディング

ラムダ式でCommandパターンで書かれたコードをシンプルにする ~ ラムダ式使いへの第一歩

デザインパターンを置き換えよう! Javaラムダ式によるシンプルコーディング 第1回


亀シミュレータ(ラムダ式バージョン)

 それでは次に、Java SE 8のラムダ式を用いて亀シミュレータを書き直してみましょう。

 リスト6の中で注目するべきポイントは、Commandの役割を担う Motion インタフェースが、move メソッドをただ1つの抽象メソッドとして持つ関数的インタフェースだという点です。つまり、Motion インタフェースのインスタンスは、LeftMotion クラスや DownMotion クラスのようなConcreteCommandの役割を担うクラスを宣言することなく、ラムダ式によって直接生成できるはずです。

 以上の方針に基づき、ラムダ式を用いてプログラムを設計した場合のクラス図は、図5のようになります。

図5:亀シミュレータのクラス図(ラムダ式)
図5:亀シミュレータのクラス図(ラムダ式)

 

 ラムダ式を用いてリスト6を書き換えたプログラムを、リスト7に掲げます。リスト6から変更のある箇所は「★」印で示しています。

リスト7:ラムダ式を用いてリスト6を書き換えたプログラム
import java.util.*;

public class LambdaTurtleSimulator {

    public static void main(String[] args) {
        // ユーザの入力
        String userInput = "↓←←↑↑→→→→↓↓";

        // 矢印文字に対応する動作を登録(★ラムダ式を使用)
        TurtleMover turtleMover = new TurtleMover();
        turtleMover.registerMotion('←', turtle -> turtle.setX(turtle.getX() - 1));
        turtleMover.registerMotion('↓', turtle -> turtle.setY(turtle.getY() + 1));
        turtleMover.registerMotion('↑', turtle -> turtle.setY(turtle.getY() - 1));
        turtleMover.registerMotion('→', turtle -> turtle.setX(turtle.getX() + 1));

        // 原点上の亀
        Turtle turtle = new Turtle(0, 0);

        // 入力に従って亀を動かす
        turtleMover.moveAround(turtle, userInput);

        // 移動先を表示
        System.out.printf("X=%d Y=%d%n", turtle.getX(), turtle.getY());
    }

    /** 平面上の亀. */
    static class Turtle {
        private int x, y;
        Turtle(int x, int y) {
            this.x = x;
            this.y = y;
        }
        int getX() {
            return this.x;
        }
        void setX(int x) {
            this.x = x;
        }
        int getY() {
            return this.y;
        }
        void setY(int y) {
            this.y = y;
        }
    }

    /** 亀の動きを起動するクラス. */
    static class TurtleMover {
        /** 文字と動作の対応. */
        private final Map motionMap = new HashMap<>();

        /** 文字に動作を割り当てる. */
        void registerMotion(char ch, Motion motion) {
            this.motionMap.put(ch, motion);
        }

        /** 入力文字列に従って亀を動かす. */
        void moveAround(Turtle turtle, String input) {
            for (char ch : input.toCharArray()) {
                Motion motion = this.motionMap.get(ch);
                if (motion != null) {
                    motion.move(turtle);
                }
            }
        }
    }

    /** 亀の動作. ★関数的インタフェースであることを明示. */
    @FunctionalInterface
    interface Motion {
        public void move(Turtle turtle);
    }
}

 実行結果は次のとおり、リスト6と同じです。

X=2 Y=1

 リスト7でラムダ式を用いている箇所は、main メソッドの中で、各矢印文字と動作との対応を行う「矢印文字に対応する動作を登録」の部分です。TurtleMover クラスの registerMotion メソッドの第2引数として、turtle -> turtle.setX(turtle.getX() - 1) といったラムダ式を渡しています。registerMotion メソッドの第2引数は Motion インタフェース型として宣言されているので、これらのラムダ式は Motion インタフェース型のインスタンスを生成するのです。

 リスト6では、LeftMotion クラスや DownMotion クラスなどを宣言して動作を記述する箇所と、コマンドオブジェクトを生成する箇所が離れていました。これに対してリスト7では、ラムダ式を用いることで、動作を記述するその場でコマンドオブジェクトを生成しています。より簡潔に記述できていることが分かると思います。

次のページ
考察:ラムダ式がCommandパターンをそれと意識して用いる必要をなくした

この記事は参考になりましたか?

デザインパターンを置き換えよう! Javaラムダ式によるシンプルコーディング連載記事一覧

もっと読む

この記事の著者

宮川 拓(ミヤカワ タク)

日本Javaユーザーグループ幹事。東京のシステムインテグレータに勤務。Java VM上で動作する言語である「Kink」を開発中。相撲とアメリカ文学とスコティッシュポップを愛する。 ・ブログ: http://d.hatena.ne.jp/miyakawa_taku/ ・Twitter: @miyakawa_taku

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/8300 2015/01/07 17:21

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー