の改善版!
ポイント
- プロパティ (クラス変数) は Public メソッド以外から呼ばないようにした。
- 関数型プログラミング入門 | プログラミング | POSTD の「副作用がない」コードという考え方を参考にした。
- 結果、Private 関数の引数が増えた。デメリットと感じる。
- 結果、プロパティが減り、ロジックが単純になった。うれしい!
VBA コード
Option Explicit
Private mcolReaded As Collection
' 自身のクラスをモデルとして扱いたい。
' インスタンス化したときに値を設定できるように、Public に設定
Public mlngNo As Long
Public mstrWeekday As String
Public mdtmFrom As Date
Public mdtmTo As Date
Public mlngPrice As Long
''' <summary>
''' コンストラクタ
''' </summary>
Private Sub Class_Initialize()
Set mcolReaded = New Collection
End Sub
''' <summary>
''' 初期化処理を実行します。
''' </summary>
''' <param name="strTartgetWorksheet">捜査対象ワークシート</param>
Public Sub Init(ByVal strTartgetWorksheet As String)
' 変数をセット
Dim objSheet As Worksheet: Set objSheet = Worksheets(strTartgetWorksheet)
With objSheet
' 下端の行番号、右端の列番号を取得
Dim lngMaxRow As Long: lngMaxRow = .Cells(Rows.Count, 1).End(xlUp).Row
Dim lngMaxCol As Long: lngMaxCol = .Cells(1, Columns.Count).End(xlToLeft).Column
' マスタデータ部分を取得。1行目はヘッダーのため無視
Dim objMaster As Range: Set objMaster = .Range(.Cells(2, 1), Cells(lngMaxRow, lngMaxCol))
End With
' マスタデータのクラスコレクション生成
Dim i As Long
For i = 1 To objMaster.Rows.Count
Dim udtRow As PriceTable: Set udtRow = New PriceTable
With udtRow
.mlngNo = objMaster(i, 1)
.mstrWeekday = objMaster(i, 2)
.mdtmFrom = objMaster(i, 3)
.mdtmTo = objMaster(i, 4)
.mlngPrice = objMaster(i, 5)
End With
Call mcolReaded.Add(udtRow)
Next i
End Sub
''' <summary>
''' 引数を条件として絞り込んだ料金を返却します。
''' 結果が複数ある場合は、最初の料金を返却します。
''' 絞込結果が 0 件の場合は、0 を返却します。
''' </summary>
''' <param name="strWeekday">曜日</param>
''' <param name="dtmTime">時刻</param>
''' <returns>料金</returns>
Public Function GetPrice( _
ByVal strWeekday As String, _
ByVal dtmTime As Date) As Long
Dim colFiltered As Collection: Set colFiltered = Filter(mcolReaded, strWeekday, dtmTime)
GetPrice = ExtractPrice(colFiltered)
End Function
''' <summary>
''' 絞込処理を実行します。
''' </summary>
''' <param name="colTarget">フィルタ対象の PriceTable コレクション</param>
''' <param name="strWeekday">曜日</param>
''' <param name="dtmTime">時刻</param>
Private Function Filter( _
ByVal colTarget As Collection, _
ByVal strWeekday As String, _
ByVal dtmTime As Date)
Dim colResults As Collection: Set colResults = New Collection
Dim target As PriceTable
For Each target In colTarget
If Instr(target.mstrWeekday, strWeekday) > 0 And _
(target.mdtmFrom <= dtmTime And target.mdtmTo > dtmTime) Then
Call colResults.Add(target)
End If
Next target
Set Filter = colResults
End Function
''' <summary>
''' 絞り込まれた金額を返却します。
''' 結果が複数ある場合は、最初の料金を返却します。
''' 絞込結果が0件の場合は、0を返却します。
''' <param name="colTarget">金額取り出し対象の PriceTable コレクション</param>
''' <returns>料金</returns>
Private Function ExtractPrice( _
ByVal colTarget As Collection) As Long
ExtractPrice = 0
If colTarget.Count > 0 Then
ExtractPrice = colTarget(1).mlngPrice
End If
End Function
Public Function ToString() As String
Dim s As String
Dim v As PriceTable
For Each v In mcolReaded
s = s & _
v.mlngNo _
& ", " & v.mstrWeekday _
& ", " & v.mdtmFrom _
& ", " & v.mdtmTo _
& ", " & v.mlngPrice & vbCrLf
Next v
ToString = s
End Function
確認用データ、コード
以前と同じデータとなりますけれども、掲載いたします。
エクセル
次のエクセル表をマスタデータとして扱うことといたします。
- シート名: Sheet1
- 1行目もエクセルに含める。
- A1 セルから始まる。
| No | 曜日 | 時刻(以降) | 時刻(未満) | 料金 |
|---|---|---|---|---|
| 1 | 月,火,水,木,金 | 9:00:00 | 12:00:00 | 1000 |
| 2 | 月,火,水,木,金 | 13:00:00 | 18:00:00 | 2000 |
| 3 | 月,火,水,木,金 | 18:00:00 | 21:00:00 | 3000 |
| 4 | 土 | 9:00:00 | 12:00:00 | 1200 |
| 5 | 土 | 13:00:00 | 18:00:00 | 2200 |
| 6 | 土 | 18:00:00 | 21:00:00 | 3200 |
| 7 | 日 | 9:00:00 | 12:00:00 | 1500 |
| 8 | 日 | 13:00:00 | 18:00:00 | 2500 |
| 9 | 日 | 18:00:00 | 21:00:00 | 3500 |
VBA コード
Option Explicit
Public Sub Test()
Dim pt As PriceTable
Set pt = New PriceTable
Call pt.Init("Sheet1")
Debug.Print pt.ToString
Debug.Print "予想: 月、21:00 ⇒ 検索結果無しで0円。結果: " & pt.GetPrice("月", #9:00:00 PM#) & "円"
Debug.Print "予想: 月、10:15 ⇒ 1000円。結果: " & pt.GetPrice("月", #10:15:00 AM#) & "円"
Debug.Print "予想: 火、13:00 ⇒ 2000円。結果: " & pt.GetPrice("火", #1:00:00 PM#) & "円"
Debug.Print "予想: 火、12:00 ⇒ 2000円。結果: " & pt.GetPrice("火", #1:00:00 PM#) & "円"
Debug.Print "予想: 水、18:00 ⇒ 3000円。結果: " & pt.GetPrice("水", #6:00:00 PM#) & "円"
Debug.Print "予想: 木、9:00 ⇒ 1000円。結果: " & pt.GetPrice("木", #9:00:00 AM#) & "円"
Debug.Print "予想: 金、17:59 ⇒ 2000円。結果: " & pt.GetPrice("金", #5:59:59 PM#) & "円"
Debug.Print "予想: 土、20:59 ⇒ 3200円。結果: " & pt.GetPrice("土", #8:59:59 PM#) & "円"
Debug.Print "予想: 土、11:59 ⇒ 1500円。結果: " & pt.GetPrice("日", #11:59:59 AM#) & "円"
End Sub
結果
こちらも前回と同じ内容ですわ。
1, 月,火,水,木,金, 9:00:00, 12:00:00, 1000 2, 月,火,水,木,金, 13:00:00, 18:00:00, 2000 3, 月,火,水,木,金, 18:00:00, 21:00:00, 3000 4, 土, 9:00:00, 12:00:00, 1200 5, 土, 13:00:00, 18:00:00, 2200 6, 土, 18:00:00, 21:00:00, 3200 7, 日, 9:00:00, 12:00:00, 1500 8, 日, 13:00:00, 18:00:00, 2500 9, 日, 18:00:00, 21:00:00, 3500 予想: 月、21:00 ⇒ 検索結果無しで0円。結果: 0円 予想: 月、10:15 ⇒ 1000円。結果: 1000円 予想: 火、12:00 ⇒ 2000円。結果: 2000円 予想: 水、18:00 ⇒ 3000円。結果: 3000円 予想: 木、9:00 ⇒ 1000円。結果: 1000円 予想: 金、17:59 ⇒ 2000円。結果: 2000円 予想: 土、20:59 ⇒ 3200円。結果: 3200円 予想: 日、11:59 ⇒ 1500円。結果: 1500円
おわりに
最初は不要なプロパティはないかしら?と探すところからリファクタリングをスタートしておりました。
そのとき、関数型プログラミング入門についての投稿を
読んでいたものですから、少し取り入れてみましたの♪
コードが複雑になってしまった部分もございましたけれども、よりシンプルになったかと存じます。
以上です。
