Java はじめて17 〜設計後の部品を実装する1〜

イントロダクション

今までに、クラスを作成して、使用するということを学習しました。クラスを作成して使用するというのは、単純に書くクラスに役割を与えてその役割ごとにメインメソッドから必要なクラスを呼び出しプログラムを動かすということです。

具体的には、JavaAPIですでに実装されていますが、文字列を扱うのであれば、Stringクラスがその役割を果たします。
また、独自に作成したクラスがその役割を果たすのであれば、そのクラスを呼び出し、実行してやればそれで目的は果たせるというわけです。

実例としてじゃんけんゲームを考えてみます。

クラスの作り方

<その1>

<その2>

じゃんけんゲームの場合

じゃんけんゲームと言っても、コンソールアプリを実装(作成)するとします。
必要な処理としては、以下のようになります。

  1. じゃんけんの手を入力する。(プレーヤーの手を入力)
  2. CPUの手を取得する
  3. プレーヤーとCPUの勝敗判定を行う
  4. 結果を表示する

※下の動画の場合は、じゃんけんの手を示すヘルプを下のように表示しています。

**************
グー  *   0 *
チョキ*   1 *
パー  *   2 *
**************

役割分担

ここで、役割分担のことを考えてみます。※あくまでも、筆者の考えたものです
上のような処理を行うのであれば、役割として次のような分担を行うことができます。

  • プログラムを実行する役割(メインメソッドのあるクラス)
  • CPUの手を取得したり、勝敗判定を行う役割(Utilityを提供するクラス)

そうすると、次のように2つのクラスを作成することができます。

  • JankenMain: じゃんけんゲームを起動するクラス(メインメソッドのあるクラス)
  • JankenUtil: じゃんけんゲームのユーティリティー(細かい機能)を提供するクラス

実装例

メインメソッドのみの実装でいくと下のような実装イメージです。

public static void main(String[] args) {
    // ユーティリティークラス
    JankenUtil util = new JankenUtil();
    // 標準入力(コンソールからの入力)
    Scanner scan = new Scanner(System.in);
    // ユーザー入力
    String input = scan.nextLine();
    // CPUの手
    String cpuTe = util.getCpuTe();

    if (util.judge(input, cpuTe)) {
        System.out.println("WIN");
    } else {
        System.out.println("LOOSE");
    }
}

フローチャートにすると下のようになります。プログラム的なプロセスと人間的なプロセスがあります。
プログラム的なプロセスに関しては、学習すればすぐにわかることなのでよいのですが、
人間的なプロセスに関しては、ほぼ無限大にパターンがあるので、頭をひねる必要があります。

設計後の部品

今回は、役割分担を行なった後にクラス(部品)をどのように組み合わせてアプリを作成するか?について記載したいと思います。
作成するのは、子供銀行とでも言いましょうか?お金の入金、引き出しができるなんちゃってATMアプリを作成したいと思います。
【補足】
アプリの規模がとても小さく、処理内容も少ないのでちゃんとした「設計書」の類は作成しません。

<ユースケース>
【前提】
コンソール画面のATMとします。
ユーザー認証は行いません。
単純に金額を入金、引き出しができるものを作ります。

【仕様】
アプリを起動してコンソールから「引き出す」「入金」を選択する
それぞれの処理に対して「預金額」から足し算、引き算を行いその結果を表示する

<クラス図>

<部品候補>

  1. メインメソッドを持ち、入力の受付も行うクラス
  2. 入金、引き出しを行う計算処理クラス

部品を作る

<部品候補>からクラスを2つ作成します。クラス名はアルファベットで作成する必要がある(全角の文字でも作成できますが、なんとなく嫌なので。。。)

  1. MainBankクラス(メインメソッドを持つ)
  2. Calcurationクラス(引出し、入金を管理する)

上のように名前をつけます。このように「役割分担」をしてやれば、いざ修正するときにどちらかのクラスの一部を修正してやれば、デグレート(修正したらおかしな事になる)する事もないように作ることができます。

ここのポイントとしては、書く処理の依存度をなるべく低くしてやることです。依存度が高いと下のようなコードになります。

public static void main(String[] args) {
   MainBank main = new MainBank();
   Scanner input = new Scanner(System.in);
   String inStr = input.nextLine();
   if ("in".equals(inStr)) {
       // 入金処理を行う
   }
      ・
      ・
      ・
}

入力を受けたあとに入金処理を同じクラスの中に書き始めると、結局のところは全部の処理をMainBankクラスに書くことになります。
ソースを読む時は全部読まないといけないし、修正するときも、あちこち直さなくてはいけません。。。
残業パラダイス必至のコードです。平和のためにこのような作成方法はやめましょう。。。

依存度を下げるために

クラスを複数作成し、役割分担をしてやります。
今回のコンソールアプリを作るのには以下のような2つの処理が必要と筆者は考えました。

自分で考えて「このように役割分担をする」という風に考える練習をすることが大切です。上記は筆者が考えたものですので、参考程度にしてください。

  1. コーダー銀行の受付(入金、引出し)を行う(判定)する処理
  2. 入金処理、引出し処理のそれぞれを行う。

ポイント

  1. 受付部分は共通なので、MainBankで行う
  2. 入金処理、引出し処理は独立させることができるので分割する

そんなわけで

  1. MainBankクラス
  2. Calcurationクラス

上記のクラスを作成することにしました。

MainBankクラス

アプリケーションの起動とコーダー銀行の受付処理を行います。
処理の詳細に関しては、以下の通りになります。

  1. コーダー銀行の受付文言をコンソールに表示
  2. デフォルトの預金金額¥1000-を表示する
  3. 入金(in)、引出し(out)の判定を行い、処理終了する時は「bye」の入力で処理を終了する
  4. そのほかの入力はエラーメッセージを表示してサイド入力を促す表示を行う

Calcurationクラス

入金、引出し処理を担当するクラスです。このクラスには預金額を管理するためのフィールド変数が必要になります。
そして、入金処理、引出し処理では以下のような処理が必要になります。

  1. 入金・引出し処理を行う旨を表示する。
  2. それぞれの処理を行った後の預金額を表示する。
  3. 受付〜各処理への状態が変化していることをプログラム的に区別する必要がある。

上の3番に関して、「プログラム的に〜」と記載している部分は「状態」を管理することにより処理クラスを変更、管理しやすいのです。この設計手法に関してはGOFのデザインパターンなどを読んでみるととても参考になります。
良いデザイン(設計)をできるようになると、色々と楽ができます。そして、仲間内で「あーだこーだ」と議論するのも楽しいと思います。

でわでわ。。。

<<< 前回 次回 >>>

<Java関連の動画リスト>



投稿者:

takunoji

音響、イベント会場設営業界からIT業界へ転身。現在はJava屋としてサラリーマンをやっている。自称ガテン系プログラマー(笑) Javaプログラミングを布教したい、ラスパイとJavaの相性が良いことに気が付く。 Spring framework, Struts, Seaser, Hibernate, Playframework, JavaEE6, JavaEE7などの現場経験あり。 SQL, VBA, PL/SQL, コマンドプロント, Shellなどもやります。

コメントを残す