抽象クラスとポリモーフィズム

 抽象クラスを使用してポリモーフィズムを実現させてみましょう。スーパークラスの型でサブクラスのオブジェクトを扱えることを思い出してください。抽象クラスの型で、抽象クラスを実装したオブジェクトを格納することができます。ただしその場合、呼び出すことができるのは抽象クラスで定義しているメンバだけです。

 これからいろいろな乗り物を操作できるシミュレーターを作成してみましょう。乗り物クラスを継承したスポーツカークラス、タクシークラスを作成して利用してみましょう。ポリモーフィズムを確認するために、乗り物のテストをするテストドライバークラスを作成して、テストドライバーが乗り物を動かすようにします。

○ プロジェクト

 プロジェクトを作成して確認してみましょう。

プロジェクトの種類 コンソール アプリケーション
プロジェクト名 AbstractPlymoTest

サンプルダウンロード

○ 作成の準備

 「AbstructClassTest」プロジェクトを修正して作成しましょう。AbstructClassTestフォルダーをコピーして、作成するプロジェクト名にフォルダー名を変更してください。

○ プログラム

 次に、乗り物クラスを継承したタクシークラスを作成しましょう。

Taxi.vb

  1. Public Class Taxi
  2.  Inherits Vehicle
  3.  'フィールド==========
  4.  Private MaxSpeed As Integer '最大スピード
  5.  'プロパティ==========
  6.  Public Property Unchin As Integer     '売上金額
  7.  Public Property Distance As Double     '走行距離
  8.  Public Property Aboard As Boolean     '乗車状態
  9.  'コンストラクタ==========
  10.  Public Sub New(gas As Double, maxspeed As Integer)
  11.   MyBase.New(gas)
  12.   'ガソリン量が容量を超えている場合は、最大容量をガソリン残量にセット
  13.   If Me.Gas > 70 Then
  14.    Me.Gas = 70
  15.   End If
  16.   Me.MaxSpeed = maxspeed
  17.  End Sub
  18.  'メソッド==========
  19.  Public Overrides Sub SpeedUp(sp As Integer)
  20.   '消費するガソリンがない場合は加速しない
  21.   If Not ((Me.Gas - sp / 20.0) <= 0) Then
  22.    '加速
  23.   Me.Speed += sp
  24.    Me.Gas -= sp / 20.0
  25.   End If
  26.   'スピードが最大スピードを超えていたら、最大スピードにセット
  27.   If Me.Speed > Me.MaxSpeed Then
  28.    Me.Speed = Me.MaxSpeed
  29.   End If
  30.  End Sub
  31.  Public Function RideToTaxi(price As Integer, distance As Double) As String
  32.   '乗車中かどうか
  33.   If Me.Aboard Then
  34.    Return "乗車中です。"
  35.   End If
  36.   '走行中かどうか
  37.   If Me.Speed <> 0 Then
  38.    Return "停車してください。"
  39.   End If
  40.   '運賃、距離を加算
  41.   Me.Unchin += price
  42.   Me.Distance += distance
  43.   Me.Aboard = True
  44.   Return Nothing
  45.  End Function
  46.  Public Function GetOffTaxi() As String
  47.   '乗車中かどうか
  48.   If Not Me.Aboard Then
  49.    Return "乗車していません。"
  50.   End If
  51.   '走行中かどうか
  52.   If Me.Speed <> 0 Then
  53.    Return "停車してください。"
  54.   End If
  55.   '乗車の状態を変更
  56.   Me.Aboard = False
  57.   Return Nothing
  58.  End Function
  59. End Class

○ クラス図

○ 解説

 4行目では最大スピードを格納するフィールドを定義しています。インスタンス生成時に最大スピードを初期化し、加速するときにこのフィールドを参照して加速するかを決定します。

 7~9行目では売上金、走行距離、乗車状態のプロパティを定義しています。

 12~19行目ではコンストラクタを定義しています。このコンストラクタはガソリン量を受けとって、スーパークラスのコンストラクタを呼び出し、ガソリン量をセットしています。そのあと、ガソリンタンク容量と比較して、セットしたガソリン量が多ければ最大容量にセットするという処理をします。

 22~34行目ではSpeedUpメソッドをオーバーライドしています。抽象クラスを継承すると、抽象メソッドは必ずオーバーライドしなければならないという義務が発生します。今回は加速するときに、消費するガソリン量がない場合は加速しない、最大スピードに達していた場合はそれよりスピードが出ないようにしています。 スポーツカークラスと違い、消費する燃料を抑えています。

 36~52行目では乗車する処理を定義しています。車が走っているか、既に乗車している場合には人は乗せられないようにしています。止まっているか、空車の場合は引数として受け取った料金、距離、乗車状況を、プロパティを使って設定しています。

 54~68行目では、降車する処理を定義しています。車が走っている場合は人を降ろせないようにしています。止まっていれば降車処理をしますが、今回は乗車状態を変更しています。

○ プログラム

 次に、乗り物を運転するテストドライバークラスを作成しましょう。次にようにクラスを作成してください。

TestDriver.vb

  1. Public Class TestDriver
  2.  'フィールド==========
  3.  Private Accelerate As Integer     '加速度合(km)
  4.  Private Car As Vehicle     '車
  5.  'コンストラクタ==========
  6.  Public Sub New(car As Vehicle, sp As Integer)
  7.   Me.Car = car
  8.   Me.Accelerate = sp
  9.  End Sub
  10.  'メソッド==========
  11.  Public Sub SpeedUp()
  12.   Me.Car.SpeedUp(Me.Accelerate)
  13.  End Sub
  14.  Public Sub SpeedDown()
  15.   Me.Car.SpeedDown(Me.Accelerate)
  16.  End Sub
  17. End Class

○ クラス図

○ 解説

 3行目では加速度合いを保存する変数を宣言しています。また、4行目ではテストドライバーが操作する乗り物オブジェクトを保持する変数を宣言しています。この変数はVehicle型なので、Vehcileを継承したクラスであれば保持できることになります。そのためテストドライバーは乗り物を継承した様々なタイプの乗り物を動かすことができます。今回作成したタクシークラスと、先回作成したスポーツカークラスはVehicleクラスを継承しているため、保持することができます。

 7~10行目ではコンストラクタが定義されています。引数に乗り物、加速度合いを受け取り、それぞれのフィールドにセットします。テストドライバーがどの乗り物を運転するかがテストドライバーオブジェクトを作るときに決まることになります。

 13~15行目では加速処理が定義されています。ここのSpeedUpメソッドは、乗り物クラス・スポーツカークラス・タクシークラスとは直接関係はありません。そのため、別のメソッド名で定義しても問題ありません。自分が乗っている(フィールドに保持している)乗り物のSpeedUpメソッドを呼び出す記述が14行目にあります。フィールド変数にセットされているスピード分だけ加速します。

 17~19行目では減速処理が定義されています。ここのSpeedDownメソッドは、乗り物クラス・スポーツカークラス・タクシークラスとは直接関係はありません。そのため、別のメソッド名で定義しても問題ありません。ここでの振る舞いは、前述したSpeedUpメソッドと同じです。自分が乗っている(フィールドに保持している)乗り物を減速させます。

○ プログラム

 では次にMainメソッドを修正しましょう。

Module1.vb

  1. Module Module1
  2.  '車の状態を表示するメソッド
  3.  Public Sub ShowMeter(car As Vehicle)
  4.   'コンソールの表示を消す
  5.   Console.Clear()
  6.   '各プロパティの内容を表示する
  7.   Console.WriteLine("スピード:{0}km/h", car.Speed)
  8.   Console.WriteLine("ガソリン:{0}L", car.Gas)
  9.  End Sub
  10.  Sub Main()
  11.   '選択メニューを表示
  12.   Console.WriteLine("走らせる車の種類を選んでください。")
  13.   Console.Write("1)スポーツカー 2)タクシー:")
  14.   Dim inputdata As String = Console.ReadLine()
  15.   '選択した車オブジェクトを生成
  16.   Dim car As Vehicle
  17.   Dim driver As TestDriver
  18.   If inputdata = 1 Then
  19.    'スポーツカーとテストドライバーを生成
  20.    car = New SportsCar(60)
  21.    driver = New TestDriver(car, 20)
  22.   ElseIf inputdata = 2 Then
  23.    'タクシーとテストドライバーを生成
  24.    car = New Taxi(50, 60)
  25.    driver = New TestDriver(car, 5)
  26.   Else
  27.    Console.WriteLine("車を作れませんでした。")
  28.    Console.ReadLine()
  29.    Return
  30.   End If
  31.   '状態を表示
  32.   ShowMeter(car)
  33.   While True
  34.    '操作を入力
  35.    Console.Write("1)加速 2)減速 9)終了:")
  36.    inputdata = Console.ReadLine()
  37.    '操作によって分岐する
  38.    Select Case inputdata
  39.     Case "1"
  40.      '加速する
  41.      driver.SpeedUp()
  42.      ShowMeter(car)
  43.     Case "2"
  44.      '減速する
  45.      driver.SpeedDown()
  46.      ShowMeter(car)
  47.     Case "9"
  48.      'プログラムを終了する
  49.      Return
  50.     Case Else
  51.      ShowMeter(car)
  52.    End Select
  53.   End While
  54.  End Sub
  55. End Module

○ 解説

 15~17 行目で、乗り物の選択肢を用意しました。ユーザーはスポーツカーかタクシーを選ぶことになります。22~34行目では、選択した乗り物と、テストドライバーを生成しています。乗り物に応じてテストドライバーに加速の仕方を指示(乗り物と加速度合い)しています。

 39~60行目では、メニューを表示してテストドライバーに加速、減速などの指示を与えています。テストドライバーは自分にセットされている乗り物に対してSpeedUpメソッドやSpeedDownメソッドを呼び出して車を走らせることになります。その状態をShowMeterメソッドで表示しています。スポーツカーかタクシーのどちらのSpeedUp・SpeedDownメソッドが呼び出されるかは、テストドライバーにどちらのオブジェクトがセットされているかによって決まります。

今回のポリモーフィズムのイメージ
今回のポリモーフィズムのイメージ

 抽象クラスを使用してポリモーフィズムを実現させることができました。各オブジェクトを作り、テストドライバーにテスト実行時に乗り物を指定して加速させたり減速させたりさせ、その乗り物の状態を確認してメーターに表示しています。TestDriverクラスで呼び出しているSpeedUpメソッドやSpeedDownメソッドは、どのオブジェクトがセットされるかによって振る舞いが変わっているのを確認できたと思います。これを多態性、多様性(ポリモーフィズム)と言います。

 抽象クラスでは同じような属性を持ったオブジェクトを作ることができます。乗り物クラスであれば、乗り物の部類に属するものを定義することができます。次に、属性が全く異なるものに対しても同じ処理を指定する方法を見てみましょう。

前へ   次へ