前回はクラスの基本について書きました。そして後半では、クラス無しコードも記述して、クラスありと無しの場合を比較しました。
今回は、もっと掘り下げてクラスの使いどころについて検証していきたいと思います。
クラスの必要性をいまいち感じない、使いどころがわからないという人に読んでいただきたいです。
前回のコード(振り返り)
クラスありのコード
車クラスモジュールを作成して、Carオブジェクトを生成しました。
①車クラスにはタイヤプロパティとガソリンプロパティを作っています。
②イニシャライズでタイヤプロパティに50が代入されます。
③空気メソッド:タイヤプロパティに10が加算されるメソッドです。
④空気調整メソッド:タイヤプロパティからxが減算されるメソッドです。
⑤給油メソッド:ガソリンプロパティに10が加算されるメソッドです。
⑥排出メソッド:ガソリンプロパティからxが減算されるメソッドです。
⑦空気圧メソッド、⑧残量メソッドを作っています。ファンクション型になっており、返り値としてそれぞれタイヤプロパティ、ガソリンプロパティが設定されています。
Sub クラスTEST_1()
Dim car As 車
Set car = New 車
car.空気
car.空気調整 (60)
car.給油
car.排出 (0)
MsgBox "タイヤの空気:" & car.空気圧結果
MsgBox "のガソリンの残量:" & car.残量
End Sub
Private タイヤ As Long
Private ガソリン As Long
Private Sub Class_Initialize()
タイヤ = 50
End Sub
Sub 空気()
タイヤ = タイヤ + 10
End Sub
Sub 空気調整(x As Integer)
タイヤ = タイヤ - x
End Sub
Sub 給油()
ガソリン = ガソリン + 10
End Sub
Sub 排出(x As Integer)
ガソリン = ガソリン - x
End Sub
Function 空気圧結果() As Integer
空気圧結果 = タイヤ
End Function
Function 残量() As Integer
残量 = ガソリン
End Function
クラス無しのコード
Private タイヤ As Long
Private ガソリン As Long
Sub クラスTEST_2()
タイヤ = 50
Call 空気
Call 空気調整(60)
Call 給油
Call 排出(0)
タイヤ = 空気圧結果
ガソリン = 残量
MsgBox "タイヤの空気:" & タイヤ
MsgBox "のガソリンの残量:" & 残量
End Sub
Sub 空気()
タイヤ = タイヤ + 10
End Sub
Sub 空気調整(x As Integer)
タイヤ = タイヤ - x
End Sub
Sub 給油()
ガソリン = ガソリン + 10
End Sub
Sub 排出(x As Integer)
ガソリン = ガソリン - x
End Sub
Function 空気圧結果() As Integer
空気圧結果 = タイヤ
End Function
Function 残量() As Integer
残量 = ガソリン
End Function
前回も述べましたが、このコードを見比べて、そこまでクラスを使うメリットを感じないということ・・・。
では、どういう場合にクラスが有効なのかを具体的に検証します。
今回のコード(クラス無し)
前回のコードを少し変更して、使用する変数を配列変数にしました。
最終的にはそれぞれの変数に格納してある数字をメッセージボックスに出しています。
Sub クラスTEST_2()
Dim タイヤ(1 To 3) As Long
Dim x As Integer
Dim i As Integer
j = 1
For i = 1 To 3
タイヤ(i) = 50
Call 空気(タイヤ, j)
x = x + 10
Call 空気調整(タイヤ, x, j)
MsgBox "車" & i & "のタイヤの空気:" & 空気圧結果(タイヤ, j)
j = j + 1
Next
End Sub
Sub 空気(タイヤ() As Long, j As Integer)
タイヤ(j) = タイヤ(j) + 10
End Sub
Sub 空気調整(タイヤ() As Long, ByVal x As Integer, j As Integer)
タイヤ(j) = タイヤ(j) - x
End Sub
Function 空気圧結果(タイヤ() As Long, j As Integer) As Long
空気圧結果 = タイヤ(j)
End Function
コードの流れ
- 配列変数を宣言
- For ~Nextステートメントで添え字を代入
- タイヤ配列変数に50を代入
- コールステートメントで空気調整プロシージャを呼び出し、タイヤ配列変数に10を加算
- コールステートメントで空気調整プロシージャを呼び出し、タイヤ変数から引数分減算
- プロシージャ名:空気圧結果のファンクションプロシージャを使ってメッセージボックスを表示する(ファンクションではなく変数を直接使っても良かったですが、後述するクラスのあるコードにファンクションを使っているのでそれに合わせています。)
今回のコード(クラスあり)
前回と同様に車クラスを使います。(クラスの基本、使い方については前回の記事をご覧ください。)
標準モジュール
Sub クラスTEST_2()
Dim Car(1 To 3) As 車
Dim i As Long
Dim x As Integer
For i = 1 To 3
Set Car(i) = New 車
Car(i).空気
x = x + 10
Car(i).空気調整 x
MsgBox "車" & i & "のタイヤの空気:" & Car(i).空気圧結果
Next i
End Sub
車クラス
Public タイヤ As Long
Private Sub Class_Initialize()
タイヤ = 50
End Sub
Sub 空気()
タイヤ = タイヤ + 10
End Sub
Sub 空気調整(タイヤ As Integer)
Me.タイヤ = Me.タイヤ - タイヤ
End Sub
Function 空気圧結果() As Integer
空気圧結果 = タイヤ
End Function
- For~Nextステートメントを使って、車クラスのCarオブジェクトを3つ生成しています。Car(1)、Car(2)、Car(3)です。(イニシャライズを設定してあり、タイヤプロパティに50が代入されています)
- それぞれのCarオブジェクトの空気メソッドで10が加算
- 空気調整メソッドでそれぞれの引数をタイヤプロパティから減算
- 空気圧結果メソッドを使って、メッセージボックスを出しています
比較
比較するとそこまで大きくコードがすっきりしたという印象はないと思います。しかし、クラス無しの場合は、いちいち他のプロシージャに値を渡す時に引数で添え字(配列変数番号)を渡していますが、クラス有りの場合は、配列変数に使っている番号分だけオブジェクトを生成しているわけですから、そういった引数は省略できます。
つまり、クラス無しの場合は、他のプロシージャに渡す時に、どの配列番号なのかの指定が必須ですが、クラス有りの場合は必要ありません。
メリット
そもそもクラスは、複数のオブジェクトが同一のクラスを共有できるということが大きな特長でありメリットです。
今回で言えばCarオブジェクト(1)~(3)は同一の「車」クラスを扱えるということです。
クラスの中のプロパティとメソッドをオブジェクトごとに扱えることが最大のメリットです。
配列とクラス
配列変数を使って、以下のコードのようにCar配列変数に車A、車B、車C配列変数を入れてあげることで車A、B、Cをクラスのプロパティのように扱うことが可能です。
しかし、配列変数の数が増えていくと、入力がかなり大変になってきます。
こういう場合もクラスを使った方が効果的ということがわかります。
クラス無し
'配列プロシージャ
Sub クラスTEST_3()
Dim 車A(0 To 2) As Variant
Dim 車B(0 To 2) As Variant
Dim 車C(0 To 2) As Variant
Dim car(0 To 2) As Variant
車A(0) = 200
車A(1) = 200
車A(2) = "トラック"
車B(0) = 50
車B(1) = 50
車B(2) = "軽自動車"
車C(0) = 100
車C(1) = 100
車C(2) = "普通車"
car(0) = 車A
car(1) = 車B
car(2) = 車C
Call 調整(5, 5, car(0))
End Sub
Sub 調整(x As Integer, y As Integer, car As Variant)
car(0) = car(0) + x
car(1) = car(1) + y
End Sub
調整プロシージャにCar(0)の(0)と(1)を渡して5を加算するというコードです。
クラスあり
'標準モジュール
Sub クラスTEST_5()
Dim car(1 To 3) As 車
Dim i As Long
For i = 1 To 3
Set car(i) = New 車
car(i).サイズ Cells(i + 1, 1).Value, Cells(i + 1, 2).Value, Cells(i + 1, 3).Value
Next i
car(1).調整 5, 5
End Sub
'クラスモジュール
Public 重量 As Long
Public 車高 As Long
Public 車種 As String
Sub サイズ(重量 As Long, 車高 As Long, 車種 As String)
Me.重量 = 重量
Me.車高 = 車高
Me.車種 = 車種
End Sub
Sub 調整(重量 As Long, 車高 As Long)
Me.重量 = Me.重量 + 重量
Me.車高 = Me.車高 + 車高
End Sub
調整プロパティでCar(1)クラスオブジェクトの車高プロパティと重量プロパティに5が加算されます。
ワークシートに入力したものを引数として使用することでFor文で一気に取り込めます。
クラス無しの場合もワークシートを参照して、For文と二次元配列を使うことで一気に取り込めますが、二次元配列では、配列をクラスのオブジェクトとプロパティ、メソッドのように使うことはできづらいです。
'二次元配列
Sub クラスTEST_4()
Dim r As Integer
Dim c As Integer
Dim car(1 To 3, 1 To 3) As Variant
For r = 1 To 3
For c = 1 To 3
car(r, c) = Cells(r + 1, c).Value
Next c
Next r
End Sub
検証結果:配列とクラスの比較(まとめ)
- クラスを使うことで、他のプロシージャに渡す時に配列の添え字を省略できる。
- 配列変数を複数使用する場合は、クラスにすることでコードのシンプル化ができる。
- オブジェクトごとのプロパティ、メソッドが活用できるので、他のプロシージャに渡す場合に配列より扱いやすい。
プロパティのカプセル化
さて、前回の記事でクラスのプロパティをPrivateにしていることをお伝えしたと思います。
これについては、プロパティの値が標準プロシージャで簡単に変更されるのを防ぐ意味があります。
'標準プロシージャ
Sub クラスTEST_2()
Dim car(1 To 3) As 車
Dim i As Long
Dim x As Integer
For i = 1 To 3
Set car(i) = New 車
car(i).空気
x = x + 10
car(i).空気調整 x
MsgBox "車" & i & "のタイヤの空気:" & car(i).空気圧結果
Next i
car(1).タイヤ = 0 'タイヤプロパティに0を代入
MsgBox "車1のタイヤの空気:" & car(1).タイヤ
End Sub
'クラスモジュール
Public タイヤ As Long
Private Sub Class_Initialize()
タイヤ = 50
End Sub
Sub 空気()
タイヤ = タイヤ + 10
End Sub
Sub 空気調整(タイヤ As Integer)
Me.タイヤ = Me.タイヤ - タイヤ
End Sub
Function 空気圧結果() As Integer
空気圧結果 = タイヤ
End Function
クラスの中のタイヤプロパティはPublicです。
標準プロシージャ内でcar(1).タイヤ = 0ができてしまうとタイヤプロパティは一瞬で0になってしまいます。これだとせっかくクラス内でプロパティの値を保存していたとしても、簡単にリセットされてしまいます。
よって、標準プロシージャ内では、クラスのプロパティを扱えないようにするためにprivateにしておくのが一般的です。
これをカプセル化と言います。
まとめ
今回はクラスの使いどころに絞って記事を書きました。
次回もお楽しみに!
コメント