第2回 クラスの詳細(4月19日)

今日の課題

■ クラスとインスタンス

オブジェクトは、クラスとインスタンスの2種類がある。クラスは概念であり、インスタンスは具体物である。

たとえば、「クレジットカード」という概念には「カード会社名、カード名義、カード番号、有効期限、…」などの情報が含まれている。一方、自分が持っているクレジットカードは、その具体物であり、これらの情報が具体的に決まっている。

Smalltalk で「クレジットカード」のクラスを定義するとき次の変数が必要であろう(3つに省略している)。

Smalltalk で「クレジットカード」のインスタンスを作るとき、上記の変数にデータを入れておく必要がある。

クレジットカードクラスを作ってみよう

先週の続きの状態ならば、System Browser のカテゴリペインの最下行には「MyObject」というカテゴリが存在している。「MyObject」を左クリックをすると、クラスを定義するための雛形が「編集のペイン」に表示される。

以下の手順で、クラスを定義する。

  1. System Browser を開ける。
  2. 「カテゴリ」のペインで「MyObject」を選択する。
  3. 「編集」のペインで、「#NameOfSubclass」を「#CreditCard」に変更する。
  4. 「編集」のペインで、「instanceVariableNames: ''」を「instanceVariableNames: 'company owner number'」に変更する。
  5. コントロールを押しながら左クリックを押し、「了解(s)」を選択する。

こうして、インスタンス変数として、company, owner, number が定義されるが、インスタンス変数を書き換えるためのメソッド(アクセサと言う)が必要である。メソッドは次の手順で定義する。

  1. System Browser の「クラス」のペインにおいて、CreditCard を選択する。
  2. 「プロトコル」のペインで、「-- all --」を選択する。
  3. 「編集」のペインを全て削除する(通常、緑色でフラッシュしているので、デリートキーなどで一発消去ができる)。
  4. 「メソッド名: 引数名」で定義する。下記の例で、「setCompany:」がメソッド名、「n」が引数名であり、次の行が代入のステートメントで、インスタンス変数 company に n を代入している。
    setCompany: n
      company := n
    
  5. コントロールを押しながら左クリックを押し、「了解(s)」を選択する。

自分のクレジットカード(インスタンス)を作ってみよう

Workspace 上で以下を実行する。

  1. a := CreditCard new ※ 直後に alt キーを押しながら d を押すと実行できる
  2. a setCompany: 'JCB'
  3. a inspect

インスペクトのウインドウが表示され、その中にインスタンス変数の状態が表示されている。

■ 練習

カード名義、カード番号を代入するメソッド setOwner: と setNumber: を作成しよう。

Workspace 上で以下を実行し、インスペクトウインドウの表示の変化を見てみよう。

  1. a setOwner: 'Tokuhisa Masato'
  2. 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機能付きのクレジットカードのクラスを定義するにはどうすれば良いか?

  1. インスタンス変数として、カード会社、カード名義、カード番号、エディ金額を持つクラスを定義する。そして、カード会社、カード名義、カード番号を登録するメソッドを定義した上、エディ金額の参照と変更のためのメソッドを定義する。
  2. クレジットカードクラスの下位クラスとして、エディ金額のインスタンス変数を持つクラスを定義する。そして、エディ金額の参照と変更のためのメソッドを定義する。

どちらが簡単そうに見えますか?

クラスの継承をしてみよう

まず、下位クラス(サブクラス)を定義する。

  1. System Browser を開ける。
  2. 「カテゴリ」のペインで「MyObject」を選択する。
  3. 「編集」のペインで、「Object subclass: #NameOfSubclass」を「CreditCard subclass: #EdyCreditCard」に変更する。
  4. 「編集」のペインで、インスタンス変数の '' を 'edy'に変更する。
  5. 「了解(s)」をする。

次に、エディ金額の参照と変更のためのメソッドを定義する。

  1. 「クラス」のペインで、「EdyCreditCard」を選択する。
  2. 「プロトコル」のペインで、「-- all --」を選択する。
  3. 「編集」のペインで全て削除する。
  4. 「編集」のペインで、メソッド名を「readEdy」とし、ステートメントを「^edy」とする。「^」は C言語の return と同じである。「了解(s)」をすると「↑」になる。
  5. 同様に、メソッド名を「writeEdy:」とし、引数を「n」とする。ステートメントを「edy := n」とする。「了解(s)」をする。

試しに動かしてみよう

Workspace で、以下を実行しよう。

  1. a := EdyCreditCard new
  2. a inspect
  3. a entry: 'VISA' owner: 'Masato Tokuhisa' number: '87654321'
  4. a writeEdy: 10000
  5. Transcript show: a readEdy

■ 小レポート

身の回りの物を Smalltalk のクラスとサブクラスで定義しよう。

ヒント:
基本機能のものを上位のクラスに、発展機能のものを下位クラスで定義するとよいでしょう。たとえば、「電話」をクラスにすると、インスタンス変数は電話番号になり、「留守番機能付き電話」をサブクラスにすると、追加するインスタンス変数は「留守番メッセージ」と「受信メッセージ(メモリーは簡単に1件のみとしよう)」として、それらの読み書きのメソッドを追加する。
提出の要領:

来週、演習の開始時に集めます。

画面の取り込みは、Linux の画面の一番上のメニューバーの「アクション」を選択し、「スクリーンショット」を選択する。すると、Screenshot.png というファイルが作られる。その印刷は、「gimp」などのグラフィックツールを使用して印刷する。

■ 伝達事項

小レポートの採点後は、いったん返却します。返却されたレポートは各自がファイルに綴じておいて下さい。最終レポートと同時にそのファイルを提出してもらいます。その後、ファイルは返却しませんので、最後の提出時は必要ならば自分でコピーをとっておいて下さい。


(C) 2007.4.15 by tokuhisa