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

イントロダクション

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

クラスの役割分担をする

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

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

  • メインメソッドを持つクラス
  • じゃんけんゲームを起動するクラス
  • じゃんけんの入力や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)します
<作成するインターフェース>

public interface ExeInterface {
    // 抽象メソッド(implementsしたクラスに実装を強制する)
    public execute(Scanner scan);
}

<FirstClsにimeplementsする>

public class FirstCls implements ExeInterface {
    // 中身は省略
}
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を作成したとします。
メインメソッドも下のように修正します。

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

<プロパティファイルを読み取る例>

/** コンストラクタ */
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);
    }
}

<プロパティファイルのキーから値を取得する例>

/**
 * プロパティファイルから値が取得できた、値を返し
 * 取得できない時はから文字("")を返す
 * @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);

の部分です、リフレクションの実装になります。クラスの完全名からクラスオブジェクトを取得、インスタンスの生成。というような処理を行います。

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 ミニゲーム ソース 〜じゃんけんゲーム 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の基本といってもいろいろあるので、クラスの作り方をメインにやろうと思います。

本記事の概要

  1. クラスとメインメソッドの作成
  2. ハローワールドの作成
  3. プログラム引数を受け、IF文追加
  4. プログラム引数が複数あっても起動するように修正
  5. 計算処理を追加
  6. 一度作成したコードを残して、再度呼び出す方法を考える
  7. クラスを作って処理(メソッド)を残す
  8. 実際にクラスを作って役割分担をする

早速作りましょう

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

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

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

my.sample.Main

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

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

Javaを起動する時には、まずJVMが動きます。そして、このJVMはメインメソッドを動かします。

どんなに大きなアプリケーションでも必ず動きます。それを忘れないでください。

何をするか考える

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

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!");
    }
}

変数名「args」というのが、プログラム引数です。この引数はプログラムを実行する時に渡す事ができます。

「args」は配列になっていて、プログラム引数に渡す時はスペースで区切ります。なので配列の長さが0の時は引数なしと判断します。

アプリを起動するときに、デバッグモードで起動、バッチ、シェルから起動など、そんな時に使うことが多いです。ちなみにプログラム引数に関しては下のリンクを参照下さい。

コマンドライン引数

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: クラスを作る(役割分担)

とりあえず、今メインメソッドにある処理は邪魔なので、作成したクラスへ移動してしまいます。

  • つまり、下の様に役割分担をします。
    1. メインメソッドを持つクラス
    2. 処理を持っているクラス

    処理を持っているのは、新たに作成したクラスは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++環境〜EclipseにCDTをインストール〜
    3. Setup OpenGL with Java〜JOGLを使う準備 for Eclipse〜
    4. Eclipse Meven 開発手順〜プロジェクトの作成〜
    5. Java OpenCV 環境セットアップ(on Mac)
    6. Eclipse SceneBuilderを追加する
    7. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~

    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 Git〜Gitリポジトリからクローン〜


    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でない場合は、それぞれのクラスに別々のデータが設定されます。


    Java Mid Basic〜数秘術から社会人基礎力のロジック〜

    今回は、数秘術の数字を算出する処理を実装します。
    参照するのは、こちらの本です。

    数秘術の数字

    この本によるとまずは「ネームチャート」を作るのがはじめの一歩のようです。「〜ようです」というのは明示的に書いてないのでこのような書き方をしています。

    ネームチャート

    早い話が、名前をローマ字(アルファベット)にして母音と子音を出し、それに数字を割り振ったものです。
    具体的には「Nanashino Takunoji」であれば下のようになります。

    Nanashino -> 
    母音[ 1, 1, 9, 6] "aaio";= 1+1+9+6=17=>1+7=「8」
    子音[5, 5, 1, 8, 5]"Nnshn"= 5+5+1+8+5=24=>2+4=「6」
    合計する=>8+6=14=>1+4=「5」
    
    Takunoji -> 
    母音[ 1, 3, 6, 9] "auoi";= 1+3+6+9=18=>1+8=「9」
    子音[ 2, 2, 5, 1]"Tknj"= 2+2+5+1=10=>「1」
    合計する=>9+1=10=>「0」
    

    苗字の部分の計算、名前を計算して結果を出します。
    ちなみに最後に算出している数字は「人格数」にあたります。

    ロジックにする

    「ロジック」と聞いて「は?」となる人のために記載しますが、早い話が、入力に対して想定通りの結果を返せる「処理」のことです。
    今回の場合は。。。
    入力:「名前(フルネーム)」のアルファベットが入ります。
    出力:上で示したように「人格数」となりそうですが、そうではなく、母音と子音の"["と"]"で囲まれた数字を出力として欲しいのです。
    この出力結果が「人格数」になると他の「運命数」は「生年月日」なので違いますが、「ハート数」などが算出できません。

    いざロジック

    初めに上に示したものを作成します。入力が「名前」出力が「母音と子音の数字配列」です。
    しかし、Javaのメソッドの返り値は1つだけなので文字列に区切りもの「,(カンマ)」をつけて分けます。。。
    いや、面倒なので配列にしてしまいましょう。コードにすると次のようになるのですが、今回は処理の仕様が決まっているので「テストケースから作成します。→「テスト駆動型開発」というやつです。
    作成したテストコードもあります。

    でわでわ。。。



    Java Mid Basic 〜数秘術から社会人基礎力のロジック〜

    イントロダクション

    前回までに、占い(数秘術)と社会人基礎力の調査を行い、占いから社会人基礎力のパラメータを算出する方法を作成しました。
    今度は、それをプログラムで実装しようというわけです。

    設計

    数秘術の数字の算出方法は占いの手順をそのまま行うので良いのですが、各数字(人格数、運命数。。。)から「社会人基礎力」の算出に関しては、理論も何もないので「直感」で割り振りました。下のような感じになります。詳細は前回の記事に記載しております。

    <社会人基礎力>
    1:「目的」
    2:「学び」
    3:「統合」
    <ルール>
    「人格数」: 1:「目的」と2:「学び」に割り振る
    「運命数」: 3:「統合」に割り振る
    「ハート数」: 1:「目的」に割り振る
    「意思数」: 2:「学び」に割り振る
    「成熟数」: 3:「統合」に割り振る

    処理手順について

    処理手順は前回の記事に記載した、算出方法がそのまま適用されます。
    つまり、以下のような手順になります。

    手順

    1. 数秘術で各数字(人格数など)を算出
    2. 社会人基礎力への変換表に付け合わせて値を割り振る

    しかし、この手順ではプログラムに落とすことができません。視点が人間目線なので機械のレベルまで掘り下げてやる必要があります。
    人間目線(高レベル)→機械目線(低レベル)というようなイメージです。そして、世間でよく言われている「高レベルAPI」という言葉は人間目線に近いAPIという意味です。逆にいうと細かい部分の操作ができません(笑)

    レベルを下げる

    初めの手順ではレベルが高い位置にあるので、これを下げて機械レベル(PCレベル)に近づけていきます。
    上の手順を「PC操作でやろうとした時にどのように操作するか?」を考えます。そうすると下のようになると思います。

    1. 数秘術で算出するのに必要な「名前」と「生年月日」を入力する(名前はローマ字 or アルファベット)
    2. 入力されたアルファベット(ローマ字を含む)より、数秘術の計算を行う
    3. 各数字(人格数など)を算出し、社会人基礎力のマップに照らし合わせて、各項目に対しカウントアップ(割り振り)を行う

    以上のような手順になります。

    プログラムにすると

    大雑把に下のような形になります。もちろん他にも方法はありますし、このサンプルが気に入らなければ他のやり方でも結構です。むしろアイディアを聞かせて欲しいくらいです(笑)

    とりあえずは、このような形でプログラムを作成していけばゴールにはたどり着けるであろうというものです。

    関連ページが下の方にあるのでよかったらどうぞ。

    public class CreatePlayerParam implements CommandIF {
    
        /** 
         * CommandIFを実装する、コマンドクラス。
         * 
         * @see jp.zenryoku.sample.lv3.refactor.CommandIF#execute()
         */
        @Override
        public void execute() {
            // 標準入力
            Scanner input = new Scanner(System.in);
            System.out.println("あなたの名前をローマ字(ヘボン式)で入力してください: ");
            // 入力された文字列
            String inStr = input.nextLine();
    
            // 母音を切り取る
            String boIn = cutOffBoin(inStr);
            // 子音
            String shiIn = inStr;
            // 人格数
            int jinkakuSu = getJinkakuSu(boIn, shiIn);
            // 運命数
            int unmeSu = getUnmeSu(boIn, shiIn);
            // ハート数
            int heartSu = getHeartSu(boIn, shiIn);
            // 意思数
            int ishiSu = getIshiSu(boIn, shiIn);
            // 成熟数
            int seijukuSu = getSeijukuSu(boIn, shiIn);
            /* 社会人基礎力の算出 */
        }
    
        public String cutOffBoin(String inStr) {
            // 未実装
            return null;
        }
    
        public int getJinkakuSu(String boIn, String shiIn) {
            // 未実装
            return 0;
        }
    
        public int getUnmeSu(String boIn, String shiIn) {
            // 未実装
            return 0;
        }
    
        public int getHeartSu(String boIn, String shiIn) {
            // 未実装
            return 0;
        }
    
        public int getIshiSu(String boIn, String shiIn) {
            // 未実装
            return 0;
        }
    
        public int getSeijukuSu(String boIn, String shiIn) {
            // 未実装
            return 0;
        }
    }

    以前作成したCommandIFを使用して、このクラスをロードしてパラメータを算出するような実装にしようと思っているので。このクラスのみを作成すれば、今まで作成していたコンソールアプリに組み込むことができます。詳細は上記のリンクを参照してください。

    でわでわ。。。

    関連ページ

    Java Mid Basic テキストRPG 〜数秘術から社会人基礎力を算出〜

    イントロダクション

    前回は、数秘術についてどんなものか調べました。
    今回は「社会人基礎力」を算出する、ルールを作成します。
    詳細な内容に関してはこちらの記事に記載しました。
    大雑把に、数秘術の書く値が、それぞれどのような意味を持ち、それに対して関連付ける値はどのようなものが良いか?を考えるための材料を揃えた次第です。調査自体はなかなか面白かったし、女性には喜ばれますね。ちょっとだけ相談しました。→「占いって興味ありますか?」的なことを聞きました。
    そして、まとめたものが、以下のような表になります。


    1:「目的」=>「前に踏み出す力」のために必要とされる

    主体性:1、7、9
    働きかけ力:3、7、9
    実行力:1、5、8

    2:「学び」=>「考え抜く力」のために必要とされる

    課題発見力:2、4、8
    計画力:2、5、8
    創造力:1、2、9
    3:「統合」=>「チームで働く力」のために必要とされる

    発信力:1、4、9
    傾聴力:1、7、0
    柔軟性:4、6、9
    情報把握力:1、7、0
    規律性:4、6、0
    ストレスコントロール力:1、5、9


    算出手順

    [Step1]
    まずは数秘術にて、以下の数値を算出します。詳細はこちら

    1. 「人格数」: 名前の合計
    2. 「運命数」: 生年月日の合計
    3. 「ハート数」: 母音の合計
    4. 「意思数」: 子音の合計
    5. 「成熟数」: 人格数 + 運命数
    6. 「特性数」:用途未定
    7. 「欠落数」:用途未定

    そして、それぞれに算出した値を上記の表に割り当てます。

    <例>
    「人格数」: 名前の合計=1
    「運命数」: 生年月日の合計=2
    「ハート数」: 母音の合計=3
    「意思数」: 子音の合計=4
    「成熟数」: 人格数 + 運命数=3
    のような結果が出た人であれば、上記の表と以下のルールより
    <ルール>
    「人格数」: 1:「目的」と2:「学び」に割り振る
    「運命数」: 3:「統合」に割り振る
    「ハート数」: 1:「目的」に割り振る
    「意思数」: 2:「学び」に割り振る
    「成熟数」: 3:「統合」に割り振る

    主体性:1
    働きかけ力:1
    実行力:1
    課題発見力:1
    計画力:
    創造力:1
    発信力:1
    傾聴力:1
    柔軟性:
    情報把握力:
    規律性:
    ストレスコントロール力:

    のようになります。これは「先天的に持っている」という程のデータになるのと、ゲームで使用するパラメータなので「なんか点数低くね?」とか思わないでください。。。

    でわでわ。。。

    関連ページ

    1. テキストRPGを作る〜数秘術の概要まとめ〜
    2. Java Mid Basic〜リファクタリングLv2 処理の整理とクラス分け(準備編)〜
    3. Java Mid Basic 〜Lv3_2_Javaの基本(リファクタリングLv2)ゲームループ付き
    4. Java Mid Basic〜リファクタリングLv2 Mainメソッドを作る〜
    5. Java Mid Basic〜リファクタリングLv2 プロパティファイルで無修正ものを作る〜
    6. Java Mid Basic 〜仕様作成、数秘術から社会人基礎力〜


    Java Mid Basic 〜仕様作成、数秘術から社会人基礎力〜

    イントロダクション

    こちらのサイトを見つけました、内容は、「社会人基礎力」について項目を挙げ、各内容について記載している記事です。丁度、ゲームのパラメータに悩んでいたところヒトとしてのパラメータ的なものがあったので、参考にしたました。
    使用するのは以下のものです。

    <数秘術>; 下のリンクは広告です。

    経済産業省提唱「社会人基礎力

    換算する値

    以下の項目が、「社会人基礎力」で挙げられている項目です。12個あります。カテゴリとしては、1〜3=①, 4〜6=②, 7〜12=③の様に分けます。

    <パラメータ>

    1. 主体性: 1, 7, 9
    1. 働きかけ力:3, 7, 9
    1. 実行力:1, 5, 8
    1. 課題発見力:2, 4, 8
    1. 計画力:2, 5, 8
    1. 創造力:1, 2, 9
    1. 発信力:1, 4, 9
    1. 傾聴力:1, 7, 0
    1. 柔軟性:4, 6, 9
    1. 規律性:4, 6, 0
    1. ストレスコントロール:1, 5, 9
    1. 状態把握力:1, 7, 0

    これらの項目に値を設定するのですが、結論から言うと計測不能なので直感で割振りました。数秘術で算出した以下の項目を使います。

    数秘術の値

    • 人格数=①と②に割り振る
    • 運命数=③に割り振る
    • ハート数=①
    • 意思数=②
    • 成熟数=③
    • 特性数=保有属性
    • 欠落数=弱点属性

    上の値は、<パラメータ>の表にある数字部をカウントする形で算出します。

    人格数が9の人は、表の番号1, 2, 6に一点加算するといった形で計算していきます。

    数字について

    数字; 属性 / 星; 神様
    1: 火 / 太陽; ヘリオス, アポロン )
    2: 水 / 月; セレネー, アルテミス
    3: 風 / 土星; クロノス, サトゥルヌス
    4: 地 / 地球: ガイア
    5: (エーテル)風 / 水星; ヘルメス
    6:地/ 金星; アプロディーテー, ヴィーナス)
    7: 風 / 海王星; ネプチューン, ポセイドン
    8: 水 / 土星; クロノス, サトゥルヌス
    9: 火 / 火星; アレス

    これらの数字は、「特製数」と「欠落数」に対応させようと考えております。

    特性数

    1、3、4が特性数の場合→火、風、地の属性を持ちます。そして、ネームチャートに出て来た数字の数をレベルにします。つまり「A」が2回、「C」が1回、「D」が3回出てくるような人は火=Lv2, 風=Lv1, 地=Lv3となります。

    欠落数

    逆に2、5、8が欠落数の場合は水、(エーテル)風が弱点になり、2と8は属性が「水」なので水が致命的な弱点になります。

    とりあえず

    現状ではこんな感じの仕様でゲーム作成を行おうと思います。

    でわでわ。。。



    Java Mid Basic〜Lv3_4_リファクタリングLv2 プロパティファイルで無修正ものを作る〜

    イントロダクション

    前回は、メインメソッドの修正を行わないでのコマンド追加実装をやりました。
    具体的には、コンストラクタに作成した、クラスをマップに登録する処理を追加します(1行)。。。
    しかし。これもなんだかんだとクラスの修正をしているのでイマイチです。なので

    メインクラスを修正しない

    この方向でコマンドを追加する方法を実践したいと思います。その方法は以下の手順で行います。

    1. プロパティファイルにキーとクラスの完全名をセットにして登録する
    2. クラスの完全名からクラスのインスタンスを取得して実行するようにする

    上記のような形になります。「よくわからん。。。」と思った方、詳細を下に記載します。

    修正のいらない実装

    修正をしなくても「クラスを追加」もしくは、「新しい機能の実装を追加」するためには「依存関係を分断」してやる必要があります。

    依存関係の分断

    依存関係とは「関連性がある」ということ、つまり「関連性がある=片方を修正したら、もう片方も修正する必要がある」という関係が出来上がっていることです。
    よく世間では「依存関係の注入」などという言葉で言いますが、実際どういうことか?に関して触れていることが少ないように感じています。
    実装方法に関してはいろんな記事があり、わかりやすく説明がされていると思います。

    つまり

    依存関係を分断しようということです。具体的には下のように考えます。

    1. 新しい機能を追加するときには今実装している部分を修正したくない
    2. 新しく機能を追加するのと、実装中のクラスを修正しない方法は?

    大雑把に、上のように考えます。サンプルとして今回のサンプルアプリを参考にして考えてみます。
    現状の実装はGitにあるソースを見てもらうと一目瞭然です、一部抜粋して以下に示します。(メインメソッドのみ抜粋)

    public static void main(String[] args) {
        // コマンドの用意
        cmdMap = new HashMap();
        cmdMap.put("hello", new HelloCommand());
        cmdMap.put("ready", new ReadyCommand());
        // 標準入力
        Scanner input = new Scanner(System.in);
    
        while(true) {
            System.out.println("入力してください: ");
            String inStr = input.nextLine();
            CommandIF cmd = cmdMap.get(inStr);
            if (cmd != null) {
                cmd.execute();
            }
            if ("bye".equals(inStr)) {
                System.out.println("Good Byw");
                break;
            }
        }
    }
    

    動きは下の動画のようになります。

    この状態では、Mapにコマンドクラスを追加してやれば新しい機能を追加できます。なので修正するポイントはコンストラクタのみになります。

    この際だから。。。

    そう、「ここまできたら最後までいけ!」と思うのが人情(自分だけでしょうか?(笑))、なのでやってしまいましょう。

    <実装手順>

    1. コンストラクタでMapにコマンドクラスを追加するのをやめる
    2. その代わりにプロパティファイルを使用する
    3. プロパティファイルから完全クラス名を取得し、インスタンスを生成
    4. 生成したインスタンスのメソッドを実行する

    このようにしてやれば、メインクラスの修正はいりません。
    <追加するもの>
    ・プロパティファイル
    ・プロパティファイルのロード処理
    ・同様に値の取得処理

    [CommandList.properties]
     hello=jp.zenryoku.sample.lv3.refactor.cmd.HelloCommand
    ready=jp.zenryoku.sample.lv3.refactor.cmd.ReadyCommand
    
    /** プロパティファイル取得 */
    public void loadPropertyFile() {
        prop = new Properties();
        try {
            // resources/
            prop.load(getClass().getResourceAsStream("/CommandList.properties"));
        } catch (IOException e) {
            e.printStackTrace();
            // エラーコード-1をセットしてプログラム終了
            System.exit(-1);
        }
    }
    

    プロパティファイルからインスタンスの取得

    public CommandIF getCommandIF(String key) {
        // 完全クラス名を取得する
        String fullClassName = prop.getProperty(key);
        if (fullClassName == null || "".equals(fullClassName)) {
            return null;
        }
        CommandIF cmd = null;
        try {
            @SuppressWarnings("unchecked")
            Class cmdCls = (Class) Class.forName(fullClassName);
            cmd = cmdCls.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(-1);
        }
        return cmd;
    }

    このように、メインメソッドの修正を行わなくてもCommandIFを実装したクラスの数だけコマンドに対する実行処理を作成することができます。

    その代わり、プロパティファイルにキーと値を追加する必要がありますが。。。しかしコードを修正するとテストを行う必要があるので格段に余計な手間と時間を省くことができます。

    まさに「無修正」

    エロいですねぇ(笑)

    できた時間を使用して、心と体のリフレッシュ及び、楽しい時間を過ごす。。。これが平和への第一歩だと思います。
    このように、時間を大切に使わないと、昔の不況時代のように「寝る暇がない!」とか「今日も漫画喫茶でお泊まり!」とか。。。おおよそ人間の尊厳が無いような、不幸なことになってしまうので、日々精進を重ねることが大切だと思います。。。趣味にしてしまうのが一番手っ取り早いという噂もあるとか無いとか(笑)

    でわでわ。。。



    Java Mid Basic〜Lv3_3_リファクタリングLv2 Mainメソッドを作る〜

    イントロダクション

    初めに、メインメソッドを整理して、オブジェクト指向プログラミングの準備を行いました。そして、次にインターフェースの使い方について記載と実装を行いました。

    <早い話>
    クラスを使用して、役割分担をしたいけど。。。処理がごちゃ混ぜになっていると分担しづらいので整理して、どこでどんな処理をしているかわかりやすくしました。

    インターフェースを使う

    今回からは、1クラス1機能の形で実装していきたいと思います。

    なので、複数クラスを使用していきますので、あっちこっち飛ぶことになります。

    まずはメインメソッドのクラスを作成します。名前は「Lv3_1_RefactorLv2_Main」にします。
    そして、今までやってきたものとほぼ同じものを作成します。
    <実装内容>
    ・標準入力からコマンドを実行する
    ・「hello」コマンドで「Hello World」をコンソールに表示
    ・「ready」コマンドで「Ready?」をコンソールに表示
    ・1クラス1機能

    上記のような形で実装します。
    <実装するクラス>
    Lv3_1_RefactorLv2_Main「処理フローを作る」
    CommandIF「コマンドを作る」
    HelloCommand「helloコマンド」
    ReadyCommand「readyコマンド」

    上記の4クラスを作成します。
    ここで、インターフェースの使い方を復習します。以前記載したインターフェースの使い方も参照ください
    ちなみに、インターフェースの作り方(Eclipseでの作成方法)に関しては下の動画を参照ください。

    インターフェースの使い方

    インターフェースは、実装部分のないメソッドの宣言のみが実装されているクラスのことです。具体的には下のようなコードになります。

    /**
     * コマンドインターフェース
    * インターフェースは、処理内容を書きません。 * * @author takunoji * 2019/08/23 */ public interface CommandIF { /** コマンドを実行する */ public void execute(); }

    インターフェースクラスの名前は「CommandIF」で実行するメソッドは「execute()」です。このインターフェースを実装(Implements)するクラスは「execute()」メソッドを実装する義務が生じます。つまり実装しないとビルドエラーになります。

    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("Hello World!");
        }
    }

    オーバーライド

    ちなみに「@Override」はオーバーライド、メソッドのオーバーライドのことを意味しています。オーバーライドの使い方は大雑把に2種類あります。
    <パターン1: Interfaceのオーバーライド>
    上のコードそのままです。
    <パターン2: 実装されているものをオーバーライド>
    Javaでの自作クラスを含む全てのクラスは「Objectクラス」を親クラスに持ちます。親クラスのことを「スーパークラス」と呼び、こちらが世界でも通用する言い方になります。具体的には、以下のようなクラスを作成したとします。

    public class ReadyCommand /* implements CommandIF */ {
    
        /* (non-Javadoc)
         * @see jp.zenryoku.sample.lv3.refactor.CommandIF#execute()
         */
        /* @Override */
        public void execute() {
            // TODO Auto-generated method stub
            System.out.println("Ready?");
        }
    }

    本当は、CommandIFを実装しているクラスなのですが、説明のため。。。

    オーバーライド2

    このクラスは「スーパークラス」(super class)にObjectクラスを持っています。なので、Objectクラスのメソッドも使用することができます。その証拠にEclipseなどのIDEを使用してコードアシスト機能などで使用できるメソッドが選択できることがありますが、これはObjectクラスのメソッドです。(下のイメージ参照)

    そして、この「equals()」メソッドをオーバーライドすると下のような実装になります。

    public class ReadyCommand implements CommandIF {
    
        /* (non-Javadoc)
         * @see jp.zenryoku.sample.lv3.refactor.CommandIF#execute()
         */
        @Override
        public void execute() {
            // TODO Auto-generated method stub
            System.out.println("Ready?");
        }
    
        @Override
        public boolean equals(Object cls) {
            return true;
        }
    }

    インターフェースを使う

    これに関しては、詳細の説明よりも動かしてみるのが一番だと思うので(実装してみるのがベスト)、実行結果を舌に載せておきます。

    このように、作成したコマンドクラスを登録してやるだけで新しい処理を追加できます。しかしこれではMainメソッドの修正が必要になるのでイマイチです。

    次回は、メインメソッドを修正しなくても良いようにリファクタリングします。

    でわでわ。。。