第2回 クラスの詳細(4月19日)
今日の課題
■ クラスとインスタンス
オブジェクトは、クラスとインスタンスの2種類がある。クラスは概念であり、インスタンスは具体物である。
たとえば、「クレジットカード」という概念には「カード会社名、カード名義、カード番号、有効期限、…」などの情報が含まれている。一方、自分が持っているクレジットカードは、その具体物であり、これらの情報が具体的に決まっている。
Smalltalk で「クレジットカード」のクラスを定義するとき次の変数が必要であろう(3つに省略している)。
- company: カード会社名
- owner: カード名義
- number: カード番号
Smalltalk で「クレジットカード」のインスタンスを作るとき、上記の変数にデータを入れておく必要がある。
- company = JCB
- owner = 徳久雅人
- number = 12345678
クレジットカードクラスを作ってみよう
先週の続きの状態ならば、System Browser のカテゴリペインの最下行には「MyObject」というカテゴリが存在している。「MyObject」を左クリックをすると、クラスを定義するための雛形が「編集のペイン」に表示される。
以下の手順で、クラスを定義する。
- System Browser を開ける。
- 「カテゴリ」のペインで「MyObject」を選択する。
- 「編集」のペインで、「#NameOfSubclass」を「#CreditCard」に変更する。
- 「編集」のペインで、「instanceVariableNames: ''」を「instanceVariableNames: 'company owner number'」に変更する。
- コントロールを押しながら左クリックを押し、「了解(s)」を選択する。
こうして、インスタンス変数として、company, owner, number が定義されるが、インスタンス変数を書き換えるためのメソッド(アクセサと言う)が必要である。メソッドは次の手順で定義する。
- System Browser の「クラス」のペインにおいて、CreditCard を選択する。
- 「プロトコル」のペインで、「-- all --」を選択する。
- 「編集」のペインを全て削除する(通常、緑色でフラッシュしているので、デリートキーなどで一発消去ができる)。
- 「メソッド名: 引数名」で定義する。下記の例で、「setCompany:」がメソッド名、「n」が引数名であり、次の行が代入のステートメントで、インスタンス変数 company に n を代入している。
setCompany: n
company := n
- コントロールを押しながら左クリックを押し、「了解(s)」を選択する。
自分のクレジットカード(インスタンス)を作ってみよう
Workspace 上で以下を実行する。
- a := CreditCard new ※ 直後に alt キーを押しながら d を押すと実行できる
- a setCompany: 'JCB'
- a inspect
インスペクトのウインドウが表示され、その中にインスタンス変数の状態が表示されている。
■ 練習
カード名義、カード番号を代入するメソッド setOwner: と setNumber: を作成しよう。
Workspace 上で以下を実行し、インスペクトウインドウの表示の変化を見てみよう。
- a setOwner: 'Tokuhisa Masato'
- a setNumber: '12345678'
(発展)
3つの情報は基本的な情報なので、同時に登録したい。3引数のメソッドを定義しよう。
entry: c owner: o number: n
company := c.
owner := o.
number := n
複数のステートメントは、ピリオドで区切りながら入力する。
(実行例)
x := CreditCard new
x entry: 'AMEX' owner: 'Tokuhisa Masato' number: '43215678'
■ クラスの継承
最近のクレジットカードには、電子マネー(Edy)の機能や、ショッピングポイントの機能が付いている。これらのカードは、「クレジットカード」+αというように、概念的に少し違いがある。
Edy機能付きのクレジットカードのクラスを定義するにはどうすれば良いか?
- インスタンス変数として、カード会社、カード名義、カード番号、エディ金額を持つクラスを定義する。そして、カード会社、カード名義、カード番号を登録するメソッドを定義した上、エディ金額の参照と変更のためのメソッドを定義する。
- クレジットカードクラスの下位クラスとして、エディ金額のインスタンス変数を持つクラスを定義する。そして、エディ金額の参照と変更のためのメソッドを定義する。
どちらが簡単そうに見えますか?
クラスの継承をしてみよう
まず、下位クラス(サブクラス)を定義する。
- System Browser を開ける。
- 「カテゴリ」のペインで「MyObject」を選択する。
- 「編集」のペインで、「Object subclass: #NameOfSubclass」を「CreditCard subclass: #EdyCreditCard」に変更する。
- 「編集」のペインで、インスタンス変数の '' を 'edy'に変更する。
- 「了解(s)」をする。
次に、エディ金額の参照と変更のためのメソッドを定義する。
- 「クラス」のペインで、「EdyCreditCard」を選択する。
- 「プロトコル」のペインで、「-- all --」を選択する。
- 「編集」のペインで全て削除する。
- 「編集」のペインで、メソッド名を「readEdy」とし、ステートメントを「^edy」とする。「^」は C言語の return と同じである。「了解(s)」をすると「↑」になる。
- 同様に、メソッド名を「writeEdy:」とし、引数を「n」とする。ステートメントを「edy := n」とする。「了解(s)」をする。
試しに動かしてみよう
Workspace で、以下を実行しよう。
- a := EdyCreditCard new
- a inspect
- a entry: 'VISA' owner: 'Masato Tokuhisa' number: '87654321'
- a writeEdy: 10000
- Transcript show: a readEdy
■ 小レポート
身の回りの物を Smalltalk のクラスとサブクラスで定義しよう。
- ヒント:
- 基本機能のものを上位のクラスに、発展機能のものを下位クラスで定義するとよいでしょう。たとえば、「電話」をクラスにすると、インスタンス変数は電話番号になり、「留守番機能付き電話」をサブクラスにすると、追加するインスタンス変数は「留守番メッセージ」と「受信メッセージ(メモリーは簡単に1件のみとしよう)」として、それらの読み書きのメソッドを追加する。
- 提出の要領:
- プログラムと実行の様子が分かるように画面に表示させる(プログラムは、上位クラス、下位クラス、作成した全メソッド)。
- 画面のハードコピーをプリンタで印刷する。
- プログラムにコメントを記入する。
継承の様子がわかる実行の様子を、特に強調して説明をする。
来週、演習の開始時に集めます。
画面の取り込みは、Linux の画面の一番上のメニューバーの「アクション」を選択し、「スクリーンショット」を選択する。すると、Screenshot.png というファイルが作られる。その印刷は、「gimp」などのグラフィックツールを使用して印刷する。
■ 伝達事項
小レポートの採点後は、いったん返却します。返却されたレポートは各自がファイルに綴じておいて下さい。最終レポートと同時にそのファイルを提出してもらいます。その後、ファイルは返却しませんので、最後の提出時は必要ならば自分でコピーをとっておいて下さい。
(C) 2007.4.15 by tokuhisa