Back To Main

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ ◆Javaで珈琲ブレイク vol.012 後編◆
┃……………………………………………………………………………………………
┃ [不定期] まぐまぐ ID=0000088576 Melma! ID=m00061296
┃……………………………………………………………………………………………
┃ 今回からご覧になる方は、バックナンバーご活用下さい
┃ http://javacafebreak.tripod.com
┃ http://www.melma.com/mag/96/m00061296/
┃ http://backno.mag2.com/reader/Back?id=0000088576
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

◆目次◆

■Question10の解答
■BankUserInterface.java 【version 1.0621】
■BankAccount.java 【version 1.0621】


前編からの続きです。

■Question10の解答
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
それでは、以上のvol.011と上記の内容をふまえて、Question10のサンプル解答は以下のようになります。一つだけ補足しておきますと、メインメニューの表示はboolean型のprintMenu変数がトグルの役割をしていて、printMenuがtrueの場合だけ(各ロジックからまたメインメニューに戻る場合だけ)、表示するようにしています。それ以外の場合(ユーザーが適切な値を入力しなかった場合)はメインメニューを表示しないようにしています。


■BankUserInterface.java 【version 1.0621】
━━━━━━━━━━━━ ここから ━━━━━━━━━━━━━━━━━━
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

/**
* BankAccountクラスを使用しないコンソールベース・ユーザー・インターフェイス。
* クラス作成の分業を考慮し、BankAccountクラスを使用せずにコンパイル・実行する。
* BankAccountクラス関係の文は記述するが、コメントとしておく。
*
* @author Mr.Hack
* @version 1.0621
* @since 1.0607
*/
public class BankUserInterface {

/**
* コンソールからの文字列がy、Y、n、Nかをチェックする。
*
* @return true ユーザーがnかNを入力した時
* false ユーザーがyかYを入力した時
* @exception IOException コンソールからの入力時例外が発生した時
* @since 1.0609
*/
private static boolean isContinued() throws IOException {
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String answer = buffer.readLine();
if (answer.equals("y") || answer.equals("N")) {
return false;
}
else if (answer.equals("n") || answer.equals("N")){
return true;
}
else {
System.out.print(" 入力が正しくありません。YかNを入力して下さい:");
}
}
}


/**
* コンソールベースのユーザーインターフェイスを実行するメインメソッド。
*
* <PRE>
* 1.メインメニューを表示する。
* 2.ユーザーがメニュー番号を選ぶと、各ロジック(預金・引き出し・残高参照・終了)を実行。
* 3.終了を選んだとき、プログラムが終了する。
*
* また、メニュー番号以外をユーザーが選ぶともう一度適切な入力を促す。
* </PRE>
*
* @param args コマンドライン引数。使用せず。
*/
public static void main(String[] args) {
System.out.println(" _________________________________________");
System.out.println("");
System.out.println(" 仮想バンキングへようこそ ");
System.out.println(" _________________________________________");

//コンソールからの入力ストリームを確立し、バッファーとして蓄えられるようにする
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));

boolean nextTransaction = true;
boolean printMenu = true;

// BankAccountの初期化
BankAccount bankAccountObject = new BankAccount();

// IOExceptionをまとめてキャッチする
try {
// isContinuedがtrueの間、ループする(ユーザーがEnterキーをタイプした場合はループ)
while (nextTransaction) {
if (printMenu) {
System.out.println(" _________________________________________");
System.out.println("");
System.out.println(" [1] 預金をする");
System.out.println(" [2] 引き出しをする");
System.out.println(" [3] 残高を参照する");
System.out.println(" [4] 取引を終了する");
System.out.println(" _________________________________________");
System.out.println("");
System.out.print(" ご希望のお取引番号をお選び下さい : ");
}

char choice = 0;

try {
choice = buffer.readLine().charAt(0);
}
// String#charAt()がスロー
catch (IndexOutOfBoundsException e) {
System.out.print(" 番号が正しくありません。もう一度入力して下さい:");
printMenu = false;
continue;
}
// BufferedReader#readLine()がスロー
catch (IOException e) {
throw e;
}

switch (choice) {
//預金ロジック
case '1':
int balance = (int) bankAccountObject.getBalance();
System.out.println("");
System.out.println(" あなたの現在の残高は" + balance + "円です");
System.out.println("");
System.out.print(" 預金額を入力して下さい: ");
// ユーザーが適切な数値(数値でマイナスではない値)を入力するまでループ
while (true) {
try {
// double型の値を取得。数値でない場合、NumberFormatExceptionをスロー
double depositAmount = Double.parseDouble(buffer.readLine());
bankAccountObject.deposit(depositAmount);
balance = (int) bankAccountObject.getBalance();
System.out.println("");
System.out.println(" " + (int) depositAmount + "円を預金しました");
System.out.println(" あなたの現在の残高は" + balance + "円です");
System.out.println("");
break; // 例外が発生しなければ、whileループを抜ける
}
// Double#parseDouble()がスロー
catch (NumberFormatException e) {
System.out.print(" 入金額が正しくありません。もう一度入力して下さい : ");
}
// BankAccount#deposit()がスロー
catch (IllegalArgumentException e) {
System.out.println("");
System.out.print(e.getMessage() + "もう一度入力して下さい : ");
}
// BufferedReader#readLine()がスロー
catch (IOException e) {
throw e;
}
}
printMenu = true;
break;
//引き出しロジック
case '2':
// do withdraw()
balance = (int) bankAccountObject.getBalance();
System.out.println("");
System.out.println(" あなたの現在の残高は" + balance + "円です");
System.out.println("");
// 考え方は、預金の時と同じ
while (true) {
try {
double withdrawAmount = Double.parseDouble(buffer.readLine());
bankAccountObject.withdraw(withdrawAmount);
balance = (int) bankAccountObject.getBalance();
System.out.println("");
System.out.println(" " + (int) withdrawAmount + "円を引き出しました");
System.out.println(" あなたの現在の残高は" + balance + "円です");
System.out.println("");
break;
}
catch (NumberFormatException e) {
System.out.print(" 引出額が正しくありません。もう一度入力して下さい : ");
}
catch (IllegalArgumentException e) {
System.out.print(" " + e.getMessage() + "。もう一度入力して下さい : ");
}
catch (IOException e) {
throw e;
}
}
printMenu = true;
break;
//残高参照ロジック
case '3':
// do get balance()
balance = (int) bankAccountObject.getBalance();
System.out.println("");
System.out.println(" あなたの現在の残高は" + balance + "円です");
System.out.println("");
printMenu = true;
break;
//終了ロジック
case '4':
System.out.println("");
System.out.print(" お取引を終了しますか?(終了:y/続行:n) : ");
//次の取引を続けるかどうかのフラグを設定
nextTransaction = isContinued();
printMenu = true;
break;
// 1, 2, 3, 4以外のキャラクタ
default :
System.out.print(" 番号が正しくありません。もう一度入力して下さい:");
printMenu = false;
}
}
}
// BufferedReader#readLine()がスロー
catch (IOException e) {
System.out.println("不正な処理を行ったため、プログラムを終了します");
return;
}
finally {
// ストリームを閉じる
try {
buffer.close();
}
catch (IOException e) {
System.out.println("ストリームをクローズ出来ませんでした");
}
}
System.out.println("");
System.out.println(" ご利用ありがとうございました");
}
}
━━━━━━━━━━━━ ここまで ━━━━━━━━━━━━━━━━━━

■BankAccount.java 【version 1.0621】
━━━━━━━━━━━━ ここから ━━━━━━━━━━━━━━━━━━
/**
* バンク預金口座クラス。顧客の口座の出し入れ、残高
* 照会をおこなう(通貨単位:円)。預入引き落とし時、
* Precondition(条件)をチェックし、条件に合わない場合は、
* 例外を発生させる。残高をゼロとするデフォルトのコンストラクタ、
* 預金額をセットできるコンストラクタがある。また、一度に引き出せる上限は
* 2万円、一度に預金できる上限は10万円としてある。
*
* 例:
*
* <PRE>
* BankAccount account = new BankAccount(2000);
* try {
* account.deposit(1000);
* account.withdraw(500);
* }
* catch (Exception e) {
* Sytem.out.println("例外が発生しました:" + e.getMessage());
* }
* double currentBalance = account.getBalance();
* </PRE>
*
* 2000円を口座開設時預金し、1000円を預金後、600円を引き出して、現在の残高400円
* を<CODE>currentBalance</CODE>に保持する。
*
* @version 1.0621
* @since 1.0511
* @author Mr.Hack
* @see BankAccountTest テストクラス:BankAccountTest
*/
public class BankAccount {

/**
* 口座の残高
*/
private double balance;
/**
* 一度に預け入れる上限額
*/
private final double MAX_DEPOSIT_AMOUNT = 100000.0;
/**
* 一度に引き落とせる上限額
*/
private final double MAX_WITHDRAW_AMOUNT = 20000.0;

/**
* 残高をゼロにセットするデフォルトコンストラクタ。初期化時、
* 残高をゼロにセットする。
*
* @author Mr.Hack
*/
public BankAccount() {
this.balance = 0;
}

/**
* <code>amount</code>分を残高としてセットするコンストラクタ。初期化時(新しい口座作成時)、
* 預金額を残高としてセットする。
*
* @param amount 口座に預け入れる金額(預金)
* @exception IllegalArgumentException <code>amount</code>がゼロかマイナスの場合、定められた一度に預金できる
* 金額を上回った場合、例外発生。
*/
public BankAccount(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("入力した金額は0かマイナスです。");
}
if (amount > MAX_DEPOSIT_AMOUNT) {
throw new IllegalArgumentException("一度に入金できる額の上限は" + MAX_DEPOSIT_AMOUNT + "です。");
}
this.balance = amount;
}

/**
* <code>amount</code>分を預金として口座に預ける。<code>amount</code>がゼロかマイナスの時、一度に預ける
* 上限金額を上回った時、例外を発生させる。
*
* @param amount 口座に預け入れる金額(預金)
* @exception IllegalArgumentException <code>amount</code>がゼロかマイナスの場合、定められた一度に預金できる
* 金額を上回った場合、例外発生。
*/
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("入力した金額は0かマイナスです。");
}
if (amount > MAX_DEPOSIT_AMOUNT) {
throw new IllegalArgumentException("一度に入金できる額の上限は" + MAX_DEPOSIT_AMOUNT + "です。");
}
this.balance += amount;
}

/**
* <code>amount</code>分の金額を引き出す。<code>amount</code>がゼロかマイナスの時、引き落とし金額が残高を上回った時、
* あるいは、一度に引き出せる上限金額を上回った時、例外発生。
*
* @param amount 引き出す金額
* @exception IllegalArgumentException <code>amount</code>がゼロかマイナスの場合、引き出し額が残高を上回った場合、
* または、一度に引き出せる金額を上回った場合、例外発生
*/
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("入力した金額は0かマイナスです。");
}
if (balance < amount) {
throw new IllegalArgumentException("残高を超えています。");
}
if (amount > MAX_WITHDRAW_AMOUNT) {
throw new IllegalArgumentException("一度に引き落としできる額の上限は" + MAX_WITHDRAW_AMOUNT + "です。");
}
this.balance -= amount;
}

/**
* 現在の残高を戻り値として返す。
*
* @since 1.0518
* @return balance 口座にある現在の残高
*/
public double getBalance() {
return this.balance;
}


/**
* 現在の残高を戻り値として返す。
*
* @deprecated メソッド名が不適切なため、Version 1.0518から{@link #getBalance}に入れ替わり。
* @see #getBalance
* @return balance 口座にある現在の残高
*/
public double getBlance() {
return this.balance;
}
}
━━━━━━━━━━━━ ここまで ━━━━━━━━━━━━━━━━━━

それでは、宿題にいってみましょう。今回は、仮想バンキングシステムにパスワードを設定します。

Question 11
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1.バンクアカウントのIDとパスワードを設定しなさい。仕様は下記の通り。

(a) BankAccountInterfaceクラスを実行した時、アカウントIDを入力してもらう
(b) 引き続きパスワードを入力してもらう
(c) パスワードが不正なら、もう一度入力してもらう
(d) もし、三回入力しても不正なら、終了する旨を伝え、プログラム終了
(e) もしパスワードが正しければ、メインメニューを表示し銀行取引を開始する

2. アカウントIDの仕様は以下の通り

(a) アカウントIDはアルファベットの大文字か小文字のみ
(b) 最低3文字以上の文字列から構成されなければならない
(例)Mrhack、mRh

3. パスワードの仕様は以下の通り

(a) パスワードはアルファベットの大文字か小文字、または、数字のみ
(b) パスワードは最低アルファベットの大文字、小文字、数字をそれぞれ一字づ つ含む
(c) 最低5文字以上の文字列から構成されなければならない
(例) mRha9

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ヒント

あなたは、Mr.Hackコーポレーションの社員で、仮想バンキングシステムを手がけています。前回はインターフェースプロジェクトチームでユーザーインターフェイスを作り、よりユーザーフレンドリーになるように、メインメニューをもうけました。預金、引き出し、残高参照、そして、プログラム終了とメニューがありとても操作しやすくなりました。今度は、上司に、ある特定の人だけがログインできる用にパスワードを設定しろといわれました。ここで、賢いあなたは、即座に上司に質問します。BankUserInterfaceクラスとBankAcountクラスのどちらにパスワードを設定するロジックをもうければいいか、と。上司は、おまえに任せるとしかいいません。何とも、外資系的ですね。上司は無能なのかあなたのためを思って自分で考えろとっているのか分かりませんが、とにかく自分で考えなければなりません。
そういえば、ユーザーインターフェイスはユーザーとのやり取りに専念するというコンセプトで作られたクラスだということを思い出しました。計算したり、正しい値かどうかをチェックするのは、ロジック部分でやらないといけないことも。そうなると、BankAcountクラスに、新たに、accountIdとpasswordというインスタンスfieldをもうけて、そこで、パスワードをチェックした方が良さそうです・・・。


今回は、パスワードを仮想バンキングシステムに設定します。あるIDに適切なパスワードが入力された時だけ、バンクシステムにログインできるようにします。

アカウントIDとパスワードはBankAcountクラスにハードコード(埋め込み)してはいけません。インスタンスを生成してから、setPassword()のようなメソッドで設定しましょう。つまり、このような形をとると、UserInterface.java上でデフォルトのIDとパスワードを設定して、それをユーザーからの入力と比較するようになるでしょう。

さて、今回も長くなりました。それでは、またあいましょう。

Mr.Hack

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆Javaで珈琲ブレイク◆
───────────────────────────────────
皆様からの激励・批判のメールをお待ちしております。
【発行者】 Mr.Hack - javacafebreak@hotmail.com
【掲示板】 https://javacafebreak.tripod.com/cafe_entrance.html
※質問は上記の掲示板からどうぞ。
【サイト】 http://javacafebreak.tripod.com
【発行数】 まぐまぐ[943] Melma[143]
【解除】http://javacafebreak.tripod.com
※解除は上記のサイトからいつでもできます。
────────────────────────────────────
(c)2002 MR.HACK ALL RIGHTS RESERVED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

【解答】
false : newキーワードでメモリー領域を新たに確保します。equals()メソッドは==と同じ意味ですので、参照場所が違えば、同じ内容の配列でもfalseを返します。配列の内容の一致の比較には、java.util.Arrays#equals()メソッドをつかって比較します。ちなみに、

int[] intArray = new int[] {1, 2, 3};

は、初期化と代入と同時に行い、

int[] intArray = new int[3];
intArray[0] = 1;
intArray[1] = 2;
intArray[2] = 3;

と同じ意味です。

© 2002 MR.HACK ALL RIGHTS RESERVED