Java Mid Basic 〜Lv3_1_Javaの基本(リファクタリングLv2)ゲームループ付き

イントロダクション

前回は、リファクタリングをやり、メインメソッドを整理しました。ここまで来た方、おめでとうございます。

ここから、オブジェクト指向プログラミングの始まりです。

今迄の事がわかれば何かしらの処理を自分で考えて作れるレベルになっていると思います。でわ、ここから何をやるか?ですが、基本の更に深いところ、オブジェクト指向について理解していこうと思います。

オブジェクト指向

オブジェクト指向については、色々な書籍があり、色々な事が書かれていますが、ネコとかイヌを例に出しているものは、混乱すると思います。(自分はハマりました(笑))

他にも、個人的な呼び名でありますが「staticおじさん事件」というのがあり、左記のリンク先にある結論が面白かったのでこのような呼び方をした次第です。

現状は「オブジェクト指向プログラミング言語」というカテゴリのプログラミング言語がほとんどです。よく「オブジェクト指向」とか「手続き型」とか「関数型」とか言いますが、どれもこれも書き方を間違えれば「カオス化」するという事です※上記のリンク先参照。

クラスとオブジェクト

クラスの書き方をしたのように図にして見ました。ズバリUMLになります。

「オブジェクト指向ってなによ?」という疑問がはじめに出てくると思います。諸説ありますが。。。

早い話が

「プログラムの資源を現実にあるモノ(オブジェクト)と同じように扱う(考える)ためのコードの書き方(考え方)」です。
いろんな人がいろいろなことを言うので混乱すると思いますが、下のUMLのクラス図ように「クラスというハコを使ってプログラムを考えましょうよ」というのが「オブジェクト指向」という考え方の基本になります。※筆者の解釈なので自分で考えて、イメージをつけるようにしてください。

ちなみに、「クラス」をインスタンス化すると「オブジェクト」になります。
プログラムコードで書くならば下のようになります。

下のコードでは、上記の人間クラスを具体的なプログラムコードにしてみました。この「Humanクラス」を使用するときにはメインメソッドで実行します。
この「クラス」を「new」するとクラスはオブジェクトを生成します。このときに生成されたオブジェクトには必ず「フィールド変数の値を持っています」
ここがクラスとオブジェクトの大きな違いです。

このようにクラスを使用すれば、一つのクラスを定義すれば

  1. 引数なしで「new」すると名前がTakunojiになります。
  2. 引数ありで「new」すると年齢と名前、体重を指定した「誰か」になります。

明確に言うのであれば

「クラス」というテンプレートを用意して、「new」することで、実際に値をセット(テンプレートに書き込んだ)オブジェクトが生成されるということです。

<人間クラスのプログラムコード>

public class Human {
    /** 年齢 */
    private int age;
    /** 名前 */
    private String name;
    /** 体重 */
    private double weight;

    /** コンストラクタ */
    public Human() {
        this.age = 43;
        this.name = "Takunoji";
        this.weight = 60;
    }

    /** コンストラクタ:オーバーライド */
    public Human(int age, String name, int weight) {
        this.age = age;
        this.name = name;
        this.weight = weight;
    }

    /** 挨拶 */
    public void greet() {
        System.out.println("私の名前は、" + this.name + "です。" + this.age + "歳です。");
    }
}

<クラスのインスタンス化などの解説>

具体的に

プログラムを眺めてみると、1つのファイルに1000行を超える様なデカイ、ファイルになっているものがあったりします。申し訳ないがこういうプログラムは「オブジェクト指向」していません。何故か?再利用出来ないからです。

つまり、「オブジェクト指向」とか、いろんなことを言っても「きれい」で「再利用できる」かつ「わかりやすい」コードが「良いコード」ということです。上のような「オブジェクト指向していません」という言葉は「良いコードでない」という意味です。※筆者も不適当な使い方をしていたみたいです。。。すいません。。。

まずは概念

プログラムの動きは、目に見えないので大雑把な概念からイメージの輪郭を拾います。この概念を理解するのにわかりやすいのがUMLだと思うのでUMLのクラス図を例に出したいと思います。

UMLの細かい部分に関しては下のリンクを参照下さい。

UMLツール Star UML〜ユースケース図を書いて見た〜

クラス図の書き方

Java言語の基本単位
Java言語の場合、プログラムの基本単位はクラスです。もっと言うと、全てがクラスで表現されます。だからオブジェクト=クラスで考えて良いです。
明確に言うならば、「new」する前と後で、それぞれ「クラス」か「オブジェクト」かの違いになるので、「new」しないで考えるなら「クラス」「new」した後で考えるなら「オブジェクト」ですが、「new」した後で考えるときはデータクラスを考えるときがほとんどなので、あまり区別しなくても問題ありません。

ただし、先ほども申し上げたように「new」する前と後ではちょっと注意が必要です。

下の動画は、クマ(のような)が葉っぱを食べるのですが、Java言語でできているので葉っぱも、クマ(のような)もすべてオブジェクトです。
クマ(のような)はインスタンスが一つ=オブジェクトが一つですが、葉っぱは複数あります。画面に表示された状態が「new」した後です。
<Greenfoot>

上のリンクは、UMLのユースケース図について記載しています。そして、クラス図の書き方も隣のリンクに記載しました。

早い話が、プログラムをどのように使うか?(ユースケース)とどんな構成で作るか?(クラス図)を絵にしたものがUMLです。

準備

オブジェクト指向プログラミングの準備として、どんなクラス構成でやるか?(プログラム・デザイン)を考えます。こんなデザイン(設計)、あんなデザイン…と最も美しい(効率の良い)デザイン(設計)をやります。もちろん「完璧なデザイン(設計)」は存在しないので、現時点での最高のもので良いと思います。

実装

準備の段階で作成したデザイン(設計)を元にコーディングを行います。

今回は、メインメソッドを整理した状態で再実装(リファクタリング)します。注意点は以下の通り。

  1. 作成したオブジェクトは再利用出来るように作る
  1. 各オブジェクト間の依存関係を分断してやる。なるべく「このクラスを使う時はあのクラスも必要…」とならない様にする

あとは「リーダブルコード」を読みましょう(笑)

おススメです。

コーディング開始

とは言っても、即コードを書くわけではありません。まずはコードを眺めます。そして、前回作成したメインメソッドを全体の流れとして考えます。

  1. 無限ループを作る
  2. プロパティファイルから値を取得
  3. 値が取得できない時は初めの実装の処理
  4. byeコマンドでコマンドリストを出力しアプリ終了

この部分はメインメソッドで実装してます。

## 本題
オブジェクト=クラスの構成と使い方に関しては、下のリンクに記載しているので。。。

自作クラスの使い方(呼びたし方について記載します。

まずはしまめに、『クラスを使用する時にはまず「new」します。』という考えを捨てて下さい。必要なので「new」するという事です。

new演算子

クラスをインスタンス化するのはクラスに初期化処理が必要で、同じクラスを複数人で使用したい時など、クラスをnewします。

<例>

サーバーにユーザがアクセス、ログインした場合、LoginUserクラスをインスタンス化しない場合、LoginUserクラスはずっとユーザデータがセットされないので、クラスと言う型が存在しているだけになります。

しかし、インスタンス化してやるとユーザデータがセットされ1つのインスタンスとして存在できるので、サーバーのメモリが許す限り、ログインしたユーザを識別する事が出来ます。

まとめ

大雑把で良いので「クラス」「オブジェクト」という概念に対する偏見(ないのがベスト!)を捨てることができれば、おっけ!です。次回からは実際のコードと実行結果などを見ながら学んでいきたいと思います。

でわでわ。。。

<<< [前回](https://zenryokuservice.com/wp/2019/08/12/java-mid-basic-%e3%80%9clv2_7_java%e3%81%ae%e5%9f%ba%e6%9c%ac%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%92%e8%aa%ad%e3%82%80%e3%82%b2%e3%83%bc%e3%83%a0%e3%83%ab%e3%83%bc%e3%83%97%e4%bb%98%e3%81%8d/) [次回](https://zenryokuservice.com/wp/2019/08/24/java-mid-basic-%e3%80%9clv3_2_java%e3%81%ae%e5%9f%ba%e6%9c%ac%e3%83%aa%e3%83%95%e3%82%a1%e3%82%af%e3%82%bf%e3%83%aa%e3%83%b3%e3%82%b0lv2%e3%82%b2%e3%83%bc%e3%83%a0%e3%83%ab%e3%83%bc%e3%83%97/) >>>

Java Mid Basic 〜Lv2_7_Javaの基本(ファイル読み込み)Files.newBufferedReaderなど〜

イントロダクション

前回は、プロパティファイルの読み込みをやりました。
そして、今回はテキストファイルの読み込みをやります。

前回と何が違うのか?

前回の「プロパティファイル」は読み込むための処理が全てJavaAPIで実装されている状態なので、以下の実装がありません。

早い話が、プロパティファイル以外の、ファイルを読むことができる手順を紹介します。ということです。具体的な手順は下のようになります。

  1. ファイルを開く(Open)
  2. ファイルを読み込む(Read)
  3. データ(ファイルの中身)を取り出す

<ファイルの読み込みでBufferedReaderを使いました。>

ちなみに、ネットワークでの通信処理もこのファイル操作と同様な処理を行うので、つまり概念も同じなので、理解しておくと後々楽ですし、面白いこともたくさんできます。

ファイル読み込み

ファイルの読み込みは上記の手順で行います。
サンプルコードです。テキストファイルは「title.txt」で、配置場所はresources/にあります。

/**
 * テキストファイル"title.txt"を読み込みコンソールに出力します。
 */
public void showTitle() {
    File file = new File("resources/title.txt");
    BufferedReader buf = null;
    try {
        buf = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8);
        // テキストファイルを出力する
        String line = null;
        while((line = buf.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("ファイル読み込みエラーです、アプリケションを終了します。");
        System.exit(-1);
    }
}

ソース全体はGitにアップしてあるのでそちらを参照ください。

処理内容

Fileクラスでtitle.txtをOpenします。

File file = new File("resources/title.txt");

そして、BufferedReaderでファイルの読み込みを行います。

buf = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8);

読み込んだデータ(ファイルの中身)を取り出します。

// テキストファイルを出力する
String line = null;
while((line = buf.readLine()) != null) {
    System.out.println(line);
}

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

でわでわ。。。

<<< 前回 次回 >>>

Java Mid Basic 〜Lv2_5_Javaの基本(コマンド履歴を作る)ゲームループ付き〜

イントロダクション

前回は「dirコマンド」を実装しました。オプションとかは実装してませんが…

配列の使い方

Listについてやりますが、一応までに「配列はこんな感じ」というものを作成したので記載しておきます。

とりあえずは「コマンドを実行」という目的を達成する事が出来たので良しとします。

Listを使う

リストインターフェースなどに関してはこちらの記事を見ていただきたく思います。

今回はこのListを使ってコマンド履歴を作る事にします。今回はリストをフィールド変数にする事でアプリが起動している間データを保持する様にします。

現状の設計

はじめに、アプリを起動したら、コマンドの入力待ちをします。

  1. 「hello」が入力された場合はコンソールに「Hello World」を表示
  2. 「計算式(四則計算)→1+1など」が入力された場合は、計算の結果をコンソールに表示
  3. その他の入力はエラーにして、プログラムを終了

変更後の設計

上の「その他〜」の部分から変更します。

  1. 「hello」が入力された場合はコンソールに「Hello World」を表示
  2. 「計算式(四則計算)→1+1など」が入力された場合は、計算の結果をコンソールに表示
  3. 「bye」と入力されたらコマンドの履歴を表示してアプリを終了する
  4. その他の入力はエラー出力をして次の入力待ちを行う

実装

変更したところは「byeと入力されたら〜」の部分を追加しただけです。
なので、アプリが終了した時に入力されたコマンドの一覧をコンソールに出力する処理を実装します。

具体的に

入力されたコマンドは保持する必要があります。「登録する」とか「保存する」というのはDBやファイルに保存してアプリが終了してもそのデータが保存されることを指します。「保持する」というのはアプリケーションが起動している間など、一時的に保存することを指します。
その簡単な方法として「フィールド変数」を使用する方法がります。

フィールド変数

フィールド変数は下のようにクラスの中に記載します。
ちなみに下のクラスは「人間」を表すクラスを作成しました。

クラスとは

フィールド変数とメソッドを持っている、カプセル化されたオブジェクトです。

人間クラス

public class Human {
   /** 名前 */
    private String name;
   /** 年齢 */
    private int age;
   /** 身長 */
    private int tall;
    /** コンストラクタ */
    public Human() {
        name = "デーモン閣下";
        age = 10040;
        tall = 160;
    }
    public void greet() {
        int num = 0;
        System.out.println("私は" + name + "と申します" + "年齢は" + age + "、身長は" + tall + "cmです"); 
        num = 10;
         System.out.println("num: " + num);
     }
     public void count() {
         int num = 0;
         num = 10;
         age++;
         System.out.println("num:" + num + " / age: " + age);
     }
}

処理内容

  1. コンストラクタでフィールド変数に値を設定します
  2. greet()で挨拶をします

このような形でフィールド変数を使用します。

実際に動かすとき

Javaプログラムを起動するのはメインメソッドなので、下のように実装します。

public class Main {
    public static void main(String[] args) {
        Humain man = new Human();
        man.greet();
    }
}

処理内容としては、Humanクラスをインスタンス化(new)して「greet()」メソッドを呼び出す。
これだけです。上記のクラスに「new」したときの処理=コンストラクタと「greet()」メソッドが定義(実装)されているので
メインメソッドからは呼び出すだけです。

  • 「呼び出す」というのは「man.greet()」と書いている部分のことです。
  • 「定義されている」というのは「greet()」メソッドが実装済みということです。

スコープ

ここで「スコープ」という言葉について記載したいと思います。この言葉は「変数の寿命」を意味します。上のコードで行くとフィールド変数はクラスのインスタンスがある間ずっと生きている変数になります。
具体的には下のコードでHumanクラスを実行した時にローカル変数「num」はメソッドが動いている間だけ生きている変数です。なのでクラスの中でiint num;というコードが複数あってもビルドエラーにはなりません。

public static void main(String[] args) {
    Human human = new Human();
    human.greet();
    human.count();
    human.greet();
}

このように処理を行った時、1回目のgreet()で「age」は10040と表示されますが、2回目は「10041」と表示されます。
対して「num」は何回実行しても「10」のままです。
スコープにより変数の寿命が違うのでこのような違いが出ます。

コマンドの一覧

実装方法に関してはこれまでに記載したので、作成したコードと実行結果を載せます。
サンプルコードはGitに揚げてあります。
そして、起動結果です。


でわでわ。。。

<<< 前回 次回 >>>

Java Mid Basic 〜Lv2_4_Javaの基本(Dirコマンドを作る)ゲームループ付き〜

イントロダクション

前回は、作成したコードを整理整頓しました。前回のものはまだまだ初歩的なものなので創意工夫でより良いコードをかけるようにやって見てください。

注意する単語

  • ディレクトリ:フォルダのこと
  • カレントディレクトリ:コマンドプロンプトでの現在のディレクトリを示す。
  • ファイルシステム:テキストファイルなどのファイルやフォルダツリーをまとめた呼び方

Linuxでの「lsコマンド」とWindowsでの「dir」コマンドは同じようなコマンドです。

<コマンドの解説>

Dirコマンド

コマンドプロンプトを叩いたことがある人は馴染みのコマンドだと思います。ちなみにリナックスやMacの場合は「ls」コマンドで同じことができます。
単純に現在開いているディレクトリ(カレントディレクトリ)にあるファイル(フォルダ)を表示するコマンドです。

JavaでDirコマンド

Javaでコマンドをそのまま実行することができます。
Rumtime.exec()を使用することで可能ですが、今回はJavaプログラムで同じようなことをやって見ます。

Fileクラス

このクラスを使用してディレクトリにあるファイルの一覧を表示する処理を実装します。

/**
* Dirコマンドの処理を実装
*/
public void dirCommand() {
    File dir = new File(".");
    String[] files = dir.list();
    for (int i = 0; i < files.length; i++) {
        System.out.println(files[i]);
    }
}

こんな感じで実装すると、ビルドパス上の(Eclipseでの実装は設定の関係でプロジェクト直下がカレントディレクトリになります。
その実行結果はこんな感じです。

そして、今回作成したコードはGitにアップしてあります。
コマンドの処理部分は割愛しますが、Fileクラスを使用した実装部分について記載します。

Fileクラス

このクラスはファイルやディレクトリを表現するクラスです。実装したコードは上のようなものですが、1行ずつ内容を記載すると以下のようになります。

File dir = new File(".");

現在のディレクトリ(カレントディレクトリ)を示す"."を引数に渡してインスタンス化

String[] files = dir.list();

list()メソッドで対象のディレクトリにあるファイル(ディレクトリ)の一覧を取得します。

for (int i = 0; i < files.length; i++) {
    System.out.println(files[i]);
}

あとはループで表示するだけです、ちなみに指定するディレクトリにより取得するデータ(ファイルなど)の数が違うのでループ文で処理を行っています。

## Fileクラスの例
Fileクラスというとファイルの中身に何かしらを書き込むとか読み込むなどの処理をイメージすると思います。
今までのは。「ファイルシステム」でディレクトリツリーの参照を主軸にしていましたが、ファイルの操作も行うことができます。
以下はサンプル動画です。

<BufferedReaderクラスでファイルを読み込む>

<BufferedWriterクラスでファイルに書き込む>

でわでわ。。。

<<< [前回](https://zenryokuservice.com/wp/2019/07/29/java-mid-basic-%e3%80%9clv2_3_java%e3%81%ae%e5%9f%ba%e6%9c%ac%e3%83%aa%e3%83%95%e3%82%a1%e3%82%af%e3%82%bf%e3%83%aa%e3%83%b3%e3%82%b0%e5%ae%9f%e8%b7%b5%e3%82%b2%e3%83%bc%e3%83%a0%e3%83%ab%e3%83%bc/) [次回](https://zenryokuservice.com/wp/2019/08/06/java-mid-basic-%e3%80%9clv2_5_java%e3%81%ae%e5%9f%ba%e6%9c%ac%e3%82%b3%e3%83%9e%e3%83%b3%e3%83%89%e5%b1%a5%e6%ad%b4%e3%82%92%e4%bd%9c%e3%82%8b%e3%82%b2%e3%83%bc%e3%83%a0%e3%83%ab%e3%83%bc%e3%83%97/) >>>

Java Mid Basic 〜Lv2_3_Javaの基本(リファクタリング実践)ゲームループ付き〜

イントロダクション

前回は、リファクタリングについて触れました。
しかしコードまではいかなかったので、今回はコードの話をします。

リファクタ実践

まずは修正するコードを眺めます。
そーすると、だんだん同じような処理をしているところが見えてきます。

同じ処理をしているのはどこでしょう?

Switch文のところです、switch(kigo) {とコードを書いている部分が複数見当たります。しかも結構な行数を使っている。。。

そんなわけで、対象の部分をまとめてしまおうと考えるわけなのですが、キーワードは「同じような処理(コード)」です、同じような処理なので、値を変えてやれば、ちょっと工夫をすれば、なんとかなりそうです。

自分の出した答えは

「メソッドを作成する」です。そして、作成するメソッドは入力された計算式から「足し算なのか、引き算なのか。。。」を判定するメソッドを作成しました。実際にコードを記載します。

/*
 * judgeKigo()のテスト
 */
@Test
public void testJudgeKigo() {
    Lv2_3_Calculate test = new Lv2_3_Calculate();
    try {
        int kigo = test.jadgeKigo("1+1");
        assertEquals(0, kigo);
        int kigo1 = test.jadgeKigo("1-1");
        assertEquals(1, kigo1);
        int kigo2 = test.jadgeKigo("1*1");
        assertEquals(2, kigo2);
        int kigo3 = test.jadgeKigo("1/1");
        assertEquals(3, kigo3);
    } catch(Exception e) {
        e.printStackTrace();
        fail();
    }
}

処理の内容としては以下の通りです。

  1. テスト対象メソッド(jadgeKigo())に「1+1」を渡した時の結果が「0(足し算)」である事の確認。
  2. 同様に引き算(1)
  3. 掛け算(2)
  4. 割り算(3)

このメソッドが想定通りに動くのかテストします。作成したのはLv2_3_CalculateTestです。

問題

今度はswitch文を何度も書かなくて良いように修正して見てください。テストクラスで上のように、この値を渡したらこー返ってくる。というのを確認するメソッドがあれば、修正しても問題がないことをすぐに確認できます。

処理の実行するサンプルコードです。
そして、テストクラスです。

追伸

リファクタリング(メソッドで処理を分割しただけ)の後にテストを実行して見ました。

JUnitを使う

上記のように「メソッドを作る」のは良いけど作ったメソッドがちゃんと動くか確認をしたいところです。でも、既存のソースを変更したりするのは「イヤ!」

そのために「JUnit」があります。使い方は下の動画を参照ください。

JUnitの設定

依存関係の追加

JUnit実行サンプル

でわでわ。。。

<<< 前回 次回 >>>

  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜