Back To Main

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


◆目次◆

■Authentication(認証)とAuthorization(認可)
■データベースを視野に入れた設計(マルチユーザー)
■今回の設計(シングルユーザー)
■AccountIdとpasswordをBankAccountクラスに入れた理由
■Question 12


皆さん、こんにちは。

Mr.Hackです。今週はメルマガの発行が遅れてしまいました。メルマガを楽しみにしていた方、ごめんなさい。といいますのも、我が愛機Thinkpad T20のハードディスクが急遽逝ってしまったのです。嗚呼。カッチン、カッチン、音がするので、これはおかしいな・・・と思ったのですが(その時バックアップをとっておけば・・・)、スキャンディスクと、デフラグすれば、何とかなるだ・ろ・う・・・と思ったのが、運の尽き。今回は、唖然です。ホント大切なデータがなくなって初めて、バックアップの大切さを痛感しますね・・・。皆さんもぜひ、OSごとのバックアップまでいかなくても、大切なデータ、Email、お気に入りのバックアップはとっておいたほうがいいですよ。

そういうわけで、今週はスロースタートです。

前回は、.equals()と==の違いと、サブメニューを設定したユーザーインターフェイスを見ました。そして、前回の宿題では、仮想銀行システムにパスワードを設定するというものでした。

■Authentication(認証)とAuthorization(認可)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

システムにログインするときは、一般的に、Authentication(認証)とAuthorization(認可)があります。認証と認可はどこが違うのかといいますと、認証は、『誰(Who)がアクセスしてきたのか』をチェックすることに対し、認可は『どのような権限(What, how)を与えるか』をチェックします。たとえば、あなたが仮想銀行システムにログインするときにまずIDとパスワードをチェックされるのが認証です。MrHackというIDがアカウントリストに存在して、そのパスワードが適切なものであれば、認証をパスできます。次にチェックされるのが、認可です。認証をパスしたあなたに、どれだけの権限を与えるかが決められます。あなたが一般のカスタマーということになれば、自分の口座の預金・引き出し・残高参照といった、機能を利用利用することが許可(認可)されます。しかしながら、権限外のすべての顧客情報(アカウントリスト)を見たり、ほかの人のアカウントをリセットしたりすることは、できません。

今回は、認証の後にチェックする認可は、おいておきまして、認証をチェックするプログラムを考えていきましょう。

■データベースを視野に入れた設計(マルチユーザー)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

本来ですと、仮想バンキングにログインするのは、あなただけではありませんね。顧客情報の閲覧権限を持った銀行関係者も含まれているかもしれません。その場合、あなたが入力したIDが、『どこか』の顧客リスト(アカウントIDリスト)の中に存在し、それにユーザーが入力したIDを照らし合わせて、IDが一致すれば(存在すれば)、パスワード入力を求め、パスワードが適切なら、ログインするという形になります。

┌──────────────────────────────────┐
ユーザー <------> 仮想バンクプログラム <-----> データベース(どこか)
└──────────────────────────────────┘

┌──────────────────────────────────┐
1.ユーザーが仮想バンクプログラムにIDとPasswordを送る
2.仮想バンクプログラムは『どこかの』データベースにアクセスして
ID(Passwordも)を問い合わせる
3.データベースにIDが存在し、Passwordが適切であれば、バンクプロ
グラムはユーザーにログインさせる。
└──────────────────────────────────┘

2.で、『どこか』に注目です。この『どこか』を表す代表的な場所が、データーベースの中です。大きなシステムになりますと、データベース(オラクルのOracle 9i、マイクロソフトのMS SQL 2000、やその他フリーのMySQLなどのソフトウェアがデーターを管理)がありまして、そこにアカウント情報が保持されています。しかしながら、いつもこういったデータベースソフトが顧客情報を管理しているとは限りません、テキストファイルやXMLのような簡易的なものもデーターベースとして機能しますね。はたまた、システムがずーと起動しているのであれば、RAM(Random Access Memory、メモリー)に保持されているかもしれません。今現在では、その顧客情報が、データベースであろうが、ファイル上であろうが、メモリー上であろうが、関係ありません(最終的にはこのメルマガで、MS SQL2000かMy SQLでデータベースアクセスできるようになりましょう)。

ユーザーがログインする前に、『どこか』にデータが存在していればいいのです。今回は簡単にするため、マルチユーザーを考えませんので、任意のシングルユーザーを扱えればいいとします。つまり、ユーザーから入力されたIDがどこかに存在し、それをクエリー(Query、そのIDが存在しているかどうかを問い合わせ)し、存在していれば、その情報をUserInterfaceクラスで得れるように、あらかじめ、UserInterfaceクラスでそのシングルユーザーのオブジェクトを作成しておきます。

データベース等を使う場合ですと、データベースに直接問い合わせたり、データベースに問い合わせたりするクラスに"MrHack"をキーワードとしてクエリーします。直接データベースに問い合わせる場合は、UserInterfaceクラスにそのロジックを書かないといけないので、そのロジックを担当してくれるクラスを用意する方が役割を分担できます。たとえば、DataManagementクラスがその役割を担当し、その中の一つのメソッドget(int id)が渡されたidを元にデータベースに問い合わせたりして、得た情報をBankAccountクラスのオブジェクトにそれぞれ格納して、そのオブジェクトの参照先を返します。

┌──────────────────────────────────┐

ユーザーがMrHackとMrha9を入力

BankUserInterface 他のDB(クラス)
┏━━━━━━━━━━━━━━━━┓ 問い合わせ ┏━━━━━━━━┓
┃MrHackが存在するかどうか -----------> MrHackが存在する
┃外部のデータベース(クラスに)に のでその情報を
┃問い合わせ <---------- 送り返す
┗━━━━━━━━━━━━━━━━┛ 情報 ┗━━━━━━━━┛

※上記の『情報』をクライアント(BankUserInterface)が得るときは、
BankAccountの account参照変数は、下記のような形になります。

DataManagement aContainerObject = new DataManagement();
BankAccount account = aContainerObject.get("MrHack");

外部のクラスDataManagementはデータベースとのやり取りをしてくれるので、
"MrHack"をキーワードとして渡せば、aContainerObjectは該当する情報を
BanAccountオブジェクトに詰めて、その参照先を返却してくれる。

└──────────────────────────────────┘

何を言っているか、さっぱり分かりませんか?
今の段階では、分からなくていいのです。3ヶ月後でも、半年後でも、このメルマがを読み直した時にわかれば、それでいいと思います。ここでは、いずれ、データを管理するときは、BankUserInterfaceクラスで扱うのではなくどこかほかのクラス(データベース)であつかうのだな、ということが分かって貰えれば、今はそれで十分です。

■今回の設計(シングルユーザー)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

今回は、複雑な構造を全く抜きにしていきます。外部のクラス(データベース)や、問い合わせ等のプロセスは省略し、情報がBankUserInterfaceクラスに戻ってきたところからスタートします。

┌──────────────────────────────────┐

ユーザーがMrHackとMrha9を入力

BankUserInterface
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

┏━━━━━━━━━━━━━━━━┓ 問い合わせ ┏━━━━━━━━┓
┃MrHackが存在するかどうか -----------> MrHackが存在する
┃newで確保された領域に問い合わせ のでその情報を
┃ <---------- 送り返す
┗━━━━━━━━━━━━━━━━┛ 情報 ┗━━━━━━━━┛

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

└──────────────────────────────────┘

上記の『情報』を返す所だけに注目しBankAccountオブジェクトを参照して いるaccountは、あたかも外部のクラスがBankAccountクラスのオブジェクトに情報を詰めて、その参照先を教えてくれたかのように、newで確保された領域上の情報(idは"MrHak"で、passwordは"Mrha9"で、残高は0)を参照します。

┌──────────────────────────────────┐
BankAccount account = new BankAccount("MrHack", "Mrha9", 0);
└──────────────────────────────────┘

もちろん、newで確保された領域に、"MrHack"、"Mrha9"、0を保持したBankAccountオブジェクトが存在するのは、当たり前ですね。newでメモリー領域を確保したのですから。しかし、将来は、このnewで確保した参照先ではなく、外部がデータベース(やファイル)を操作して得た結果をBankAccountオブジェクトに格納して、その参照先をaccountが参照するようになります。

Javaで書きますと、下記のようになります。


BankUserInterfaceクラスの一部
┌──────────────────────────────────┐

String myAccountId = // コンソールから得る
String myPassword = //コンソールから得る

try {

/**
* 本来、BankAccount acount = new ... の代わりに
* accountは見つかったオブジェクト(参照先)を指します。
* DataManagement aContainerObject = new DataManagement();
* BankAccount account = aContainerObject.get(myAccountId);
* if (myDabaBase == null) {
* //データベース上にIDが存在しない
* }
*/
BankAccount account = new BankAccount("MrHack", "Mrha9");


// もし、accountオブジェクトのパスワードがmyPpasswordと同じならtrue
if (account.hasPassword(myPassword)) {
// ログイン成功
}
else {
// ログイン失敗。もう一度ユーザーにIDとPasswordを入力してもらう
}
}
catch (...)

└──────────────────────────────────┘


BankAccountクラスの一部
┌──────────────────────────────────┐

class BankAcount {

String accountId;
String password;
double balance;

BankAccount(String accountId, String password, double balance) {
..
}
..

hasPassword(String aPassword) {
//もしthis.passwordとaPasswordが一致したなら、trueを返す。
}

└──────────────────────────────────┘

一方、今回のBankAccountクラスは、残高を表すbanlanceフィールドに付け加えて、新たにaccountIdとpasswordをインスタンフィールドに持ちます。

当分の間は、『どこかの』データベース(データを格納するスペース)に有効なIDがすでに存在すると仮定しますので、

┌──────────────────────────────────┐
BankAccount account = new BankAccount("MrHack", "Mrha9", 0);
└──────────────────────────────────┘

でいいですね。これは、"MrHack"をアカウントIDとするBankAccountクラスのオブジェクトが存在(メモリー上に存在)し、そのオブジェクトの参照先をaccountが、参照しているということを意味しましたね。そして、accountオブジェクトにhasPassword(myPassword)のようなメソッドを適用して、このmyPasswordが、すでにaccountが参照しているオブジェクトに格納されているインスタンスフィールドのpasswordと一致するか(aPasswordとpasswordが一致するか)チェックします。確認ですが、UserInterfaceクラスのmyPasswordとBankAccountのaPasswordは、ユーザーが入力したパスワードです。一方で、newで初期化したときの、accountが参照しているインスタンスはBankAccountのpasswordに"Mrha9"を保持することになりますね。

ここでパスワードが一致すれば、『どこか』データベース上にある(今回は、データベースの代わりにnew BankAccount()確保された、メモリー上にある)パスワードと一致することになりますから、ログイン成功です。

将来的には、/** */でコメントしたように、BankAccountクラスの参照変数であるaccountは、accountIdをキーワードとして検索し、該当したインスタンス(参照先)を参照します。別の言い方をすれば、データを管理するクラスのインスタンスのメソッド(たとえばBankAccountクラスのインスタンスを得るgetメソッド)に、ユーザーからのAccountIdを渡して、データベースを検索して、見つかったら、それをBankAccountオブジェクトにそれぞれ必要な情報(AccountId, Password, balance等)をいれて、そのオブジェクト(参照先)を返します。

そのため、ユーザーアカウントIDは"MrHack"だけでなく、利用するユーザーが入力したどんなIDも、キーワードとして検索して、見つかれば、accountがその見つかったオブジェクトを参照できます。


■AccountIdフィールドとpasswordフィールドをBankAccountクラスに入れた理由
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

いままで、仮想バンキングシステムを構成しているクラスは、BankUserInterfaceクラスと、BankAccountクラスの二つですね。先ほどは、AccountIdとpasswordという変数を、役割分担という観点から、BankAccountクラスに入れると述べました。ユーザーインターフェイス部分を担うBankUserInterfaceクラスよりも、残高を計算するロジック部分のBankAccountクラスの方が適切だと。しかしながら、もっと積極的な理由があります。それは、オブジェクト指向の考えです。

皆さん、オブジェクトとは何でしたっけ?思い出してください。『たいやき』でしたね。クラスという鉄板型(設計図)を元にして作られた、たいやき(オブジェクト)です。オブジェクト指向プログラミングのオブジェクトは、人間の実生活を母体にしていますので、実際にある対象物(物体、考え)をそのまま投影しています。たい焼きを構成している要素(メンバー、フィールド)に、あんこ、目、色、があるように、Java上に投影されたTaiyakiというクラスにも、

┌──────────────────────────────────┐

class Taiyaki {
double anko; // あんこの量
int eye; // 目の数
string color; // たい焼きの色
}

└──────────────────────────────────┘

というようなフィールドを作ることができます。このクラスである設計図から、実際のオブジェクトであるたい焼きが作られるのでしたね。

それでは、BankAccountクラスはどうでしょう。もし、BankAccountクラスを、実社会にある預金口座(考え)、または、通帳(物体)が投影されたと考えると、どのようになるでしょう?預金口座には、口座番号があり、残高または、氏名などの個人情報がありますね。
パスワードは通帳にはないかもしれませんが、預金口座という概念で考えると、パスワードを入れてもおかしくはなさそうですね。なぜなら、AccountIdとpasswordは密接に関わっているからです。実際の物体の通帳にはパスワードはないですが、概念としての対象物としては、パスワードフィールを口座に入れてもいいと思います。

┌──────────────────────────────────┐

class BankAccount {
string AccountId;
string password;
string balance;
string personName;
string address;
...
}

└──────────────────────────────────┘

もちろんもっと口座というのを狭義にとらえて、口座とは、あるアカウントに対する残高だけを意味する(概念)として、addressなどは、別個の概念を意味するとするものと考えることもできますね。そうした場合は、新たに、address関係のphone, postalCodeなどのフィールドを格納する、Addressクラスをつくってもいいですね。

さて、BankAccountクラスにAccountIdとpasswordフィールドを入れることを決めました。しかしながら、口座を作るとき(BankAccountオブジェクトを作るとき)、IDとPasswordの仕様はどうしましょう?IDは100桁からなっていてもいいでしょうか?パスワードは、すべて同じだったり、1桁だけでもいいでしょうか?IDが100桁もあったら、IDを通帳番号として使うには、使いずらそうですね。というのも2桁あれば100人分のIDを区別できますから(0から99までの数)、100桁というIDは、超がつくくらい、余裕で日本人口をカバーできてしまいます。そうすると100桁もあっても、そのほとんどの桁が意味をなさなくなってしまいますね。パスワードにおいては、1桁というパスワードを許せば、セキュリティー上大変な問題になります。なぜなら、いったんIDさえ分かってしまえば、1桁のため、10通り(0から9までの数字)で有効なパスワードを見つけることができてしまいます。

つまり、IDやPasswordには、何でも指定できるのではなく、ある規則を設定してあげないといけませんね。それが、今回のIDは3桁以上の大文字と小文字からなり、、Passwordは5桁以上の大文字、小文字、数字からなり、それぞれ最低一つ入れること、を設定した理由です。実際にどのように、Javaで書いていくかは来週のお楽しみです。

さて今日はこのくらいにして、宿題にいってみましょう。今週は、来週の予習をかねた宿題です。

■Question 12
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
以下の命題は正しいか否か答えよ。

1.

A:Mr.Hackは、まぐまぐとmelma!の両方のメールマガジンを購読している
訳ではない。
B:Mr.Hackは、まぐまぐを購読していないかmelma!を購読していないかの
どちらかである。

命題:AとBは同じことを言っている。

2.

C:Mr.Hackは、まぐまぐかmelma!のメールマガジンを購読している訳では
ない。
D:Mr.Hackは、まぐまぐを購読していないし、melma!も購読していない。

命題:CとDは同じことを言っている。

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

ちなみに、これは、コンピュータサイエンス学科の学生が最初の一年目に習わないといけないDiscrete Mathのトピックの一部です。さあ、アメリカの学生に負けていられません。数学と聞くと頭の痛い方もたくさんいらっしゃるでしょうが、がんばっていきましょう。

今回は、一つのアカウントが存在すると仮定したり、オブジェクト指向の考えを見ましたので、難しかったかと思います。疑問に思った点がありましたら、掲示板でどしどし質問してください。それでは、また会いましょう。

Mr.Hack

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

© 2002 MR.HACK ALL RIGHTS RESERVED