Java Basic 中級編 ~③メインメソッドを修正しないで拡張する~

イントロダクション

前回は、メインメソッドを修正しない形での実装を行いました。

この段階では、まだ役割分担を行っただけでこれがどんな効果があるのか?というところがわからないと思います。

なので、今回は、「〇×あてゲーム」を拡張することを考えていきたいと思います。
作成したプログラムコードはGithubにアップしてあります。

メインメソッドを修正しないで拡張する

今までに「役割分担」を行ったので、この役割分担を活用していきます。
Lv2Mainクラスはメインメソッドを動かすクラスなので、これ以外のクラスを実装していきます。

  • Lv2Main
  • MarubatsuConsole
  • MarubatsuUtils

Lv2Mainを見る

まずは、メインメソッドを見てみます。Lv2Main

/**
 * Javaの基本レベル2:小さなレベルのプログラムを拡張する。
 * 今回は、〇か×か当てるゲーム。
 */
public class Lv2Main {
    /** 終了フラグ */
    private static boolean isFinish;

    public static void main(String[] arg) {
        isFinish = false;
        // 標準入力を受け取るクラスをインスタンス化
        Scanner scan = MarubatsuUtils.getScanner();

        while (true) {
            // ゲーム開始文言
            MarubatsuConsole.printGameStart();
            // 標準入力を受け取る
            int input = scan.nextInt();
            // isFinishがtrueならば処理終了。
            if (isFinish) {
                MarubatsuConsole.printTerminated();
                break;
            }
            // 0か1の値を返却する
            int res = MarubatsuUtils.nextInt(2);

            // 0: 〇 1: ×で当たったかどうかの判定
            boolean isAtari = MarubatsuUtils.judgeAtariOrNot(res, input);
            MarubatsuConsole.printAtatiorNot(isAtari, input);

            // 続けるのかどうか判定する
            if (MarubatsuConsole.printNextPlayOrNot(scan)) {
                break;
            }
        }
    }
}

コメントを並べただけですが、以下の順序で処理を行っています。

  1. 標準入力を受け取るクラスをインスタンス化
  2. ゲーム開始文言
  3. 標準入力を受け取る
  4. isFinishがtrueならば処理終了。
  5. 0か1の値を返却する
  6. 0: 〇 1: ×で当たったかどうかの判定
  7. 続けるのかどうか判定する

上の番号で行くと2~7がループ処理の中にあります。
なので、7の「続けるか判定する」部分でNo(続けない)を選択するまで無限ループします。

拡張ポイントを見つける

そして、役割分担を行ったところ、つまりは、下のクラスを使用している部分が拡張ポイントになります。
Githubにアップしてあります。

具体的には、以下のコメント部分です。

  • ゲーム開始文言
  • isFinishがtrueならば処理終了。の終了表示部分
  • 0か1の値を返却する
  • 0: 〇 1: ×で当たったかどうかの判定
  • 続けるのかどうか判定する

もしも、他の部分を拡張したいと思たのならば、メインメソッドを少し修正する必要があります。
何かの処理をほかのクラスに任せてある状態(MarubatsuConsole, MarubatsuUtilsを使用している状態)ならば
メインメソッドを修正する必要がありません。
しかし、直接メインメソッドを修正する必要がある場合はやはり、修正する必要があります。

このような実装方法を理解すると、下のようなプログラムが作れます。

※ビルドするのに3分くらい時間がかかっています。
このプログラムは、メインの処理部分も、別クラスにしているので、まったく別のプログラムを起動するように修正することもできます。
しかし、現状では、テキストRPGを作成するところに注力しているので役割分担を行いそれぞれの役割を拡張して実装しています。
具体的には、テキストファイルを読み、それをもとにデータ(ステータスやアイテム)を生成してそれをゲームの中で使用する形での実装を行っております。
ちょっと残骸が残っていますが。。。

拡張するとき

先に示したように、別のクラスを呼び出している(使用している)部分を拡張、つまり処理を追加することができるので、次の部分を拡張することができます。

  • ゲーム開始文言
  • isFinishがtrueならば処理終了。の終了表示部分
  • 0か1の値を返却する
  • 0: 〇 1: ×で当たったかどうかの判定
  • 続けるのかどうか判定する

具体的には、ゲーム開始文言を変更することができる。とか、当たったかどうかの履歴を付ける。とか
そこらへんは、実装者のアイディア次第でどこまでも広げることができます。

ゲームの開始文言を変更する

先ほど、拡張する例としてゲームの開始文言を変更するということを上げました。これを実際にやってみます。

やっている手順としては、以下の通りです。

  1. JUnitテストケースの作成
  2. 現状のプログラム実行確認
  3. プログラムの修正、実行確認(目視で確認)

最後の実行確認(目視で確認)に関しては、すべてプログラムで確認することができます。
そのためには、ちょっと面倒なことをする必要があるので、割愛しました。
具体的には標準出力の出力先を変更して(別のPrintStreamを使用)そのストリーム内の出力内容と期待値を比較するという形になります。

現状としては、単純に〇×あてゲームの初期表示文言を変更するだけなので、目視で確認しました。

0: 〇 1: ×で当たったかどうかの判定

この部分は上記の動画では、挙動がおかしくなっていました。なので、これを修正し想定通りの実行結果が得られるようにプログラムを修正します。

実行した結果は下のようになります。

******************************
*「〇×あてゲーム」 0: 〇 1: ×。 *
******************************
※0は「〇」を表し1は「×」を表します。
1
はずれ:×
続けますか? 0: 続ける  1: やめる
0
******************************
*「〇×あてゲーム」 0: 〇 1: ×。 *
******************************
※0は「〇」を表し1は「×」を表します。
1
はずれ:×
続けますか? 0: 続ける  1: やめる
1

その前に、問題点を明確にします。

今回の問題点は「あたりのときの値、つまりは、『〇』が当たりなのか?『×』が当たりなのか?」が明確でないというところです。
なので、これも修正します。

先ほどと同じようにまずは、修正ポイント(先ほどは拡張ポイントと記載しました。)を見つけます。
実行結果を見ると、「はずれ:×」のように当たりはどちらなのか?がわからない状態ですので、これを明確にします。

具体的には、「「〇」があたりです。「×」が当たりですなどの文言を表示するように修正」する形で対応しようと考えております。

当然、他に良いアイディアがあれば、それを実装するとよいと思います。

当たり判定処理の修正

今回作成した「当たり判定処理」は、MarubatsuUtils#judgeAtariOrNotで実装しているのでこれを修正します。

現状のプログラムは下のようになっています。

    /**
     * 生成した乱数と、入力値が等しいか判定する。
     *
     * @param res 生成した乱数
     * @param input 入力値
     * @return true: 等しい false: 違う
     */
    public static boolean judgeAtariOrNot(int res, int input) {
        // 0: 〇 1: ×で当たったかどうかの判定
        return res == input;
    }

このプログラムの問題点は、〇と×のどちらが当たりなのか表示されない点です。
なので、これを表示するようにプログラムを修正する必要があります。

テストケースを作成する

先ほど初期表示の文言を表示するテストケースを作成しました。
これに追加して、「〇と×のどちらが当たりなのか表示する」テストケースを実装します。

仕様から考える

今回の要件(どのように動いたらよいか?)は「〇と×のどちらが当たりなのか表示する」ということです。
これを確かめるプログラムを考えます。

確認項目をリストアップ

  1. あたりは「〇」「×」どちらか表示する
  2. 予想を入力したユーザーの入力は「〇」「×」どちらか表示する

簡単ですが、2項目になります。

これもテストケースを作成する

ちなみに、このクラスのテストケースは以前、他のテストケースを作成していたので、これに今回のテストケースを追加します。

やったことは、同じです。

  1. 現状のプログラム実行確認
  2. プログラムの修正
  3. プログラムの実行確認

ちょっと長めの動画になりましたが、行ったことをそのまま動画にしてあります。
ポイントとしては、テストケースのプログラムの実装、作成方法、考え方(この記事に記載)を実際に行った
動画にしてあります。
別な言い方をすると、自分がこの作業を行ったものを動画にしました。

でわでわ。。。

Java Basic 中級編 ~②メインメソッドを修正しない形を作る~

イントロダクション

前回アプリケーションを作り、それを運用すること、拡張することについて考えてみました。

まとめると次のようなことが必要になるということを記載しました。

  • 各プログラム間(Javaのクラス同士)の依存度を限りなく低くする。
  • プログラムを拡張するのに、元のプログラムをほとんど変更しない。
  • Javaを使えるレベルの知識(技術)がある人なら、誰が見てもわかるようなコードを書く。
  • 各クラス(部品)の単体テスト(UnitTest)ケースを用意しておき、修正したら即テスト、部品を取り換えるだけでよいように、作成した資源(プログラムのコード)を結合テスト・総合テストと実施できるような体制を整える

今回は、プログラムを拡張していくための基本になる考え方と実践方法について記載していきたいと思っています。
例として「〇×あてゲーム」を拡張していく形でプログラム(クラス)間の依存度を低くした形のプログラミング方法について記載していきたいと思います。

メインメソッドを修正しない形を作る

前回作成したプログラムは下のものになります。

public class Lv2Main {
    /** 終了フラグ */
    private static boolean isFinish;

    public static void main(String[] arg) {
        isFinish = false;
        // 標準入力を受け取るクラスをインスタンス化
        Scanner scan = new Scanner(System.in);

        while (true) {
            System.out.println("「〇×あてゲーム」 0: 〇 1: ×。");
            // 標準入力を受け取る
            int input = scan.nextInt();
            // isFinishがtrueならば処理終了。
            if (isFinish) {
                System.out.println("プログラムを終了します。");
                break;
            }
            // 0か1の値を返却する
            Random rdm = new Random();
            int res = rdm.nextInt(1);

            // 0: 〇 1: ×で当たったかどうかの判定
            boolean isAtari = res == input;
            String value = input == 0 ? "〇" : "×";
            if (isAtari) {
                System.out.println("あたり:" + value);
            } else {
                System.out.println("はずれ:" + value);
            }
            System.out.println("続けますか? 0: 続ける  1: やめる");
            int next = scan.nextInt();
            if (next == 1) {
                break;
            }
        }
    }
}

この状態のプログラムはよく見かける。。。と思われる形のプログラムです。
つまりは、処理を1つのファイル内にすべて書いている形のプログラムということです。

このブログ的に表現すると「Javaの基本:上巻」に当たるプログラムの書き方になります。

「Javaの基本:下巻」に当たるプログラムの書き方はこれから説明していきます。

Step1. 役割分担を行う

上のプログラムで行っていることを、例えばチームで作業をするように、役割分担を行いそれぞれのクラスにそれぞれの役割を与えます。

例えば、次のような役割分担を行います。

  1. 〇×あてゲームを起動する役割
  2. 標準入力を受け取る、などの標準入出力をコントロールする役割
  3. 〇×あてゲームの各種判定を行う役割

もともとのプログラムは、全部の処理が書いてあるので、これを切り貼りして改造します。

1-2. クラスを作成する

上記の通り、2つの役割を担当するクラスを作成します。

  1. 〇×あてゲームを起動する役割:Lv2Main ※作成済み
  2. 標準入力を受け取る、などの標準入出力をコントロールする役割: MarubatsuConsole
  3. 〇×あてゲームの各種判定、ユーティリティの提供を行う役割: MarubatsuUtils

これらのクラスに必要な処理を切り貼りして、各クラスに移植します。
その結果を以下に記載致します。

※リンクはGithubにアップしたコードです。
Lv2Main

package jp.zenryoku.tutorial.level2;

import java.util.Scanner;

/**
 * Javaの基本レベル2:小さなレベルのプログラムを拡張する。
 * 今回は、〇か×か当てるゲーム。
 */
public class Lv2Main {
    /** 終了フラグ */
    private static boolean isFinish;

    public static void main(String[] arg) {
        isFinish = false;
        // 標準入力を受け取るクラスをインスタンス化
        Scanner scan = MarubatsuUtils.getScanner();

        while (true) {
            // ゲーム開始文言
            MarubatsuConsole.printGameStart();
            // 標準入力を受け取る
            int input = scan.nextInt();
            // isFinishがtrueならば処理終了。
            if (isFinish) {
                MarubatsuConsole.printTerminated();
                break;
            }
            // 0か1の値を返却する
            int res = MarubatsuUtils.nextInt(2);

            // 0: 〇 1: ×で当たったかどうかの判定
            boolean isAtari = MarubatsuUtils.judgeAtariOrNot(res, input);
            MarubatsuConsole.printAtatiorNot(isAtari, input);

            // 続けるのかどうか判定する
            if (MarubatsuConsole.printNextPlayOrNot(scan)) {
                break;
            }
        }
    }
}

MarubatsuConsole>※修正した後のコードがアップしてあります。

package jp.zenryoku.tutorial.level2;

import java.util.Scanner;

public class MarubatsuConsole {
    /**
     * 〇×あてゲームの開始文言を表示
     */
    public static void printGameStart() {
        System.out.println("「〇×あてゲーム」 0: 〇 1: ×。");
    }

    /**
     * 〇×あてゲームの終了文言を表示
     */
    public static void printTerminated() {
        System.out.println("プログラムを終了します。");
    }

    /**
     * 当たったかどうかを表示する。
     * @param isAtari 当たり判定の結果
     */
    public static void printAtatiorNot(boolean isAtari, int input) {
        String value = input == 0 ? "〇" : "×";
        if (isAtari) {
            System.out.println("あたり:" + value);
        } else {
            System.out.println("はずれ:" + value);
        }
    }

    /**
     * 〇×あてゲームを続けるかを表示、Yes or Noを取得する
     * @param scan
     * @return true: 続ける  false: やめる
     */
    public static boolean printNextPlayOrNot(Scanner scan) {
        boolean playNext = false;
        System.out.println("続けますか? 0: 続ける  1: やめる");
        int next = scan.nextInt();
        if (next == 1) {
            playNext = true;
        }
        return playNext;
    }
}

MarubatsuUtils>※修正した後のコードがアップしてあります。

package jp.zenryoku.tutorial.level2;

import java.util.Random;
import java.util.Scanner;

public class MarubatsuUtils {
    /** 標準入力を受け取るクラス */
    private static Scanner scan;
    /** 乱数の生成クラス */
    private static Random rdm;

    /**
     * 標準入力を受け取るクラスを生成、取得する。
     * ※シングルトン実装
     * @return Scanner
     */
    public static Scanner getScanner() {
        if (scan == null) {
            scan = new Scanner(System.in);
        }
        return scan;
    }

    /**
     * 乱数生成クラスがインスタンス化されていなければ、インスタンス化します。
     * すでにインスタンス化しているときは、既存のインスタンスを使用します。
     * ※シングルトン実装
     *
     * @param bound
     * @return 生成した乱数
     * @see <a href="https://docs.oracle.com/javase/jp/8/docs/api/java/util/Random.html">Random</a>
     */
    public static int nextInt(int bound) {
        if (rdm == null) {
             rdm = new Random();
        }
        return rdm.nextInt(bound);
    }

    /**
     * 生成した乱数と、入力値が等しいか判定する。
     *
     * @param res 生成した乱数
     * @param input 入力値
     * @return true: 等しい false: 違う
     */
    public static boolean judgeAtariOrNot(int res, int input) {
        // 0: 〇 1: ×で当たったかどうかの判定
        return res == input;
    }

}

メインメソッドは、すっきりしたコードになったと思います。

メインメソッドでは、どんな処理をしているかが一目瞭然になり。各クラスはその処理だけが書いてある形になります。

もちろん、引数と返り血があるので、呼び出し元に多少なりとも影響が出ます。

しかし、これでメインメソッドを変更しなくても〇×あてゲームを拡張する準備ができました。

ポイント

メインメソッドには、大まかな処理の順序を書く。具体的には下のような形です。

// <無限ループ開始>
// ■ゲーム開始文言を表示
// ■標準入力を受け取る
// ■isFinishがtrueならば処理終了。
// ■0か1の値を返却する
// ■0: 〇 1: ×で当たったかどうかの判定
// ■続けるのかどうか判定する

<やったこと>

  1. これらの処理をはじめの状態では、すべてLv2Mainクラスに記述していましたが、これをクラス別に分けました。
  2. 作成した各クラスをメインメソッドで呼び出して実行する。この時に初めの動きと変わらないことを確認しました。

これにより、プログラムのコードがすっきりして(したと自分は思います。。。)、メインメソッドを修正しなくても次の部分の処理が、修正が可能になりました。

1. ■ゲーム開始文言を表示: MarubatsuConsoleの修正
2. ■標準入力を受け取る: MarubatsuUtilsの修正
3. ■0か1の値を返却する: MarubatsuUtilsの修正
4. ■0: 〇 1: ×で当たったかどうかの判定: MarubatsuUtilsの修正
5. ■続けるのかどうか判定する: MarubatsuConsoleの修正

「そのように作ったんだから当たり前だろ?」と思った方、正常でございます。
このような作り方が、クラスを拡張する、アプリケーションを拡張するときに、役立つのです。

今回の「〇×あてゲーム」のような小さなレベルのプログラムはファイル一枚で何も問題はありませんが、会社の業務で使用するような大きなアプリケーションでは、いろんな機能が必要なので、役割分担を行い、機能拡張がしやすい形で、プログラムを組んでいきます。

拡張する準備をする

初めに「必要になること」について記載したのですが、触れていない部分があります。次の部分です。

  • 各クラス(部品)の単体テスト(UnitTest)ケースを用意しておき、修正したら即テスト、部品を取り換えるだけでよいように、作成した資源(プログラムのコード)を結合テスト・総合テストと実施できるような体制を整える

具体的にどのようなことか?これについて、記載したいと思います。

JavaならばJUnit

JavaのテスティングフレームワークといえばJUnitです。
具体的に、どのように使うか記載したいと思います。

役割分担をしたクラスのテストクラス作成

作成した各クラスのテストケースを作成するためのクラスを作成します。
クラス名は、「対象のクラス名 + Test」の形で作成します。

  • MarubatsuConsole: MarubatsuConsoleTest
  • MarubatsuUtils : MarubatsuUtilsTest

作成したコードは次の通りです。ただし、MarubatsuConsoleTestは、標準出力の内容を取得して。。。とちょっと面倒なので、今回は実装しません。

<JUnit実行結果>

package jp.zenryoku.tutorial.level2;

import org.junit.jupiter.api.Test;

import java.util.Scanner;

import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.matchers.JUnitMatchers.either;

public class MarubatsuUtilsTest {
    /** テスト対象クラス(全てstaticメソッドなのでインスタンス不要) */
    private static MarubatsuUtils target;

    @Test
    public void testGetScanner() {
        Scanner scan = MarubatsuUtils.getScanner();
        // インスタンスが取得できていることを確認
        assertNotNull(scan);
    }
    @Test
    public void testNextInt() {
        int res = MarubatsuUtils.nextInt(2);
        // インスタンスが取得できていることを確認
        boolean isRondom = res == 0 || res == 1;
        assertTrue(isRondom);
    }

    @Test
    public void testIsAtari() {
        assertTrue(MarubatsuUtils.judgeAtariOrNot(0, 0));
        assertTrue(MarubatsuUtils.judgeAtariOrNot(1, 1));

        assertFalse(MarubatsuUtils.judgeAtariOrNot(0, 1));
        assertFalse(MarubatsuUtils.judgeAtariOrNot(1, 0));
    }
}

でわでわ。。。

Java Basic 中級編 ~①アプリケーション設計を考える~

イントロダクション

Javaの基本文法が理解できたところで、実際に動くものを作ってみたいと思うのが人情だと思います。
基本文法だけでも、簡単なプログラムを作ることができます。
例えば、下のようなものです。

単純なゲームループ

1. アプリケーションを作るために

今までに、Javaの基本を学習してきました。大まかに次のようなことを学習しました。

  1. メインメソッドを動かすこと
  2. Stringやintなどのデータ型があり、それぞれに意味があること
  3. 条件分岐、繰り返しなどの文法(if文、switch, while, forなど)
  4. 自分で作ったクラスもデータ型として宣言することが出来て、呼び出す(動かす)事ができること
  5. JavaAPIで提供しているクラス(java.lang.Math, java.util.Scannerなど)を使用できること

これらのことを、このブログでは「Java Basic」と呼んでいました。

この基本に対して1段上の領域があります。それは「オブジェクト指向」と呼ばれている考え方なのですが、これの解釈が人によって千差万別なので、この言葉は使わないようにしようと考えております。

2. アプリケーションを作り運用することも考える

どちらかといえば、「エクストリーム・プログラミング」のほうが近いように思います。

エクトリーム・プログラミングに関しては上記のリンク先を参照してください。
早い話が、次のようなものです。

ソフトウェア品質 を向上させ、変化する顧客の要求への対応力を高めることを目的としたソフトウェア開発プロセスである。アジャイルソフトウェア開発の一つとして、短い開発サイクルで頻繁に「リリース」することを推奨することで、生産性を向上させ、新しい顧客の要求を採用するためのチェックポイントを導入することを意図している。

これを実現するために、次のようなことが求められます。

  • 各プログラム間(Javaのクラス同士)の依存度を限りなく低くする。
  • プログラムを拡張するのに、元のプログラムをほとんど変更しない。
  • Javaを使えるレベルの知識(技術)がある人なら、誰が見てもわかるようなコードを書く。
  • 各クラス(部品)の単体テスト(UnitTest)ケースを用意しておき、修正したら即テスト、部品を取り換えるだけでよいように、作成した資源(プログラムのコード)を結合テスト・総合テストと実施できるような体制を整える

個人で実現するのは、結構な苦労ですが、一人でアプリのリリースまでやろうと考えるならやっておきたいところです。

3. 基本が大前提

Javaでなくてもそうですが、基本ができないと応用はできません。
基本というのは、上記でいうところの「Java Basic」は、たとえて言うならば、「Javaの基本」という本の上巻に当たります

「じゃ、実際どの部分が基本なの?」という疑問が出ると思います。
これは、自分の見解ですが、下のように考えています。

つまりは、Javaだけでなくプログラミングの基本には次のような段階があると思うということです。

  • 「Javaの基本:上巻」は小さなレベルのプログラム(アプリケーション)が作れるレベルの基本。
  • 「Javaの基本:下巻」は小さなレベルのプログラムを拡張して、どんどん新しい機能を追加していけるレベルの基本

今後は、「Javaの基本」という本の下巻に当たる部分を学習します。

今までの学習方法(古い時代の学習方法だと思います。。。)は、とりあえず何かしらのアプリケーションを組み続けてそこから、自分で上にも書きましたが、次のことを理解していきました。

  • 各プログラム間(Javaのクラス同士)の依存度を限りなく低くする。
  • プログラムを拡張するのに、元のプログラムをほとんど変更しない。
  • Javaを使えるレベルの知識(技術)がある人なら、誰が見てもわかるようなコードを書く。
  • 各クラス(部品)の単体テスト(UnitTest)ケースを用意しておき、修正したら即テスト、部品を取り換えるだけでよいように、作成した資源(プログラムのコード)を結合テスト・総合テストと実施できるような体制を整える

これらのようなことを理解するのには、自分の場合、大体3年くらいかかりました。
あくまでも、基本が理解できたというレベルです。

そこから、このような基本を応用し、実践していくことが必要になりますが、それこそは実際にやってみるしかありません。

基本ができたら、そこから先は自分の作りたいものをどんどん作っていくということが最大の課題になると思います。自分も時間を見つけてやっています。いまだに完成までいかないものがあります。。。

やはり、「モチベーションの維持と、健康の維持」が大きな課題となります。

4. 小さなレベルのプログラムを拡張する

先ほどから、「小さなレベルのプログラムを拡張する」と記載していますが、これは一体どういうことなのか?これについて、記載したいと思います。

基本はプログラムを修正しない

小さなレベルのプログラムを拡張するときに、なるべくプログラムを修正しないようにプログラムを組んでいくというところが、このレベルでの基本になります。
それには、クラスとクラスの関係をうまく作るということがカギになるのですが、具体的なコードを見ていくほうが早いので、サンプルコードを見ていきましょう。

〇×あてゲーム

単純なアプリケーション「〇×あてゲーム」を作成しました。下のようなコードで動きました。
※コードはGithubにあります

/**
 * Javaの基本レベル2:小さなレベルのプログラムを拡張する。
 * 今回は、〇か×か当てるゲーム。
 */
public class Lv2Main {
    /** 週r等フラグ */
    private static boolean isFinish;

    public static void main(String[] arg) {
        isFinish = false;
        // 標準入力を受け取るクラスをインスタンス化
        Scanner scan = new Scanner(System.in);

        while (true) {
            System.out.println("「〇×あてゲーム」 0: 〇 1: ×。");
            // 標準入力を受け取る
            int input = scan.nextInt();
            // isFinishがtrueならば処理終了。
            if (isFinish) {
                System.out.println("プログラムを終了します。");
                break;
            }
            // 0か1の値を返却する
            Random rdm = new Random();
            int res = rdm.nextInt(2);

            // 0: 〇 1: ×で当たったかどうかの判定
            boolean isAtari = res == input;
            String value = input == 0 ? "〇" : "×";
            if (isAtari) {
                System.out.println("あたり:" + value);
            } else {
                System.out.println("はずれ:" + value);
            }
            System.out.println("続けますか? 0: 続ける  1: やめる");
            int next = scan.nextInt();
            if (next == 1) {
                break;
            }
        }
    }
}

次回

このプログラムをなるべく修正しなくても機能拡張できるように修正していきます。
現状のプログラムは、修正しようとしたら必ずメインメソッドを修正する必要があります。これを解消するために試行錯誤します。

でわでわ。。。

Java SQL はじめて ~オリジナル・データベースを作ろう~

Java SQL

javaでSQL、つまりはDB(データベース)に接続してテーブルを作ったり、データを登録したり。。。

早い話が、オリジナル・データベースを作ろうというわけです。

SQLってなに?

SQLはデータベース(DB)コントロールするためのプログラム言語です。大まかに下のような操作を行います。

  1. テーブル(表)の作成、変更、削除: CREATE,ALTER DROP
  2. データの操作: INSERT, SELECT, UPDDATE, DELETE

これだけです。細かい話をするともっとありますが、大まかにこのくらいです。

そして、実際に利用するときはポピュラーな用途として次のようなものがあります。

  • 顧客データ(ユーザーデータ)
  • 商品データ
  • ブログの記事データ

データベースというアプリケーションを使用して、様々なデータを保存、利用する事ができます。

例えばRPG

たまたま作成している学習用のプログラム、テキストRPGでもデータベースを使用します。
そのように作れば、どこでも使うことになるのですが。。。

RPGゲームを作るのに、アイテム、武器、防具などを、
手書きで。。。
ファイルに保存して。。。
それを読み込んで。。。

などとやっていてはいつまでたってもプログラムが完成しません。
もちろん、メモリをたくさん使用するので、アプリケーションとしても遅いものになります。

DBを使う

このデータベースというのは、保存したデータを関連付けることができるので重宝されています。
俗にいうリレーショナルデータベースというものです。最近はグラフDBなどのような新しいものもあり餡巣が、まずはリレーショナルデータベースの理解が先です。

こちらにDerbyというデータベースを使用したときの記事がありますので、よかったらどうぞ。

DBについて

基本情報の学習をしたときに記載した記事がありますので、こちらを参考にDBに関して記載したいと思います。

上記の記事は、基本情報技術者試験の学習なので、SQLに関しては記載しませんでしたが、この記事では記載します。

H2DataBase

このデータベースを使用します。簡単なのです。以前、Derbyというものを使用しましたが、結構手間なのでこちらを使用することにします。

H2DBをインストール

こちらのリンクが、H2DBのサイトになります。

英語ばかりですが、臆することはありません。赤枠の部分をクリックすればよいのです。

すると「h2-setup-2019-03-13.exe」というようなファイルがダウンロードできるはずですので、これを起動してインストールします。そして、以下の手順に従います。

  1. H2DBを起動する ※H2 Consoleという名前があるのでそれをクリック
  2. 下のような画面があるので、赤枠の部分にDBを作成するフォルダとファイル名を指定する

    ※「D:\Apps\H2\」のフォルダに「database.mv.db」ができます。

そして、ユーザー名などは指定していないので、未入力の状態にして「接続」をクリックします。

すると下のような、画面が見れますので、赤枠をクリックします。

すると下のようなSQLが生成されて、実行する事ができます。

DROP TABLE IF EXISTS TEST;
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255));
INSERT INTO TEST VALUES(1, 'Hello');
INSERT INTO TEST VALUES(2, 'World');
SELECT * FROM TEST ORDER BY ID;
UPDATE TEST SET NAME='Hi' WHERE ID=1;
DELETE FROM TEST WHERE ID=2;

作成されたテーブルは、サンプルのテーブルです。とりあえず作成されたことを確認できますのでこれを実行します。

実行して、テーブルが作成されたことを確認したら、「切断」して初めの画面に戻ります。

JDBC接続

次は、Eclipseを起動して、プログラムを作成します。
Eclipseに関しては、設定、セットアップをこちらの記事に記載していますので、参照ください。

まずは、「H2dbManager」クラスを作成します。動画はクラスの作成方法を示したものです。

ポイント

DriverManager.getConnection("jdbc:h2:D:\\Apps\\H2\\database");

上記の「D:~」の部分は、H2DBに接続するときに書いているJDBCのURIになります。

「D:\Apps\H2\」のフォルダに「database.mv.db」ができます。

public class H2dbManager {
    /** このクラスのインスタンス */
    private static H2dbManager instance;
    /** DBコネクション */
    private Connection con;

    /**
     * プライベートコンストラクタ、H2DBのコネクションを取得する。
     * {@link H2dbManager#getInstance()}
     */
    private H2dbManager() {
        try {

            con = DriverManager.getConnection("jdbc:h2:D:\\Apps\\H2\\database");
            Statement stmt = con.createStatement();
            ResultSet result = stmt.executeQuery("select * from TEST;");
            result.next();
            String id = result.getString(1);
            String name = result.getString(2);
            System.out.println("ID: " + id + "Name: " + name);
        } catch (SQLException e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

    /**
     * このクラスのインスタンスを取得する。
     * @return H2dbManagerインスタンス
     */
    public static H2dbManager getInstance() {
        if (instance == null) {
            instance = new H2dbManager();
        }
        return instance;
    }
}

上のコードが書けたら、実行します。実行の仕方は、以下のようなメインメソッドを作成して実行すればOKです。

public static void main(String[] args) {
    H2dbManger main = H2dbManger.getInstance();
    main.executeQuery("select * from test;");
}

追伸、下のように使用するSQLで呼び出すメソッドが違います。

// SELECT文
main.executeQuery("select * from test;");

// INSERTやUPDATE文
main.executeUpdate("INSERT INTO MyTable(ID, NAME, VALUE) VALUES(1, 'test太郎', 12);");

// CREATE TABLEなどのCRUD以外のSQL ※CRUDのSQLも実行可能
main.execute(sql);

これでJavaでのDB接続は完了です。あとは、SQLを実行してデータの登録やらテーブルの作成やらやってみるのが面白いと思います。

でわでわ。。。

Java クラスの扱い〜役割分担をする〜

イントロダクション

オブジェクト指向の理解をするのに、以下の様なステップを踏むと理解しやすいであろうというものです。

クラスの役割分担をする

以前作成したJava ミニゲーム ソース 〜じゃんけんゲーム in Console 〜を作るのにクラスの役割分担を考えます。

CommandIF(インタフェース)を使用したポリモーフィズムの実行動画があります。

単純に以下の様な分担を思いつくかもしれません。

  • メインメソッドを持つクラス
  • じゃんけんゲームを起動するクラス
  • じゃんけんの入力やCPUの手を取得などのユーティリティクラス
  • 入力チェッククラス
  • コンソール表示を行うクラス

全部で5クラスを使うアイデアが出ました。人によりアイデアは違うのでどんな分担がベストなものか議論してみるのも楽しいかもしれません。

## ソースを眺めてみる
[上記のリンク先](https://zenryokuservice.com/wp/2020/06/12/java-%e3%83%9f%e3%83%8b%e3%82%b2%e3%83%bc%e3%83%a0-%e3%82%bd%e3%83%bc%e3%82%b9-%e3%80%9c%e3%81%98%e3%82%83%e3%82%93%e3%81%91%e3%82%93%e3%82%b2%e3%83%bc%e3%83%a0-in-console-%e3%80%9c/)は下のようなクラス構成になっています。
* **Mainクラス**:メインメソッドを持っているクラス
- 「exe」と入力するとFirstCls#execute()が起動する
* **FirstClsクラス**:各処理を実装しているクラス

上記のリンク先で作成したものは、ちょっと面倒な起動の仕方をしています。じゃんけんゲーム他にも何か実装しようとしたためです。

## 役割分担の効果
ここで我々人間がみんなで作業をするときに行う「役割分担」をプログラム上で行うことを考えて見ます。
上のように、「メインメソッドを起動するクラス」と「各処理を実装しているクラス」を作成して、**作業を分担**しました。

## 分担することでできること1
### <インターフェースの追加実装>
これは、単純に分けただけですが、メインメソッドの実装をしたのように変更したとします。 ※FirstClsの実装も変える必要があります。
**ExeInterface**を作成し、FirstClsクラスに実装(implements)します
<作成するインターフェース>
```java
public interface ExeInterface {
// 抽象メソッド(implementsしたクラスに実装を強制する)
public execute(Scanner scan);
}
```

<FirstClsにimeplementsする>
```java
public class FirstCls implements ExeInterface {
// 中身は省略
}
```

```java
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String input = scan.next();

ExeInterface first = new FirstCls();
if ("exe".equals(input)) {
first.execute(scan);
}
boolean isNumber = first.isNumberString(input);
if (isNumber) {
System.out.println(input + "は数字です。");
} else {
System.out.println(input + "は数字ではありません。");
}
}
}
```

このような形にすることで、「FirstClsのじゃんけんゲームではなく、別のゲームを起動したい」と思った時に、FirstClsと同様に「ExeInterfaceを実装」してSecondClsを作成したとします。
メインメソッドも下のように修正します。

```java
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String input = scan.next();

ExeInterface second = new SecondCls();
if ("exe".equals(input)) {
second.execute(scan);
}
boolean isNumber = first.isNumberString(input);
if (isNumber) {
System.out.println(input + "は数字です。");
} else {
System.out.println(input + "は数字ではありません。");
}
}
}
```

このように修正することで、SecondCls#execute()を実行できるようになります。ちなみに修正した部分は2行です。

## さらに、ポリモーフィズムする
インターフェースを作成したことで、簡単に起動するクラスを変更できるようになりました。
しかし、メインメソッドをいちいち修正するのも面倒なので、動的に起動するクラスを追加できるようにしたいと思います。
同じような実装として[「CommandIF」というインターフェースを作成して、使用したときの記事](https://zenryokuservice.com/wp/2020/10/05/java-basic-%e3%80%9c%e3%82%a4%e3%83%b3%e3%82%bf%e3%83%bc%e3%83%95%e3%82%a7%e3%83%bc%e3%82%b9%e3%81%ae%e6%89%b1%e3%81%84%e6%96%b9%ef%bc%92%e3%80%9c/)もありますので参考までにどうぞ。

### ここでの問題1
**メインメソッドの中で「new XXXX」というコードを書くと、起動するクラスを動的に変更できない。**

という問題がありますので、この部分を動的に変更できるようにします。テクノロジーとしては「リフレクション」というものを使用します。Javaパッケージとしては「[java.lang.refrect](https://docs.oracle.com/javase/jp/6/api/java/lang/reflect/package-summary.html)」になります。

#### 具体的に。。。
1. 起動するクラスを動的に変更するために入力によって起動するクラスを取得するように修正
2. 入力値をキーにして、取得するクラスの完全修飾名を取得する
3. 完全修飾名より、起動するクラスのインスタンスを生成、取得する

大まかに上記のような手順で実装します。
##### 1. 起動するクラスを動的に変更するために入力によって起動するクラスを取得するように修正
これは単純に入力値によって条件分岐すれば良いです。

##### 2. 入力値をキーにして、取得するクラスの完全修飾名を取得する
キーと値をセットで動的に取得する、ということを考えると「プロパティファイル」を使用すると楽です。
コードとしては、下のように実装すると、プロパティファイルを読み取ることができ、プロパティファイルは追加したいクラスのキーと値をセットにして追記してやれば良いです。

<プロパティファイルの例>
```
first=jp.zenryoku.sample.FirstCls
second=jp.zenryoku.sample.SecondCls
third=jp.zenryoku.sample.ThirdCls
```

<プロパティファイルを読み取る例>
```java
/** コンストラクタ */
public Lv3_1_RefactorLv2() {
commandList = new ArrayList<String>();
prop = new Properties();
// 現在位置の状態を保持するマップ
placeInfo = getInfoMap();
try {
// resources/
prop.load(getClass().getResourceAsStream("/test.properties"));
} catch (IOException e) {
e.printStackTrace();
// エラーコード-1をセットしてプログラム終了
System.exit(-1);
}
}
```

<プロパティファイルのキーから値を取得する例>
```java
/**
* プロパティファイルから値が取得できた、値を返し
* 取得できない時はから文字("")を返す
* @param inStr キー(コマンド)
* @return プロパティファイルの値
*/
public String getPropertes(String inStr) {
String value = prop.getProperty(inStr);
if ("".equals(value)) {
listPropertyKeys();
return "";
}
return value;
}
```

上のようなメソッドを実装して、プロパティファイルのキーから値(クラスの完全修飾名)を取得します。

##### 3. 完全修飾名より、起動するクラスのインスタンスを生成、取得する
このサンプルコードは、インターフェースとして作成した「CommandIF」を使用していますが、他のインターフェースの場合は「CommandIF」を他のインターフェース型に変更してやれば良いです。

#### リフレクションの実装
そして、ポイントになるのは

Class.forName(fullClassName);

の部分です、リフレクションの実装になります。クラスの完全名からクラスオブジェクトを取得、インスタンスの生成。というような処理を行います。
```java
CommandIF cmd = null;
try {
@SuppressWarnings("unchecked")
Class<CommandIF> cmdCls = (Class<CommandIF>) Class.forName(fullClassName);
cmd = cmdCls.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(-1);
}
```
ポイントとしては、完全修飾名の「fullClsName」を引数にクラスオブジェクトを取得(Class#forName())してからインスタンスを生成(Class#newInstance())しているところです。

この処理で生成したクラスを返却してやれば、動的に「CommandIF」を実装したクラスを実行することができます。

## まとめ
役割分担すると「ポリモーフィズム」が使いやすいということです。

<サンプル動画>

## 関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

## JavaFX関連ページ
1. [Eclipse SceneBuilderを追加する](https://zenryokuservice.com/wp/2018/11/17/eclipse-scenebuilder%e3%82%92%e8%bf%bd%e5%8a%a0%e3%81%99%e3%82%8b/)
1. [JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~](https://zenryokuservice.com/wp/2018/11/17/javafx-scenebuilder-%e3%80%9ceclipse%e3%81%a8scenebuilder%e9%80%a3%e6%90%ba/)
1. [JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜](https://zenryokuservice.com/wp/2019/02/05/javafx-scenebuilder%e3%80%9c%e3%83%9c%e3%82%bf%e3%83%b3%e3%81%ab%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89%e3%82%92%e5%89%b2%e3%82%8a%e5%bd%93%e3%81%a6%e3%82%8b%e3%83%af%e3%83%b3%e3%83%9d%e3%82%a4%e3%83%b3/)
1. [Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜](https://zenryokuservice.com/wp/2020/03/30/java-%e3%83%97%e3%83%ad%e3%82%b3%e3%83%b3%e3%82%b2%e3%83%bc%e3%83%a0-%e3%80%9c%e8%a6%8b%e3%81%9f%e7%9b%ae%e3%81%ae%e4%bd%9c%e6%88%90scenebuilder%e3%81%ae%e4%bd%bf%e7%94%a8%e3%80%9c/)

## ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

## JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

## オブジェクト指向関連ページ
1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
1. [オブジェクト指向の概念2〜クラスとは〜](https://zenryokuservice.com/wp/2019/10/30/%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5%e3%80%9c%e3%82%af%e3%83%a9%e3%82%b9%e3%81%a8%e3%81%af%e3%80%9c/)

Java Discord

  1. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜
  2. Java Discord セットアップ〜Hello Discord〜
  3.  Java Discord ピンポン〜Discordプログラム〜
  4. Java Discord Listener実装〜コマンドを好きなだけ追加しよう〜

## 設計
1. [設計を始める〜1.アプリイメージ〜](https://zenryokuservice.com/wp/2018/10/25/%e8%a8%ad%e8%a8%88%e3%82%92%e5%a7%8b%e3%82%81%e3%82%8b/)
1. [設計を始める〜2.機能イメージ〜](https://zenryokuservice.com/wp/2018/10/25/%e8%a8%ad%e8%a8%88%e3%82%92%e5%a7%8b%e3%82%81%e3%82%8b%e3%80%9c2-%e6%a9%9f%e8%83%bd%e3%82%a4%e3%83%a1%e3%83%bc%e3%82%b8%e3%80%9c/)
1. [設計を始める〜3.機能概要〜](https://zenryokuservice.com/wp/2018/10/26/%e8%a8%ad%e8%a8%88%e3%82%92%e5%a7%8b%e3%82%81%e3%82%8b%e3%80%9c3-%e6%a9%9f%e8%83%bd%e6%a6%82%e8%a6%81%e3%80%9c/)
1. [Java はじめて16 〜クラス設計から実装〜](https://zenryokuservice.com/wp/2019/09/19/java-%e3%81%af%e3%81%98%e3%82%81%e3%81%a616-%e3%80%9c%e3%82%af%e3%83%a9%e3%82%b9%e8%a8%ad%e8%a8%88%e3%81%8b%e3%82%89%e5%ae%9f%e8%a3%85%e3%80%9c/)

Java ミニゲーム ソース付き 〜テスト駆動開発:文言出力部品を作る〜

今回は、RPGゲームでよくある文字を1文字ずつ読めるスピードで出力する部品を作ります。

今まで作成したテキストRPGゲームに追加します。
現状は、こんな感じで動きます。

文字の出力は、一括で出力するのでゲームっぽくありません。どちらかというとログ出力っぽいです(笑)

文字出力部品を作る

現状は、System.out.println()を使用しています。これは引数にある文字列を標準出力に出力します。
標準出力 = System.outになります。

問題

どーやって1文字ずつ出力するか?
とりあえずは、テスト駆動開発にしますので、テストケースを作成します。

毎度おなじみJUnit

JUnitを使用してテストクラスを動かします。

作成手順

  1. Eclipseのプロジェクトに「test」フォルダを作成する
  2. テストするクラスと同じパッケージを作成する
  3. テストするクラスの後にTestをつけたクラスを作成する
  4. 〜Testクラスにテストケースを作成する
具体的に。。。

実装した時の動画を作成しました。

詳細は以下のようになります。
上の手順4以降の記載になります。

JUnitをビルドパスに追加


動画にもあるのですが、上のような画面でJUnitを追加します。細かい部分は動画にありますので参照ください。

テストケースを作る

今回のテストケースはコンソールにゆっくりと表示できれば良いので、動かすだけになります。
故に、コードは下のようになります。

public class PrintUtilsTest {
    @Test
    public void testPrint01() {
        String mes = "アイウエオカキクケコ。。。。";
        try {
            PrintUtils.print(mes);
        } catch (InterruptedException e) {
            fail(e.getMessage());
        }
    }
}

今回の作成するクラスは、PrintUtilsクラスです。テストクラスは上のコードにある通りです。

作成するクラスをガワだけ作ったら、あとは、テストケースで呼び出してやる処理を実装してやるだけです。

あとは、実装→起動→修正→確認を繰り返して終了です。

シンプルなもんです(笑)

JUnitを使用したときの再生リストへのリンクです。

JUnitで10進数を2進数に変換する処理を実装

テストファーストで、補数算出メソッドの実装

EclipseでJUnitの起動設定~テストクラスの作成1

EclipseでJUnitの起動設定~テストクラスの作成2

Java テスト駆動で引き算のメソッドを作る

関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX関連ページ

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  4. Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

オブジェクト指向関連ページ

  1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
  2. オブジェクト指向の概念2〜クラスとは〜

Java ミニゲーム ソース 〜じゃんけんゲーム in Console 〜

今回は、Javaで作成するミニゲームと題して下のゲームを作成したいと思います。

じゃんけんゲーム

毎度おなじみ「じゃんけんゲーム」シンプルに、楽しめるゲームとして最もポピュラーなものだと思います。
それをJava言語を使ってコンソールゲームにしました。
しかし、バグもあります。。。

Mainメソッド

メインメソッドは変更しません。前回のコードはこちらから見れます。※前回の記事です。

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String input = scan.next();

        FirstCls first = new FirstCls();
        if ("exe".equals(input)) {
            first.execute(scan);
        }
        boolean isNumber = first.isNumberString(input);
        if (isNumber) {
            System.out.println(input + "は数字です。");
        } else {
            System.out.println(input + "は数字ではありません。");
        }
    }
}

今回の実装はFirstCls#executeから始めます。。。

実際に作ってみた

ここで、Mainメソッド変更しません。とはじめに記載したのではじめが分かりづらいです。起動したら「exe」と入力する必要がありました(笑)
そして、実装したコード(FirstCls)は下のようなコードです。
※使用していないゴミコードは削除しています。全体はこちらのGithubで見ることができます。

public class FirstCls {
    /** システム(OS)で使用する改行コード */
    private static final String SEPARATOR = System.getProperty("line.separator");
    /** プレーヤの勝利フラグ */
    private static final Integer WIN = 1;
    /** プレーヤの敗北フラグ */
    private static final Integer LOOSE = 2;
    /** プレーヤの引き分けフラグ */
    private static final Integer DRAW = 3;

    public void execute(Scanner scan) {
        System.out.println("*** EXECUTEを起動します ***");
        // じゃんけんの手のマップ
        Map<String, String> map = createJankenTe();
        // じゃんけんの勝敗マップ
        Map<String, Integer> judgeMap = createJudgement();
        Random rnd = new Random();
        while(true) {
            System.out.print("じゃんけん。。。");
            String player = scan.next();
            int cpu = rnd.nextInt();
            System.out.println("あなた:" + map.get(player) + " CPU:" + map.get(String.valueOf(cpu)));
            if (judgeMap.get(player + cpu) == WIN) {
                System.out.println("You win!");
            } else if (judgeMap.get(player + cpu) == LOOSE) {
                System.out.println("You loose!");
            } else if (judgeMap.get(player + cpu) == DRAW) {
                System.out.println("Draw! one more time ...");
                continue;
            }
            System.out.println(SEPARATOR + "もう一度やる?" + SEPARATOR + "y: もう一度 n: やめる");

            String more = scan.next();
            if ("n".equals(more)) {
                break;
            } 
        }
    }

    /**
     * じゃんけんの手を設定したMapを返却する
     * @return Map
     */
    private Map<String, String> createJankenTe() {
        Map<String, String> map = new HashMap<>();
        map.put("1", "グー");
        map.put("2", "チョキ");
        map.put("3", "パー");
        return map;
    }

    /**
     * じゃんけんの勝敗パターンをMapに設定
     * @return Map
     */
    private Map<String, Integer> createJudgement() {
        Map<String, Integer> map = new HashMap<>();
        map.put("12", WIN);
        map.put("23", WIN);
        map.put("31", WIN);
        map.put("21", LOOSE);
        map.put("32", LOOSE);
        map.put("13", LOOSE);
        map.put("11", DRAW);
        map.put("22", DRAW);
        map.put("33", DRAW);
        return map;
    }
}

こんな感じです。

処理内容

Mainメソッドは。。。割愛します。
FirstCls#execute()では、ジャンケンで取りうる手(グー・チョキ・パー)をMapに設定しておき、1~3の入力に対応してそれぞれの手を表示、じゃんけんの判定にしようします。

勝敗の判定には、全てのパターンをMapに記憶してプレーヤーの手とCPUの手を連結→プレーヤー:グー、CPU: チョキであれば"12"で勝敗マップからは「1」が取得できます。

1は勝利判定のフラグです。
詳細は上のコードに書いてありますので。。。

近くに、これの解説動画も作成いたします。

問題

バグがあるのですが、それはどこでしょうか?
<ヒント>
動かしてみるとわかります。

でわでわ。。。

関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

Java Basic Class 〜クラスを作ってクラスを理解する〜

久しぶりに、Javaの基本をやろうと思います。
Javaの基本といってもいろいろあるので、クラスの作り方をメインにやろうと思います。

早速作りましょう

とりあえずは、動かすのにメインメソッドが必要ですので、このメインメソッドを作成します。

作り方は、今までにやってきたので割愛します。

ここでのポイントは、MainメソッドのあるMainクラスを作成すると言うところです。

my.sample.Main

public class Main {
    public static void main(String[] args) {
        // 中身はまだない。。。
    }
}

このクラスから処理が始まります。

何をするか考える

設計の工程になります。。。

Step1

しかし、初めての人にもわかるよう、ハローワールドを実装します。

public class Main {
    public static void main(String[] args) {
        //  ハローワールド
        System.out.println("Hello World!");
    }
}
Step⒉

しかしこれでは、物足りない。。。
プログラム引数に、値を渡して、プログラム引数に値がある場合に表示すると言うものにしましょう

public class Main {
    public static void main(String[] args) {
        //  プログラム引数に値があるときは表示する
        if (args.length != 0) {
            System.out.println("プログラム引数:" + args[0]);
        }
        System.out.println("Hello World!");
    }
}
Step3

いやいや。。。プログラム引数が1つだけとは限らないので、そいつをどうにかしよう。

つまり、プログラム引数の数だけ表示しよう!

public class Main {
    public static void main(String[] args) {
        //  プログラム引数に値があるときは表示する
        if (args.length != 0) {
            for (int i = 0; i < args.length; i++) {
                System.out.println("プログラム引数[" + i + "]: " + args[0]);
            }
        }
        System.out.println("Hello World!");
    }
}
Step4

次は、文字表示だけじゃ面白くないから計算をしよう。

public class Main {
    public static void main(String[] args) {
        //  プログラム引数に値があるときは表示する
        if (args.length != 0) {
            for (int i = 0; i < args.length; i++) {
                System.out.println("プログラム引数[" + i + "]: " + args[0]);
            }
        }
        System.out.println("1 + 1 = " + (1 + 1));
    }
}

Step5

ここまできたら、クラスも作ってみよう。
しかし、今まで作成したコードは、書き換えてきたから、また呼び出したい時には、どうしたら良いだろうか?

クラスを使う

クラスを使うと、呼び出すメソッドを変えてやるだけで今までの作成したコードを実行できます。

Step1〜4までに作成したコードはどこかにいってしまいましたが、今後作成するプログラムは残せるように、クラスを作りながら進みます。

Step6: クラスを作る

とりあえず、今メインメソッドにある処理は邪魔なので、作成したクラスへ移動してしまいます。
新たに作成したクラスはFirstClsです、パッケージが違うのでインポートする必要があります。

そして、Mainクラスはこのようになりました。

public class Main {
    public static void main(String[] args) {
        FirstCls first = new FirstCls();
        first.printSomething(args);
    }
}

FirstCls

public class FirstCls {
    public void printSomething(String[] args) {
        //  プログラム引数に値があるときは表示する
        if (args.length != 0) {
            for (int i = 0; i < args.length; i++) {
                System.out.println("プログラム引数[" + i + "]: " + args[0]);
            }
        }
        System.out.println("1 + 1 = " + (1 + 1));
    }
}

処理の結果は変わりません。

そして、Eclipseでのパッケージ構成は下のようになっています。

ここからです。

Step7: クラスを使うメリット

現状、作成したプログラムは、
なんとなく作成した、意味のない処理が動いている状態です。

これは、とりあえずFirstClsによけておき、入力を受け取るプログラムを追加したいともいます。
これは、全ての処理の始まりになりますので、Mainクラスに実装します。実際に動かした時の動画です。

Step8: 標準入力を受ける

今までに処理結果をコンソールに表示していました。
ここは、「標準出力」と言う場所で、System.outで表現される(メモリ)領域です。

とりあえずここに表示するSystem.out.printメソッドで今まで表示を行なっていました。

次は、逆に入力、出力に対して入力を受け付けるプログラムを書きます。
Mianクラスに実装します。

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String input = scan.next();

        FirstCls first = new FirstCls();
        first.printSomething(args);
    }
}

そして、取得した標準入力をコントロールするためのメソッドをFirstClsに作成します。

public class FirstCls {

    public void handleInput(String input) {
        System.out.println("入力値: " + input);
    }

    /** 使用しないので下のアノテーションをつける */
    @Deprecated
    public void printSomething(String[] args) {
        //  プログラム引数に値があるときは表示する
        if (args.length != 0) {
            for (int i = 0; i < args.length; i++) {
                System.out.println("プログラム引数[" + i + "]: " + args[i]);
            }
        }
        System.out.println("1 + 1 = " + (1 + 1));
    }
}
Step9: まずはハローワールド

入力値をコンソールに表示するプログラムを作成しました。

上のような出力ができます。

作成したhandleInput()をそのままにしておき、次は引数が数字かどうか判定するメソッドを作成します。

public boolean isNumberString(String str) {
    // [0-9]は正規表現と言います。
    boolean isNumber = str.matches("[0-9]");
    return isNumber;
}

そして、これを初めに作ったメソッドから呼び出すようにします。

public void handleInput(String input) {
    System.out.println("入力値: " + input);
    if (isNumberString(input)) {
        System.out.println(input + "は、数字です");
    } else {
        System.out.println(input + "は、数字ではありません");
    }
}

こんな感じの実行結果が見れます。

作成したコードはこちらから参照(ダウンロード)できます
Mainクラス
FirstClsクラス

まとめ

このように、主軸になる処理を中心にして、処理を繋げられるように、処理を分断(機能レベル、処理レベル色々ありますが。。。)。

そして、組み合わせて実行!と言うように、なるべく修正、追加する作業を減らせるように作るとクールなプログラムと言えるでしょう。

あー自分も美しいプログラムが書けるようになりたい!

でわでわ。。。

関連ページ

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜


Java IoT 予備知識〜ラズパイにJava(Web)サーバーを立てる〜

ラズパイにIoT開発環境を構築するという自前のミッションがあるのですが、急遽ラズパイにJava製のWebサーバーを起動しようということになりました。※そのように考えた次第です。。。

具体的に、Iotの実装を行うためにはそれなりの開発環境を構築する必要があります。※JavaME環境

しかし、自分が持っているラズパイは古いので、遅い。。。開発環境を構築して作業を行うのはちょいと面倒なわけです。

ラズパイでの開発環境構築が必要な理由は、デバイス(USB、GPIOなど)へのアクセスが必要になるため実機での開発環境が必要になります。

なので、今回は古いラズパイ(RPi2 model B)での実装を行うので、Windows上で開発したJavaサーバーをラズパイに移植して起動しようという考えです。

具体的な手順

  1. Widnows上で開発、テストを行う
  2. JARファイル(実行ファイル)を出力して起動できる確認をする
  3. 作成したコードをGithubにコミットする
  4. ラズパイでGithubからソースをチェックアウトしてビルド、JARファイルを作成
  5. ラズパイの起動時に実行するシェル・スクリプトで手順4の処理を行う

上記のような手順で作業を行うと結果としては、下のように動くであろうというところです。

  1. ラズパイに電源を入れる
  2. 起動スクリプトが動く
  3. 作成したJavaサーバーが起動する

問題は、作成したJavaサーバーに何を行わせるか?というところです。

今回作成する、JavaサーバーはHTTPプロトコル以外でも受信し処理を行うことができるものを作成します。
「なぜそれが可能か?」というところですが、これは低レベルな実装なためHTTPだろうが、バイナリだろうが関係なく受信、レスポンスの送信を行うことが可能になります。

その代わり、以下のような部分を実装する必要があります。

  1. 受信したリクエストがHTTPなのか、それ以外なのか?を判別
  2. HTTPリクエストならばHTTPでレスポンスを返し、それ以外はそれぞれのレスポンスを返す
  3. それぞれのプロトコル(HTTP, FTPなど)で受信したときにどのような処理を行うのか?

通常というか身近にある「ウェブサーバー」と呼ばれているものはHTTPリクエストを受け、それに対応するHTMLを読みこんで、そのテキストデータ(HTML)を返却、ブラウザで表示というような処理を行っていますが、

今回作成するJavaサーバーは低レベルなため、大体のことは大体できますが、以下の部分を実装する必要があります。

HTTPリクエストを受け、それに対応するHTMLを読みこんで、そのテキストデータ(HTML)を返却

この部分を実装できるようになると、自作のフレームワークを作成したり一人で多くの作業を行おうとするときに「前もって作成しておく道具」として使用することができます。このような「道具」を作成しておくとやらなければいけいない作業が減り、いろいろなことができるのではないでしょうか?

注意点

上記のJavaサーバーは、ServerSocketを使用して作成しますが、これの実装をする前に理解しておく必要がいくつかあります。

  • サーバーとクライアントの関係に関する理解
  • Webサーバー、アプリケーションサーバー(APサーバー)、DBサーバーの関係性に対する理解
  • MVCモデルの概要に対する理解

まとめると次のようになります。

  1. リクエストの送信と受信を行うときに「サーバー」と「クライアント」の関係がある
  2. HTTP以外にもプロトコルがあり、ブラウザはHTTP、FTPなどのプロトコルを使用する
  3. HTTP以外のプロトコルで、Socket通信のようにバイトデータをそのまま送信することもある
  4. HTTP、それ以外、それぞれの通信方法で、それぞれに対応した処理を実装する必要がある

次はHttpServeltの実装について

ちょっと難しくなってしまったので、まずはJavaでのウェブサーバーを見ていきます。

JavaのWebサーバー

とりあえずはここのページを参考に作成しようと思います。

結論から言うと。。。

HttpServletクラスを拡張(extends)してリクエストを受け付ける常駐アプリを作成しようと言うことです。

とても、シンプルなJavaウェブサーバーです。Java出なくてもクライアントとサーバーの関連を学習したい人は一読作成して見ると、一発で理解できます。(理解できないと作成できません。)

このような、わりかし低レベルな実装は経験する機会があまりないので、Java学習者やウェブデザイナーなどウェブ・サーバーをよく使う人には一度やって見ると理解が早いです。

ちなみに、「通常実装するとき」というのは、SpringBoot(DispatcherServlet)、JavaEE(FacesServlet)のようなフレームワークを使用した実装のことを指しています。

今回作成するシンプルなJavaウェブサーバーというのは、一段レベルを下げて上記のようなサーブレットクラスの親クラス・インターフェース部分の実装を行うというところです。

ちなみに、FacesServletクラスはServletインターフェースを実装しています。なので、この部分に係る実装を行うということです。

具体的には、HttpServletクラスの子クラスを作成してこのクラスを拡張してやります。

大まかな仕組み

下のような図になります。

ふざけているのではありませんので。。。

  • クライアント(スマホやPC)からURLを指定してサーバーにアクセスします。
  • クライアントは、PCやスマホのことなので自分が持っている機械(デバイス)です。

そして、サーバーはどこかの会社とか、国の機関とかに置いてあるウェブサーバー(アプリ)を起動している機械(コンピュータ)にアクセスしてそのアプリが返却するHTMLを見ている状況です。一緒にJSなどもダウンロードされて画面(ブラウザ)に表示されます。

大まかに上のような処理を行う「ウェブサーバー」をJavaを使用して作成しようと言うことです。

サーバーはアプリのこと

サーバーはアプリケーションです。常駐して動き、何かしらのアクセスを待機しているアプリケーションのことを「サーバー」と呼びます。別な言い方をすると「常駐待機しているアプリケーション」ということになります。
具体的には、PCを動かすために起動する(画面を表示する)Xサーバーなんてものもありますし、電源を入れたらスマホの画面が開くのも常駐アプリなので「サーバー」の仲間に入ります。
全部がサーバーだと呼ぶのに不便なのでスマホアプリと言ったり、サーバーと言ったりして区別します。

ちなみに、サーバー(アプリケーション)を稼働させるためのコンピュータのことを「サーバー機」と呼びます、そして、基本情報などの説明書きには「サーバー」などと書かれていますが、「サーバー機」と「サーバー(アプリケーション)」とでは別物なので、注意してください。

Java版Webサーバー

通常は、TomcatとかApacheとかをダウンロードしてきてウェブサーバーとして稼働することが多いのですが、今回はこれをJavaで作成しようと思います、まずは調査から行きますが、TomcatはJavaでできているようです。

そして、よくある書籍などでは、下のようなコードで実装しています。

public class JspLlesson1 extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.setContentType("txtext/html; charset=UTF-8");
        PrintWriter write = res.getWriter();
        write.println("Hello World");
    }
}

HttpServletのポイント

このクラスはJavaDocにあるように、抽象クラスです。しかし、抽象メソッドが定義されていないので「必ずオーバーライド」をしなくてもよい形になっています。

意図としては、継承して使用してくださいということなのだと思います。※予想になります。。。

そして、「doGet()」を「doPost()」メソッドをオーバーライドすることでHTTPリクエストに対する処理を実装する事ができます。

上記の落書きのようなイメージにある、リクエストとレスポンスをハンドルする処理がこのクラス・メソッドに実装することになるというわけです。

具体的には、リクエストの種類が2つあり、それぞれ「GETリクエスト」「POSTリクエスト」になります。

GET(ゲット)リクエスト

ブラウザで、URLを叩いたときに「XXXX.html」のようなファイルを開くときに使用するリクエストです。
その名の通り、対象のファイル(HTMLファイル)をダウンロード、ブラウザで表示します。
もし、ブラウザではなくプログラムで対象のURLにアクセスしたときはどのようになるか?

下の画像は、次のコマンドをコマンドプロンプトでたたいたときの結果です。

curl https://zenryokuservice.com

POST(ポスト)リクエスト

これは、画面のキャプチャがとりずらく、イメージが取れませんでしたが、よくある「ログイン画面」を思い出してもらうとよいです。
これらの画面には、必ず「ログイン」などのような文言のある「ボタン」があると思います。

この「ボタン」はPOSTリクエストを送信するボタンになっていて、HTMLのみで書くとしたのようなHTMLコードになります。

HTMLソース
<form action="cgi-bin/abc.cgi" method="post">
<p>
名前:<input type="text" name="namae">
</p>
<p>
<input type="submit" value="送信する">
<input type="reset" value="入力内容をリセットする">
</p>
</form>

実際のブラウザ表示 ※このボタンを押下すると画面がリロードされるだけです。


HTMLソース

名前:



ちょっと補足を加えます。上記のHTMLは「formタグ」で囲っている内容をPOSTリクエストで送信しますという意味ですが、「formタグ」の属性(attribute)部分の「action」を見てみると「空」になっています。

このアクションが「空」になっているときは「このページにリクエストを送信しますよ」という意味になります。

同様に「post」の部分を見てみると「post」と書いてあります。これは「POSTリクエストを送信しますよ」という意味です。

そして、「inputタグ」にある「name」の部分はこの名前で、それぞれの値を送信するという意味になります。
つまりは、submitのボタンを押下したら、送信先へPOSTリクエストが送られるのですが、POSTリクエストはデータが一緒に送信されます、GETリクエストでも、データの送信ができますが、この場合はURLの後ろに「?変数名1=値,変数名2=値 ... 」のようにURLへ値を書く必要があります。

これでは、ログイン情報などの秘密にしたい情報が公開された状態でリクエストを送信することになるのでとても危険なのです。そのために「POSTリクエスト」を使用します。

JavaでのWebサーバー

このサイトを参考にしました。

結論から言うと、ServerSocketで受付(ポートを指定してリスン状態で待機)してHTTPメッセージを返却する。と言うものがWebサーバーの正体のようです。

シンプルなSocketサーバーは以前作成しました。

これを一度作ったことがあるならば(ServerSocketアプリのことです)わりかし簡単に作成することができると思います。

しかし、現時点では、HttpServletクラスを拡張した実装を行う方向で話を進めているのであくまでも下のようなコードをベースに考えてもらいたく思います。

public class JspLlesson1 extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.setContentType("txtext/html; charset=UTF-8");
        PrintWriter write = res.getWriter();
        write.println("Hello World");
    }
}

このコードは、Tomcatを使用したときのコードです。Eclipseで実行したのですが、作成した上のクラスファイルを右クリックして「で起動」をクリックすると実行する事ができます。

これで、「サーバー上で利用できるリソースがありませんでした。」のようなメッセージが表示されたら下の手順で、実行することができるようになります。

Tomcatの準備

Tomcatランタイムの追加

Eclipseの上部にあるメニューからウィンドウ -> 設定を選択、下のイメージのように 検索部分に「サーバー」と入力 -> 赤枠を選択します。

そして、Java8を使用しているので、Tomcatの8.5を選択します。

ここで、Tomcatがインストール(ダウンロード)されていない場合は、Apacheのサイトからダウンロードしてきます。

ダウンロードした、Tomcatを展開して、Eclipseの設定でそのフォルダーを指定します。

最後に完了を押下します。

サーバープロジェクトの追加

1.パッケージエクスプローラーを右クリック、そのほかのプロジェクトをクリック
2.下のイメージのように、その他から次へをクリック

3.同様に、完了をクリックする※設定を確認する

4.プロジェクトファセットの設定を行います。

5.プロジェクトを選択して「Altボタンを押しながらEnterを押下」すると下のような画面が見れます。

6.プロジェクトファセットを選択、下のイメージのようにJava1.8を設定、動的ウェブモジュールを設定します。

7.設定を適用します。

8.web.xmlを生成します。

web.xmlの設定を行う

書き方は以下のようになります。

<servlet>
  <servlet-name>サーブレット名</servlet-name>
  <servlet-class>クラスファイル名</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>サーブレット名</servlet-name>
  <url-pattern>呼び出す時につけるURLパス名</url-pattern>
</servlet-mapping>

classesフォルダを作成する

最終的に下のように、フォルダ構成を作ります。

JavaServletを実行する

この状態で、下のように、プログラムを実行します。

以下のURLにアクセス

localhost:8080/プロジェクト名/

今回作成したプロジェクト名が「StudyJavaBasic」なので下のようなURLにアクセスすると作成したサーブレットが起動できます。

http://localhost:8080/StudyJava/

Httpメッセージ

よく、「Httpヘッダー」とか「Httpボディ」とか言ったりしますがHttpメッセージの「ヘッダ」「ボディ」と言うのが正確な言い方です。

参考の処理内容

  1. ServerSocketをXXXポートで待機
  2. リクエストを受け付けたら、受け取ったメッセージ(Httpメッセージ)から相手のIPを取得
  3. IPを使用してHttpレスポンスを作成
  4. OuputStreamでリクエスト元に返却する(レスポンスを返却する)

と言うような流れで処理を作成しているようです。

レシピ

詳細に関しては、Java APIを参照してください。

  1. ServerSocket
  2. BufferedReader(Reader)
  3. DataOutputSream(OutputSream)

こんなくらいです。

webサーバー

  1. リクエストを受けて(SocketServer#accept())
  2. リクエストの値からファイルを読み込む
  3. HTTPメッセージボディにHTMLを書く
  4. データ(DataOutputSream)を返却

シンプルにこんな手順で処理を行えば良いと思います。

低レベルなAPIは、全て作成する必要がありますが、逆に言えば全てが想い通りに作れると言うところが魅力的(笑)

こんな感じで考えております。このアプリにどんな機能を追加するかは作成者の思うままですね。。。

何やろうかな?

でわでわ。。。



Java Mid Basic 〜チェッカークラスを作る〜

オブジェクト指向の実装

オブジェクト指向の考え方では1クラス1機能です。前回作成した、数秘術→社会人基礎力の数値を算出するクラス内に入力チェック処理を作るとあの処理、この処理…と面倒なので、チェッカークラスを作成します。

そして、staticの使い方に関しても触れます。

チェッカークラスは、チェック処理を担当するクラスです。

コマンドクラスから呼び出す

コマンドクラスはインターフェースを使用してCommandIFを実装したクラスであればなんでも良い様に作成しました。

今度は、入力チェック用のクラスを作成します。ここで大切なのは「どの様に使うか?」です。

今回は、シンプルにチェッカーユーティリティクラスを作成します。クラス名は「CheckwrUtil」にします。

使い方は以下の様に静的呼び出しで行います。理由は、インスタンス化する意味がないからこの様な形で実装します。

CheckerUtil.isMandatory("文字列");

クラスの実装は下の様になります。

public class ChckerUtil {
    public static boolean  isMandatory(String inut) {
        // チェック処理
    }
}

そして、必須入力チェックなので、入力の有無を判定し、TrueかFalseを返却するように実装してやればオッケー。

具体的に

コマンドクラスでの実装サンプルです。

public class HelloCommand implements CommandIF {

 /* (non-Javadoc)
    * @see jp.zenryoku.sample.lv3.refactor.CommandIF#execute()
     */
    @Override
  public void execute() {
        // TODO Auto-generated method stub
     System.out.println("名前を入力してください");
      Scanner input = new Scanner(System.in);
      String inStr = input.nextLine();

      if (CheckerUtil.isMandatory(inStr)) {
         // 未入力時の処理
      } else {
         // 入力ありの時
      }
   }
}

executeメソッドで、入力時のチェック処理を行います。

とりあえずは、こんな感じの実装で使用することを想定して作りました。

ポイント

通常は、newしてから使用するメンバーメソッドを作るのですが、この処理には、インスタンスを作る必要がないので、staticをつけた静的メソッドに行くしています。

詳細

インスタンスを作る必要性に関して「通常」と言う言葉を使いましたが、何かしらの処理を行うのに、準備が必要な時、処理するデータを1クラスに1つ持たせたい場合などにはインスタンスが必要です。

例えば、DBにアクセスする時には、DBサーバーへのコネクションを取得、保持する必要があり、アクセス(データを取得する操作を複数人が行う想定の場合にはstatic(静的)クラスやメソッドは使えません。何故かと言うとstaticをつけると、メソッドの場合は、インスタンス1つにつき1つのクラスにしか影響しなかったのが全てのインスタンスに影響します。

具体的には

リストにデータを設定する場合、リストの中身のデータクラスがstaticだと、リストの中身が全部同じになります。

逆にstaticでない場合は、それぞれのクラスに別々のデータが設定されます。

## ポリモーフィズムのサンプル
CommandIF(インタフェース)を使用したポリモーフィズムの実行動画があります。