クラスって何?こまけーこたぁいいんだよ

VBAプログラミング

VBAのプログラムを勉強している方で、SubとFunctionは使いこなせているけど、この↓クラスモジュールって何?という方がいるかと思います。

クラスのアイコンってなんか不気味ね。

ここではクラスの細かい定義は置いといて、実践的なところでクラスを使うと何が良いかということをお伝えします。

例えば、Functionで、何か計算を行ったときに、その結果を返すことはできますが、エラーになった場合のエラー内容を一緒に戻すことはできませんね。

そういう時は、例えば「エラーの場合は0を返す」のようなマイルールで運用するような形になりがちですが、それがエラーなのか本当に0なのか分かりません。

また、Functionの引数がたくさんあるとき、例えば下記のような条件。

顧客番号1000番以上、関西地区、担当者Aさん、年間売り上げ100,000円以上。

このように条件が多いと、引数が非常に長くなりますよね。

'呼び出し元
Sub check()

    Dim customerID As Integer
    Dim address As String
    Dim tanto As String
    Dim uriage As Integer
    Dim custCheckResult As Boolean
    
    For RowCount = 2 To 100
    
'1列目 - 顧客番号
'2列目 - 住所
'3列目 - 担当者
'4列目 - 年間売上
customerID = Cells(RowCount, 1) address = Cells(RowCount, 2) tanto = Cells(RowCount, 3) uriage = Cells(RowCount, 4)
'引数が多いとわかりづらい・・ custCheckResult = CustomerCheck(customerID, uriage, address, tanto) '結果を5列目に記載 Cells(RowCount, 5) = custCheckResult Next End Sub '引数が多いとわかりづらい・・ Function CustomerCheck(customerID, uriage, address, tanto) On Error GoTo ErrorShori If customerID >= 1000 And _ uriage >= 100000 And _ InStr("大阪", address) > 0 And _ tanto = "Aさん" Then CustomerCheck = True Else CustomerCheck = False End If Exit Function ErrorShori: MsgBox ("エラーが発生しました。怒らずに落ち着いてから開発元へスクリーンショットを送ってください。" & vbCrLf & Err.Description) End Function

このようにFunctionの引数が多いと何番目が何の項目かがわかりにくく、プログラム変更を行ったときに、Functionの引数の場所を間違えたりしてしまいがちです。

また、もう一つの問題として、Functionでエラーが発生した場合、その都度ポップアップのメッセージが出てしまいます。

このコードでは2行目から100行目をループしていますが、もしすべてエラーが出てしまった場合、100行目まで毎回OKボタンを押すか、タスクマネージャーで落とすしか方法がありません。

タスクマネージャーにはいつもお世話になっています。

クラスを使用した場合、引数(渡す値)がわかりやすいのと、結果をいくつでも受け取ることが出来るので、上記のチェック結果とエラーかどうか、エラー内容などを受け取ることが出来ます。

ではさっそくクラスを追加してみましょう。

まずは下記のように左側のツリーで右クリックして、挿入 – クラスモジュールを選択します。

次に、追加されたクラスのプロパティで、今回はオブジェクト名をCustomersにしておきましょう。

それでは次にクラスを記述していきます。クラスにはプロパティとメソッドというものがあります。ものすごく簡単に言えば、プロパティとはデータ(Functionで言うところの引数や返り値)、メソッドとは動作(SubやFunction)のことです。

説明が簡単すぎて逆にわからん。

まずはプロパティからですが、これがなかなか面倒なので、挫折しないように、こちらも簡単にご説明します。

プロパティにはクラス側で受け取りたい値(CusotomerIDや売上など)と、クラスから渡したい値(チェック結果や、エラー有無など)を設定します。

受け取りたい値は下記のように、

Private CustomerID_ As Integer  と、

Property Let customerID(value As Integer)
CustomerID_ = value
End Property

を記述します。_(アンダーバー)を今回は付けていますが、何でも構いませんが、呼び出し元とは異なる名称にする必要があるので、アンダーバーを付けています。

とりあえず下記丸ごとコピペで構いません。

' ----------------- プロパティの設定 -------------------
'--- クラスが受け取りたい値(Functionで言うところの引数)
Private CustomerID_ As Integer
Private Uriage_ As Integer
Private Address_ As String
Private Tanto_ As String
'

Property Let customerID(value As Integer)
    CustomerID_ = value
End Property

Property Let uriage(value As Integer)
    Uriage_ = value
End Property

Property Let address(value As String)
    Address_ = value
End Property

Property Let tanto(value As String)
    Tanto_ = value
End Property
'---

'--- クラスから渡したい値(Functionで言うところの返り値)
Property Get custCheckResult() As Boolean
    custCheckResult = custCheckResult_
End Property

Property Get noError() As Boolean
    noError = noError_
End Property

Property Get errorDesc() As String
    errorDesc = errorDesc_
End Property
'---
' --------------------------------------------------------------------

長すぎだろこれ。もうFunction一発でいいや。

それ言ったらこの記事の意味ないわよ。

次にメソッドです。上記の下に続けてコピペしてください。

中身を見てもらうとわかりますが、内容は一番最初に例に挙げたFunctionとほぼ同じです。ただ、顧客チェック結果以外に、エラーの有無やエラー内容もプロパティに代入しています。

' ----------------- メソッドの設定(クラス内のSubとかFunctionのこと) -------------------
'顧客チェック
Sub custCheck()

    On Error GoTo ErrorShori

    If CustomerID_ >= 1000 And _
       Uriage_ >= 100000 And _
       InStr("大阪", Address_) > 0 And _
       Tanto_ = "Aさん" Then

       custCheckResult_ = True

    Else

       custCheckResult_ = False

    End If

    'エラーなし
    noError_ = True
    errorDesc_ = ""

Exit Sub

ErrorShori:
    'エラーあり
    noError_ = False
    errorDesc_ = Err.Description

End Sub
' --------------------------------------------------------------------

クラスの作成はここまでです。プロパティの箇所が面倒ですが、書き方さえ覚えてしまえば、面倒なだけで難しくはないと思います。

その面倒なのが問題なんだが。。

VBAだからね。しょうがないね。

次に呼び出し元です。

ここでは一先ずSheet1の方に下記をコピペしてください。

'呼び出し元
Sub check()
    
    Dim result As Boolean
    Dim cust As Customers
    
    For RowCount = 2 To 100
        
        'Customersクラスをセット
        Set cust = New Customers
        
' --- クラスの処理を書く ---


        'Customersクラスを解放
        Set cust = Nothing
    
    Next

End Sub

少しわかりにくいとは思いますが、Dim cust As Customers で先ほど作成したクラスを宣言して、Set cust = New Customersで、custという変数名でクラスをセットしています。(セットすることをインスタンス化といいます)

そして、Set cust = Nothing でクラスを解放しています。変数の初期化みたいな感じです。

それではここで一つ試してほしいのが、上記の「クラスの処理を書く」のところで、 cust.(点)と打ってみてください。

VBE(VB Editor)の補完機能で、先ほど作成したクラスのプロパティとメソッドが一覧で表示されます。

自分が作ったのが自動で出てくるのは気持ちいい~

ちょっと何言ってるかわからない。

クラスが便利なのは、このように補完される点にもあります。

それでは残り分も含めたコードは下記になります。

'呼び出し元
Sub check()
    
    Dim result As Boolean
    Dim cust As Customers
    
    For RowCount = 2 To 100
        
        'Customersクラスをセット
        Set cust = New Customers
        
'1列目 - 顧客番号
'2列目 - 住所
'3列目 - 担当者
'4列目 - 年間売上 cust.customerID = Cells(RowCount, 1) cust.address = Cells(RowCount, 2) cust.tanto = Cells(RowCount, 3) cust.uriage = Cells(RowCount, 4) cust.custCheck If cust.noError = False Then MsgBox ("エラーが発生しました。怒らずに落ち着いてから開発元へスクリーンショットを送ってください。" & _ vbCrLf & cust.errorDesc) Exit Sub End If '結果を5列目に記載 Cells(RowCount, 5) = cust.custCheckResult 'Customersクラスを解放 Set cust = Nothing Next End Sub

まずは cust.customerID = Cells(RowCount, 1)のところで、customerIDのプロパティに値を入れています。ここは順番は関係ありませんので、例えばcust.address = Cells(RowCount, 2)を先に記述しても問題ありません。

ここがFunctionと比較すると、わかりやすいところです。Functionの場合、引数の順番で、渡す値が決まっていますが、このようになっていると、何の値を渡しているのかが明確ですね。

次に、cust.custCheckのところで、顧客のチェックを行って、結果がcust.custCheckResultに入ってきます。

ここで便利なのが、cust.noErrorというプロパティには、チェックしたときにエラーがなかったかどうかが入っていますので、こちらがfalseの場合、メッセージを出して、Exit Subで処理を終了させることができます。

このように、コードは長くなってしまいますが、Functionだけでは出来ないことが可能になります。今回は一例を挙げて、クラスの良い点をご説明しましたが、実際にはまだまだほかにも利点がありますので、また今後ご紹介したいと思います。

もしまだクラスを使ったことが無いという方は、ぜひ一度試してみてください。

実際にステップ実行して1つずつの処理を確認してみるといいかもね。

なるほど。つまり細かく説明するのが面倒ってことね。

コメント

タイトルとURLをコピーしました