Personsクラスの改良

Personsクラスの改良

前回

akashi-keirin.hatenablog.com

Personsクラスをちょこっとだけ改良する。

PersonsクラスのextractNamesメソッドは、その名のとおりPersonインスタンスNameプロパティの値だけを指定したセルを開始位置として転記するものだった。

これを、Personインスタンスが持つ三つのデータ(NameBirthPlaceBelongsTo各プロパティの値。)を転記するように改める。

Personsクラスのコードの修正

PersonsクラスのextractNamesメソッドの名前をextractDataとし、中身を次のように書き換える。宣言セクションに列挙体を追加した関係で、クラスモジュール全体を掲載する。

Personsクラス
Option Explicit

'Constants'
Private Enum PersonsData
  psdName = 1
  psdBirthPlace
  psdBelongsto
End Enum

'Module Level Variables'
Private items_ As New Collection

'Properties'
Public Property Get Items() As Collection
  Set Items = items_
End Property

'Methods'
Public Sub addItem(ByVal name__ As String, _
                   ByVal birthPlace__ As String, _
                   ByVal belongsTo__ As String)
  Dim newPerson As New Person
  Call newPerson.init(name__, birthPlace__, belongsTo__)
  Call items_.Add(newPerson)
End Sub

Public Sub removeItem(ByVal indexNumber As Long)
  Call items_.Remove(indexNumber)
End Sub

Public Sub extractData(ByVal targetLeftTop As Range)
  Const DATA_COUNT As Long = 3
  Dim i As Long
  Dim ar() As String
  ReDim ar(1 To items_.Count, 1 To DATA_COUNT)
  For i = 1 To items_.Count
    With items_(i)
      ar(i, psdName) = .Name
      ar(i, psdBirthPlace) = .BirthPlace
      ar(i, psdBelongsto) = .BelongsTo
    End With
  Next
  Dim targetRange As Range
  Set targetRange = targetLeftTop.Resize(items_.Count, DATA_COUNT)
  targetRange.Value = ar
End Sub

Personインスタンスの諸データを2次元配列に格納するForループ内で、2次元目のインデックスを指定するときにreadableになるように、列挙体PersonsDataを定義した。

あと、2次元目の上限値の指定がマジックナンバーになってしまうので、メソッド冒頭で定数(DATA_COUNT)にしている。

将来、Personクラスのプロパティが増えたときには、この値を変更すれば良い。

また、Personクラスのプロパティ数(データの種類)を、他のメソッド等で使用するような事態になったら、この定数をProcedure LevelからModule Levelにしたら良い。

実行

シート上のコマンドボタンに、次のプロシージャを登録して実行してみる。

M01ModuleMainモジュール
Private Sub testPersonClass()
  Dim i As Long
  With Sh01Master.NameList
    For i = 1 To .Rows.Count
      Call Persons.addItem(.Cells(i, sh01icName).Value, _
                           .Cells(i, sh01icBirthPlace).Value, _
                           .Cells(i, sh01icBelongsTo).Value)
    Next
    For i = 1 To Persons.Items.Count
      Call Persons.Items(i).introduceMyself( _
                           .Cells(i, sh01icEntranceSide).Value, _
                           .Cells(i, sh01icWrestlerRank).Value)
    Next
  End With
  Call Persons.extractData(Sh02Extracted.StartCell) '……(*)'
  Sh02Extracted.NameList.Borders.LineStyle = xlContinuous
  Set Persons = Nothing
End Sub

前回から変えたのは(*)のところだけ。変えたっつってもメソッド名の変更に追随しただけですけど。

オブジェクト指向の良いところは、このように呼び出し側を変更する必要がない、というところですね。

f:id:akashi_keirin:20190704080126g:plain

このとおり。

おわりに

まあ、同様のことはPersonオブジェクトの配列でも実現できるんですけど、データの抽出とか転記、といった処理をクラスの中に閉じ込めることができる、というのは結構なメリットかも。

抽出とか転記の処理を書くこと自体は簡単だけれど、毎回毎回となると結構めんどくさいんで。