金宏 和實(かねひろ かずみ)

 富山県高岡市 株式会社イーザー副社長。阪神タイガース9連敗。「昨日は負けなくてよかったね」「ああ,雨で中止やったしね」と朝の挨拶ように話していたダメ虎時代に戻ったのかと思いました。しかし,若手が伸び,自力がついているようで,そう悲観することもないみたいですね。本当に弱いときは,負けゲームにベテランが中継ぎをしていましたが,今は若手投手が出てくるので「渡辺投手はいいなあ」「伊予野は何が足りのやろ?」「辻本はまだかな?」と負けゲームにも楽しみが見出せます。おっと,でも勝ってくださいね。

 今回からは数回にわたり,ある程度まとまったアプリケーションを作っていきたいと思います。まとまったアプリケーションを作るときにコアとなるのは,やっぱりクラスです。

 おっと,「オブジェクト指向は苦手だから,読まないでおこう」なんて思わないでくださいね。Visual Basic(VB)2005なら,オブジェクト指向開発なんて大上段に構える必要はありません。Visual Studio(VS)が提供してくれる機能を使えば,クラスの作成は思いのほか簡単です。

 さて,筆者は『こうしろうのMindStorms日記』にも書いておりますように,小学生を相手にLEGO MINDSTORMSを使ったロボット・プログラミングを教えています。また,WRO Japanの富山県予選にもかかわっています。ときには,情報処理やソフトウエア開発会社の若手技術者向けのロボット競技会で審判を務めることもあります。

 そんな中で,頻繁に行う競技はライントレース競技です。光センサーを付けた自律式ロボットが黒い線をなぞって進み,主にタイムを競います。

 図1のようなコースをロボット(写真1)が黒い線をトレースして進み,タイムを競うのです。もちろんタイムだけではなく,コースをきれいにトレースしているとか,停止位置で確実に止まったなどの要素も競技の採点に加味されます。具体的には,ライントレース終了後にきちんと停止できなかったら,ペナルティとして2秒加算というように成績に反映させます。

図1●ライントレース競技のコース例。ロボットがこの黒い線をトレースして走行し,ゴールするまでのタイムなどを競う
図1●ライントレース競技のコース例。ロボットがこの黒い線をトレースして走行し,ゴールするまでのタイムなどを競う

写真1●LEGO MINDSTORMS(レゴ マインドストーム)で作成したロボットの一例
写真1●LEGO MINDSTORMS(レゴ マインドストーム)で作成したロボットの一例

 このライントレース競技会の競技結果を記録するアプリケーションを数回にわたって作成していきたいと思います。その過程で,読者の皆さんに学習していただくことは,クラスの定義とインスタンス(オブジェクト)の生成,インスタンスをコレクションするArrayListとジェネリック版Listの違い,正規表現を使った入力フォームでのチェック処理,バイナリファイルとしてコレクションを永続化する方法などです。

 言いわけのように聞えるかもしれませんが,オブジェクト指向の重要な要素である継承(インヘリタンス)と多態性(ポリモーフィズム)はここでは扱いません。継承や多態性は大事な概念ですが,継承や多態性から説明を始めてしまうと,どうも概念的になりすぎて,オブジェクト指向を実際より小難しいものに見せてしまう可能性があるからです。

クラスの作成

 クラスを作成するには,まずプロパティとメソッドを決めなくてはいけません。「ほら,始まった。プロパティとかメソッドと言われてもなあ。それがピンと来ないんだよ。変数とか配列なら,慣れているんだけど」──こんな声が聞えてきそうですね。

 でも,[プロジェクト(P)]メニューから,[Windowsフォームの追加(F)]を選んで,フォームを作成してみてください。作成したフォームのコードを表示させると,先頭に

Public Class Form1
と定義されているはずです。つまり,フォームはクラスなのです。

 「フォームに,ライントレース競技会の記録のために必要な各チームの情報を入力するためのテキストボックスと必要な機能を実現するボタンを配置してください」──こんなお題にすりかえると考えやすいでしょうか。

 各テキストボックスがプロパティであり,ボタン・クリックで実行する機能がメソッドという風にも考えることができますね(図2)。

図2●ライントレース競技会の競技結果を記録するアプリケーションのフォーム
図2●ライントレース競技会の競技結果を記録するアプリケーションのフォーム

 NOは,チームを一意に識別するための番号です。参加チームは1チームを2,3人で構成することとし,チーム名と代表者名,代表者の連絡先として電話番号とメールアドレスを登録することにします。備考にはメモを入力します。例えば,このチームは女性ばかりだから,えこひいきをしようなどと入力します(笑)。

 競技は2回行うものとします。出走順は,抽選や先着順で決めます。タイムとペナルティとして加算する値の合計を1回の結果とします。ここまでがプロパティです。

 競技結果の評価方法は,スキーのジャンプ競技のように二本飛んで合計を競う方法と,2回のうち良いほうのタイムで競う方法があります。2回の合計を返す機能と2回のうち良いほうの結果を返す機能のそれぞれをメソッドとして用意することにします。

 これらのプロパティとメソッドをForm1クラスではなく,独自に作成するクラスに定義してやれば良いのです。プログラミングに入る前に,クラス図としてまとめておきましょう(図3)。

図3●今回のアプリケーションで最初に作成するクラスのクラス図。最初はあまり難しいことは考えず,必要なプロパティやメソッドを仕切って書くだけでよい
図3●今回のアプリケーションで最初に作成するクラスのクラス図。最初はあまり難しいことは考えず,必要なプロパティやメソッドを仕切って書くだけでよい

 何も難しいことはありません。箱を書いてその中にクラス名とプロパティ,メソッドを仕切って書けば良いだけです。詳細なクラス図になると,プロパティやメソッドにパブリック(+)やプライベート(-),プロテクテッド(#)といった修飾子を付けなければいけませんが,VBの場合,Javaとはプロパティの作り方が違うので,あまり厳密に考える必要はありません。

 また,同様にVBでは,Javaのようにプロパティやメソッドを明確に分けて考えることが難しいので,とりあえず,プロパティがフィールドで,メソッドが機能だというイメージを頭に描いてください。

 それでは,実際にクラスを作っていきましょう。クラスを作成するには[プロジェクト(P)]から[クラスの追加(C)]を選んで…という解説はこの連載の読者には不要かもしれませんが,プロパティは(図4)のようにスニペットの挿入を使って作成してください。もちろん,直接入力しても構わないのですが,スニペットでプロパティの定義を挿入すれば,無駄な間違いを起こす可能性が減ります。

図4●プロパティの定義といった定型的なコードは,Visual Studioのスニペット機能を使えば簡単に挿入できる
図4●プロパティの定義といった定型的なコードは,Visual Studioのスニペット機能を使えば簡単に挿入できる
[画像のクリックで拡大表示]

図5●プロパティの定義のスニペットを挿入した直後のコード
図5●プロパティの定義のスニペットを挿入した直後のコード

 図5は,プロパティの定義のスニペットを挿入した直後のコードです。

 VBのプロパティ定義では,プライベート変数を宣言して,その変数に値を設定(Set),取得(Get)するプロパティを作成します。もちろん,値を取得するだけのプロパティ(ReadOnly)や値を設定するだけのプロパティ(WriteOnly)を作成することもできます。

 緑色に反転している部分を実際のプライベート変数名,プロパティ名,データ型で置き換えていきます。例えば,NOプロパティはスニペットを(図6)のように変更して作成します。Privateの後ろの緑反転している変数をmintNoのように入力すると,GetやSetの中の変数名も連動して変更されます。Tabキー押すと,緑反転の部分だけを移動できます。

図6●スニペットで挿入したコードを実際の変数名などに置換するのも容易。この例では,宣言部の変数名をmintNoと入力すると,GetやSetの中の変数名も連動して変更される
図6●スニペットで挿入したコードを実際の変数名などに置換するのも容易。この例では,宣言部の変数名をmintNoと入力すると,GetやSetの中の変数名も連動して変更される

Public Class RaceTeam
  Private mintNo As Integer
  Public Property NO() As Integer
    Get
      Return mintNo
    End Get
    Set(ByVal value As Integer)
      mintNo = value
    End Set
  End Property
        ・
        ・
        ・
リスト1●RaceTeamクラスのプロパティを定義

 リスト1のように順にプロパティを定義しました。Javaなどのオブジェクト指向言語の経験がある方や,UMLを勉強したことがある方は,これをプロパティということに違和感があるかもしれませんね。VB 2005でのプロパティは,フィールド変数とアクセサ・メソッドの組み合わせなのです。

 このクラスに必要な機能として,クラス図に記述した合計タイムを取得する機能,ベストタイムを取得する機能,さらにクラス図には書きませんでしたが,各回のタイムとペナルティを合計して一回分の結果を求める機能が挙げられます。これらの機能もPropertyステートメントを使って記述することができるのです。

 ですから,今回作成するクラスでは,先ほどの図3のクラス図にあるどこまでがプロパティで,どこからがメソッドかを分ける線にはあまり意味がないようです。違いは対応するフィールド変数があるか,ないかです。


Public ReadOnly Property Result1() As Double
  Get
    Return Time1 + Penalty1
  End Get
End Property
Public ReadOnly Property Result2() As Double
  Get
    Return Time2 + Penalty2
  End Get
End Property
Public ReadOnly Property ResultSum() As Double
  Get
    Return Result1 + Result2
  End Get
End Property
Public ReadOnly Property ResultBest() As Double
  Get
    If Result1 = 0 And Result2 = 0 Then
      Return 0
    End If
    If Result1 < Result2 Then
      If Result1 > 0 Then
        Return Result1
      Else
        Return Result2
      End If
    Else
      If Result2 > 0 Then
        Return Result2
      Else
        Return Result1
      End If
    End If
  End Get
End Property
リスト2●合計タイムを取得するなどの四つの機能を読み取り専用プロパティとして定義

 この四つのプロパティは結果を返すだけですから,読み取り専用(ReadOnly)プロパティとして定義します。ちなみに,Getだけのプロパティを記述してReadOnlyを書き忘れると,コンパイル・エラーとしてはじいてくれます。こんなところにもVB 2005の親切さを感じます。