クラス変数っぽいものを実現してみる
クラス変数っぽいものを実現してみる
Attribute VB_PredeclaredId
をTrue
にしたクラスモジュールでちょっと実験をしてみた。
実験用クラス
実験用に、Rahmen
クラスを作成。
こちらの記事にインスパイヤされたでござる。
クラスモジュール Rahmen
Option Explicit '///Attribute VB_PredeclaredId = True///' Public Enum NoodleSolidity nsYugeTooshi nsKonaOtoshi nsHarigane nsBariKata nsKata nsFutsuu nsYawa nsZundare End Enum Private count_ As Long Private solidity_ As String Public Property Get Solidity() As String Solidity = solidity_ End Property Public Property Let Count(ByVal value_ As Long) count_ = value_ End Property Public Property Get Kaedama() As String Kaedama = CStr(count_) & "玉目" End Property Private Sub Class_Initialize() solidity_ = "ふつう" End Sub Public Sub setSolidity(ByVal solidityArg As NoodleSolidity) solidity_ = getSolidityString(solidityArg) End Sub Private Function getSolidityString( _ ByVal arg As NoodleSolidity) As String Dim ret As String Select Case arg Case nsYugeTooshi: ret = "湯気とおし" Case nsKonaOtoshi: ret = "粉落とし" Case nsHarigane: ret = "ハリガネ" Case nsBariKata: ret = "バリカタ" Case nsKata: ret = "カタ" Case nsFutsuu: ret = "ふつう" Case nsYawa: ret = "やわ" Case nsZundare: ret = "ずんだれ" Case Else: ret = "ち~んw" End Select getSolidityString = ret End Function Public Function getInstance( _ ByVal solidity__ As NoodleSolidity) As Rahmen Dim ret As New Rahmen Call ret.setSolidity(solidity__) count_ = count_ + 1 ret.Count = count_ '……(*)' Set getInstance = ret End Function
例によって、Attribute VB_PredeclaredId
をTrue
にしている。
NoodleSolidity
という列挙体をPublic
で宣言しているので、このクラスモジュールをインポートしたプロジェクトでは、この列挙体を使用することができる。
基本的に、getInstance
メソッド内でsetSolidity
メソッドに渡すための引数に用いる。
setSolidity
メソッドからは、getSolidityString
メソッドを呼んで、〈麺のかたさ〉を表す文字列を取得する。一番かたい「湯気とおし」から一番やわらかい「ずんだれ」まで、無駄にヴァリエーション豊富にしたw
Solidityプロパティ
変数solidity_
の内容を返すだけ。
変数solidity_
に値をセットするのは、デフォルトのコンストラクタであるClass_Initialize
か、インスタンスメソッドのsetSolidity
(とそこから呼ばれるgetSolidityString
メソッド)のみ。
setSolidity
にNoodleSolidity
列挙体のメンバを引数として渡すと、対応する〈麺のかたさ〉を表す文字列を取得して変数solidity_
にセットする。
Kaedamaプロパティ
変数count_
に入っている数値を文字列に変換し、「玉目」を附加した文字列を返す。
実は、getInstance
メソッドをRahmen.getInstance
の形で呼び出したとき、メソッド内部の変数count_
には、Rahmen
内部の(インスタンスのものでない)変数count_
の値が入っている。
この性質を生かして、クラス変数的なことができないものか、と考えたわけです。
そこで、getInstance
メソッドの(*)のところ、
ret.Count = count_
とした。
こうすることで、Rahmen
が持っているcount_
の数値をインスタンスが持っている変数count_
にセットするのだ。
逆にいえば、ret
のCount
プロパティにセットする、という形にしないと、インスタンス内部のcount_
を変更できないらしい。
実は、このことが大問題の原因になる。後述する。
とりあえず使ってみる
標準モジュールに次のコードを書いて使ってみる。
リスト1 標準モジュール
Public Sub disposable01() Dim rahmen1 As Rahmen Set rahmen1 = Rahmen.getInstance(nsKonaOtoshi) Dim rahmen2 As Rahmen Set rahmen2 = Rahmen.getInstance(nsBariKata) Dim rahmen3 As Rahmen Set rahmen3 = Rahmen.getInstance(nsZundare) Call printData(rahmen1) Call printData(rahmen2) Call printData(rahmen3) Debug.Print Rahmen.Kaedama End Sub Private Sub printData(ByVal targetRahmen As Rahmen) With targetRahmen Debug.Print "替え玉:" & .Kaedama; _ "/麺のかたさ:" & .Solidity End With End Sub
見ておわかりのとおり、rahmen1
、rahmen2
、rahmen3
の三つのRahmen
型変数を準備し、それぞれRahmen.getInstance
メソッドでインスタンス化する。
あとは、printData
メソッドを用いて、それぞれのKaedama
プロパティとSolidity
プロパティ、すなわち〈麺のかたさ〉を表示し、最後にRahmen
オブジェクト自体のKaedama
プロパティを表示しておしまい。
実行結果
一回目。
二回目。
一応、意図どおりの結果が出ている。
クラス内の変数count_
が、クラス変数のような働きをしている。
大問題
〈麺のかたさ〉を設定するsetSolidity
メソッドはともかく、Property Let Count
がPublic
だというのは非常にまずい。
count_
が外部から自在に書き換えられてしまうからである。
あと、setSolidity
メソッドにしても、単独でこのメソッドを実行するだけなら、Rahmen
内部の変数count_
は変化しないので、おかしなことになる。
おわりに
まだまだ解決せねばならんことが多い……。