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_6_Javaの基本(プロパティファイルを読む)ゲームループ付き〜

イントロダクション

前回までに以下のような事をやってきました。

ゲームループ=無限ループ内でゲームのように「入力→XXXな処理」を繰り返すことができる形でプログラムを作る形で
ハローワールドや四則演算を行う形で再再度プログラムの学習を行うというものです。

  1. Java Mid Basic 〜Lv1Javaの基本を理解する(ゲームループ付き)〜
  2. Java Mid Basic 〜Lv2_Javaの基本(コードの書き方)ゲームループ付き〜
  3. Java Mid Basic 〜Lv2_1_Javaの基本(四則計算)ゲームループ付き〜
  4. [Java Mid Basic 〜Lv2_2_Javaの基本(リファクタリング)ゲームループ付き〜]()
  5. Java Mid Basic 〜Lv2_3_Javaの基本(リファクタリング実践)ゲームループ付き〜
  6. Java Mid Basic 〜Lv2_4_Javaの基本(Dirコマンドを作る)ゲームループ付き〜
  7. Java Mid Basic 〜Lv2_5_Javaの基本(コマンド履歴を作る)ゲームループ付き〜

<各項目の概要と目的>

  1. ハローワールドを行い、コードを書いて動かす:これによりメインメソッドの存在とコンソールへの出力方法を知ります。
  2. 動かしてみたので、その内容を理解します。
  3. とりあえずのレベルで内容を理解したので、実際にコードを書いて動かします。自分でコードを考えて実装→起動を行うとプログラミングの面白みも見えてくるかと思います。
  4. 書いたコードをレベルアップします。今後この「リファクタリング」はどのレベルになってもついてきます。レベルが高ければ高いほど難易度も上がっていきます。
  5. 理論的なことをやったのであとは実践です。これも「どのように整理してやれば「拡張性、保守性、パフォーマンス」の面で良いものができるか考えるのである意味「永遠のテーマ」です。(笑)
  6. 今度は、入力した文字によっていろんな処理を実装できるようにプログラムを改造していきます。サンプルとして「Dirコマンド」のようなカレントディレクトリ(現在いるフォルダ)のファイル一覧を取得する処理を実装しました。
  7. javaに初めからついているクラス「List」を使用してコマンド履歴を出力するプログラムを作成します。ここではjava.utilパッケージについて記載しています、今後はこのパッケージにあるクラスを何個か使用します。

ハローワールド

変数の扱い方

四則演算

クラスについて

プロパティファイル

今回は、今まで行ってきたことを拡張するために使用できる「プロパティファイル」に関して学習したいと思います。
プロパティファイルは何かしらの値をテキストファイルに定義しておき、これをJavaプログラムの実行時に読み込んでから実行する形で使用します。

プロパティファイルの使用例

例えば、勇者と戦士がプログラムの中に登場するとしましょう。このキャラクターのステータス(状態)はプログラムを実行するたびに変化していきます。
途中でプログラムを終了してそれから、再開したい時、終了したときの情報を保存しておきたいでしょう。

我々がよく目にするのは、「ゲームのセーブ機能」です。保存した情報を読み込んでからプログラムを実行するのでちょうどプロパティファイルの使用方法と似ています。実際には各制作会社で独自のロジックを使用しているかもしれません。

具体的に。。。

例えば下のようなプロパティファイルがあったとしましょう。ファイルの中身は「キー=値」のように定義します。
下のものは「hp」がキーで「10」が値です。同様に下の表のようになっています。

キー
hp 10
mp 3
ATK 10
DIF 3

<プロパティファイル>

hp=10
mp=3
AKT=10
DIF=3

これをプログラムで読み込むときには下のようなコードで取得することができます。

Properties prop = new Properties();
String path = "/path/to/dir/sample.properties";
InputStream s = new FileInputStream(path);
prop.load(s);
// 「hp」の取得
String value = prop.getProperty("hp");

プロパティファイルを使用するのもjava.utilパッケージにあるクラスを使用します。「プロパティファイル」とは拡張子がproperiesのファイルを指します。「*.properties」
このファイルはキーと値がセットになっています。具体的には下のような感じです。

ads="グーグルアドセンス"
win="ウィンドウズ"
mac="マッキントッシュ"

このようなファイルを作成し、これを読み込んでプログラム中で使用します。
今回の使い方は「コマンドをキーにして値を表示する」というような形でやろうと思います。

IN: ads
OUT: グーグルアドセンス

設計

前提として、前回までのコードに追加修正を加える形で実装します。

  1. コンストラクタでプロパティファイルを読み込みます。
  2. プロパティファイルにあるキー(コマンド)を入力した時はプロパティファイルの値を表示
  3. それ以外のコマンド(キー)は前回までと同じ動き

つまり

プロパティフィルにあるキーが存在すればそれを出力して、それ以外はいままで通りということです。

実装

今回のポイントはプロパティファイルを読み込むところです。
プログラムが動き始めたら即ファイルを読み込んでおきたいので、コンストラクタで読み込むように実装します。
そして、Propertiesクラスはフィールド変数として使用します。
ちなみにファイルまでのパスを指定しますが、ビルドパスを基準にパスを記載するのでちょいと注意が必要です。
resources/test.properties>resources/test.propertiesを読み込みたい場合は「ビルドパスがresourcesにつながっていることを確認します。

そしてコードは下のような感じです。

/** コンストラクタ */
public Lv2_6_Properties() {
    commandList = new ArrayList&l5;String>();
    prop = new Properties();
    try {
        // resources/
        prop.load(getClass().getResourceAsStream("test.properties"));
    } catch (IOException e) {
        e.printStackTrace();
        // エラーコード-1をセットしてプログラム終了
        System.exit(-1);
    }
    }

ポイントの部分はprop.load(getClass().getResourceAsStream("test.properties"));の部分です、ここではPropertiesクラスのload()メソッドを使用してInputStreamからプロパティファイルを読み込みます。
getClass().getResourceAsStream("パス")で対象ファイルのInputStreamを取得します。
具体的にはビルドパスにつながっているディレクトリがルート「/」になるので「/test.properties」が対象のパスになりますが、環境によりルートが違う場合があります。
作成したコードはこちらです。
そして、実行結果です。

<<< 前回 次回 >>>

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/) >>>