(for Internet Explorer)
← ▼ ▲
↑
get_ModuleConsts : クラスの定数 (vbsool)
定数は、静的オブジェクトのメンバー変数に格納します。
定数シンボルが、グローバル・スコープのシンボルではなくなるので、名前の衝突の可能性が
低くなります。
Class ClassA
Public c
Private Sub Class_Initialize()
Set Me.c = get_ClassAConsts()
End Sub
End Class
'********************************************************************************
' <<< [get_ClassAConsts] >>>
'********************************************************************************
Dim g_ClassAConsts
Function get_ClassAConsts()
If IsEmpty( g_ClassAConsts ) Then _
Set g_ClassAConsts = new ClassAConsts
Set get_ClassAConsts = g_ClassAConsts
End Function
Class ClassAConsts
Public CutTag, ExistOnly
Private Sub Class_Initialize()
CutTag = 1
ExistOnly = 2
End Sub
End Class
定義例：
使用例１：
Dim c : Set c = get_ClassAConsts()
copy_ex src, dst, c.CutTag
c.CutTag
get_ClassAConsts
CutTag
CutTag
ver2 候補
使用例２：
Sub main()
Dim obj : Set obj = new ClassA
copy_ex src, dst, obj.c.CutTag
End Sub
obj.c.CutTag
get_ClassAConsts
→ 名前空間の汚染の対策
未確認
参考
← ▼ ▲
多くの場合、クラスに所属しない関数の中の最初で get_Object した後で、Validate メソッド
を呼び出します。 Validate は、パラメータに指定した状態にオブジェクトをするメソッドです。
Sub FuncA()
Dim m : Set m = get_ClassA() : m.Validate Empty
m.MethodA
End Sub
演算器的なオブジェクトとは、インスタンスを特定する必要が無いオブジェクトのことで、
切り替えることはあっても同時に複数存在しなくても目的の出力が得られるものです。
ユーザーは演算器の種類 (ClassV) を指定します。
ClassV_validate で取得したオブジェクトを明示的に削除する必要はありません。
明示的に削除を指定したり、削除する許可をしたりする ClassI のメンバ関数を作っても
構いませんが、キャッシュのように、状況に応じて自動的に判断することが処理効率が
良いこともあります。
Dim g_obj as ClassI
インターフェイスを
参照する変数
ClassI
オブジェクトの
インターフェイス
オブジェクト（アトム）
ClassA
get_Object 関数
オブジェクトを操作するインターフェイス(ClassI）は、演算器の種類(ClassV)と異なることが
あります。 さらに ClassV は、インスタンスのクラス(ClassA)と異なることもあります。
たとえば、ClassI =コンパイラ、ClassV = C言語コンパイラ、ClassA = A社製コンパイラver2。
状況や設定に応じて、適切な ClassA のインスタンスが返ります。 内部で、インスタンスが
生成されるかもしれないし、引数をそのまま維持するだけかもしれません。基本的に
インスタンスは１つ（シングレトン）ですが、マルチコアを生かしたり、マルチスレッドでレイテ
ンシを短くするために、Opt 引数に、新規インスタンスを指定することがあるかもしれません。
（VBScript は、基本的にシングルスレッドですが）
演算器的なオブジェクトのライフサイクル
→ グローバル・テスト・オブジェクト, SampleTest
ライブラリ・オブジェクト、演算器的なオブジェクト
参考
[ 親: vbsool : オブジェクト記述法 ]
→ バージョン判定、環境変数
← ▼ ▲
バージョンを表す静的オブジェクト
プログラムが使用する外部プログラムのバージョンが異なると、使用する
データが微妙に異なったりします。 たとえば、Visual Studio のプロジェクト・
ファイルを出力するプログラムは、Visual Studio のバージョンによって、
出力するファイルの拡張子が変わります。
プロジェクト・ファイルを出力する関数をプログラミングするときは、
バージョンを判定して、出力内容を変えるというのが一般的ですが、
規模が大きくなると、同じ条件分岐のコピーがたくさん記述されること
になり、メンテナンス性が低くなります。
たとえば、プロジェクト・ファイルの拡張子が変わると、ファイルを作成する
コードと、使用するプロジェクト・ファイルをソリューション・ファイル内に
記述するコードの２箇所に、バージョンを判定するコードが記述されます。
この状態で、将来、バージョンと拡張子の関係が変わったら、２箇所の修正が
必要なのに、１箇所だけ修正して完了としてしまうリスクがあるのです。
Dim o : Set o = new MakeVS
o.SetMakeProjContext MakeProjContext, get_MakeVSProjType( TypeName )
o.MakeProj
Class　MakeVSProjType
Public　VSVer　　　　　　 '// as integer
Public　TargetPlatform　　'// as string
Public　ProjectExtension　'// as string
End Class
Function　get_MakeVSProjType( TypeName )
Dim　ret, items
Select Case　TypeName　　　　　　　　'// VSVer, TargetPlatform
Case　"VS2010Win32"　　: items = Array( 2010, "Win32" )
Case　"VS2008Win32"　　: items = Array( 2008, "Win32" )
Case　"VS2010Win32Lib" : items = Array( 2010, "Lib" )
Case　"VS2008Win32Lib" : items = Array( 2008, "Lib" )
Case Else　Error
End Select
Set ret = new MakeVSProjType
ret.VSVer　　　　　= items( 0 )
ret.TargetPlatform = items( 1 )
If ret.VSVer = 2010 Then
ret.ProjectExtension = ".vcxproj"
Else
ret.ProjectExtension = ".vcproj"
End If
End Function
これを避けるには、プロジェクト・ファイルの拡張子を変数にすることです。
この状態で、バージョンと拡張子の関係が変わったら、変数の値を代入する
箇所だけを変えるだけで済みます。
このような違いを集めたオブジェクトは、Visual Studio のバージョンによって
異なるものであるため、バージョンごとに存在する静的オブジェクト（コンパ
イル時に値が決定する static な構造体）になります。
そして、静的オブジェクトを取得する関数を定義するとよいでしょう。 その
定義は、下記のようにテーブルで記述するとよいでしょう。 また、相関関係が
ある場合は、下記の ProjectExtension 変数のように条件分岐が使えます。
この条件分岐は、静的オブジェクトを取得する関数の中にまとめられるため、
メンテナンス性が高くなります。
If VSVer <= 2008 Then f.Open ".vcproj" Else f.Open ".vcxproj"
f.Close
f.Open ".sln"
If VSVer <= 2008 Then f.Write ".vcproj" Else f.Write ".vcxproj"
← ▼ ▲
参考
→ Factory Methodパターン／Abstract Factoryパターン (Web)
[ 親: vbsool : オブジェクト記述法 ]
→ 名前の一覧
→ オブジェクトの Name と TrueName
Name プロパティ : 名前参照 (vbsool)
→ T_NameDelegator フォルダ
サンプルファイル
→ T_NameList フォルダ
→ Name と TrueName が多対１の場合
→ T_Name フォルダ
Name と TrueName が、１対多の場合
Name と TrueName が、多対１の場合
Name と TrueName が、多対１の場合の一覧
Property Get Name() as string
→ vbslib を使う vbsool サンプル
インスタンスの名前です。 クラス名と同じになることもあります。
Property Get TrueName() as string
get_Object
関数に指定する名前と同じです。
以下は、一般名 (Name) と正式名 (TrueName) の違いから生じる問題の対策法です。
→ Module Mixer 3 の実装
← ▼ ▲
SetVar,
GetVar など）に正式名を指定することもできます。
オブジェクトの Name と TrueName
クラス名やインスタンス名は、一般名と正式名があり、多くの場合、一般名を必要とします。しかし、
new に指定する型の名前や、TypeName で取得できる型の名前はクラスの正式名であることが
多く、扱いにくいでしょう。 そこで、
[ 親: vbsool : オブジェクト記述法 ]
Sample_getTrueName
get_Object
処理フロー
get_TrueSample
一般名は場面によって（抽象度が変化して）変わります。 正式名はインスタンスの内容や定義の
抽象度によって変わります。 一般名と正式名が、同じになることもあります。
一般名と正式名は、１対多の関係があるので、場面に応じて、一般名から正式名を選択する必要
があります。（同時に多対１の関係もありますが別の章を参照）。
多くの場合、自動判定を行いますが、環境変数（レジストリや、設定ファイルや、vbslib の
( "Sample" )
new TrueSample
一般名 "Sample" のオブジェクトを取得する
get_Sample
'// Class Sample has_interface_of ClassI
Function get_Sample()
Set get_Sample = get_Object( Sample_getTrueName() )
get_Sample.Name = "Sample"
End Function
Function Sample_getTrueName()
Dim ret : ret = GetVar( "Sample" )
If IsEmpty( ret ) Then
'// default is ClassA fixed
ret = "TrueSample" : SetVar "Sample", ret
End If
Sample_getTrueName = ret
End Function
'// 言語上の Class Sample の定義は不要です。
GetVar
一般名(Sample)のクラス定義 (一般名と正式名が１対多だけの場合）
一般名 "Sample" から正式名 "TrueSample" を選択
( "TrueSample" )
get_Object
上記は ret = "TrueSample" 固定ですが、場面に応じて TrueSample 以外の正式名を
返すように自動判定した方がよいです。
Name プロパティは、インスタンスの一般名とします。
TrueName プロパティは、インスタンスの正式名とします。
'// Class TrueSample has_interface_of ClassI
Dim g_TrueSample
Function get_TrueSample() '// has_interface_of ClassI
If IsEmpty( g_TrueSample ) Then _
Set g_TrueSample = new TrueSample
Set get_TrueSample = g_TrueSample
End Function
Class TrueSample
Public Name
Public Property Get TrueName() : TrueName = TypeName(Me) : End Property
'--- Name is factory pattern.
Private Sub Class_Initialize() : Name = TypeName(Me) : End Sub
:
End Class
正式名(TrueSample)のクラス定義 (一般名と正式名が１対多だけの場合）
ClassI
ClassB
ClassI
ClassA
Name = "ClassN", TrueName = "ClassA"
Name = "ClassN", TrueName = "ClassB"
データ構造
→ T_Name フォルダ
サンプルファイル
一般名で選択
例： Windows
例： Windows XP, Windows7
正式名 "TrueSample" のオブジェクトを取得する
[Sample]
[Sample]
[TrueSample]
[TrueSample]
→ T_Name_vbslib フォルダ
→ T_NameAdd_vbslib フォルダ
← ▼ ▲
Dim g_NameDic : Set g_NameDic = CreateObject( "Scripting.Dictionary" )
Function get_NameDelegator( Name, TrueName, InterfaceName )
If g_NameDic.Exists( Name +"__"+ TrueName ) Then
Set get_NameDelegator = g_NameDic.Item( Name +"__"+ TrueName +"_"+ InterfaceName )
Exit Function
End If
Set get_NameDelegator = new_X( InterfaceName + "_Delegator" ) : With get_NameDelegator
.Name = Name
.m_Delegate = TrueName '// if validated was need.
If not g_bNeedValidateDelegate Then _
Set .m_Delegate = get_Object( TrueName ) '// if validated was not need.
End With
Set g_NameDic.Item( Name +"__"+ TrueName +"_"+ InterfaceName ) = get_NameDelegator
End Function
Class NameDelegator '// defined_as_interface
Public Name
Public Property Get TrueName() : TrueName = NameDelegator_getTrueName( Me ) : End Property
Public m_Delegate ' as ClassA or ClassB or string(before validated)
Public Property Get DefineInfo() : Set DefineInfo = m_Delegate.DefineInfo : End Property
End Class
NameDelegator のクラス定義
複数から同じインスタンスを参照し、オブジェクトから一般名（Nameプロパティ）を取得する必要が
ある場合は、一般名と正式名が多対１の関係になり、次のような委譲をしないと、Name プロパティ
がそれぞれの場面に応じた一般名になりません。
'// Class Sample has_interface_of ClassI
Function get_Sample()
Set get_Sample = get_NameDelegator( "Sample", Sample_getTrueName(), "ClassI" )
End Function
Function Sample_getTrueName()
Dim ret : ret = GetVar( "Sample" )
If IsEmpty( ret ) Then
'// default is ClassA fixed
ret = "TrueSample" : SetVar "Sample", ret
End If
Sample_getTrueName = ret
End Function
GetVar
'// Class ClassA has_interface_of ClassI
Dim g_TrueSample
Function get_TrueSample()
If IsEmpty( g_TrueSample ) Then _
Set g_TrueSample = new TrueSample
Set get_TrueSample = g_TrueSample
End Function
Class TrueSample
Public Property Get Name() : Name = TypeName(Me) : End Property
Public Property Get TrueName() : TrueName = TypeName(Me) : End Property
'--- Name is factory pattern.
Public Value
Public Function Method1() : Method1 = "TrueSample.Method1" : End Function
End Class
一般名(Sample)のクラス定義 (一般名と正式名が多対１もある場合）
正式名(TrueSample)のクラス定義
get_NameDelegator
Name プロパティは、ユーザーが取り扱っている場面（ドメイン）によって抽象度が変化して、同じ
インスタンスに対して複数の一般名を持つことになります。 このケースに対応する実装は委譲の
形態をとるとよいでしょう。
他のドメインの名前を参照する必要は、ほとんどありませんが、もし参照するのであれば、Names
という集合のプロパティになります。
場面Aの関数
オブジェクトの削除は、ガーベジコレクションに任せて、ClassI_Delegator が無くなるまで存在させ
るとよいでしょう。
実体のファイルが削除されたショートカットのように、ClassI_Delegator が参照する、正式名の
オブジェクトだけを無くすときは、一般名から委譲先を参照している ClassI_Delegator::m_Delegate
を Empty にしてガーベジコレクションを動かして削除します。 また、Empty にすれば、削除された
オブジェクトにアクセスしようとしたときに、きちんと例外が発生するようになります。
Name 以外は
参照
場面Aでの Name
場面Bでの Name
ある１つのインスタンス
TrueName
（正式名）
ClassI_Delegator クラス
（一般名）
Name と TrueName が多対１の場合
Sample_getTrueName
get_Object
処理フロー
( "Sample" )
一般名 "Sample" のオブジェクトを取得する
一般名 "Sample" から、正式名 "TrueSample" を選択
get_NameDelegator
new_ClassI_Delegator
new ClassI_Delegator
new TrueSample
If not g_NameDic.Exists( Name +"__"+ TrueName +"_"+ InterfaceName ) Then
InterfaceName インターフェイスを持ち、
TrueName へ委譲するオブジェクトを生成
正式名のオブジェクトを生成する
サンプルファイル
→ T_NameDelegator フォルダ
[Sample]
[Sample]
[TrueSample]
場面Bの関数
委譲
get_Sample
データ構造
g_NameDic
Dictionary
ClassI_Delegator
.Item
.Key
string
= Name +"__"+ TrueName +"_"+ InterfaceName
.Name
.m_Delegate
string
TrueSample
= "Sample"
ClassI
→ get_NameDelegator (vbslib)
参考
ClassI_Delegator クラス定義
new_X
( InterfaceName + "_Delegator" )
( Name, TrueName, InterfaceName )
ClassI
.Name = Name
Set .m_Delegate = get_Object( TrueName )
Public Property Get DefineInfo() : Set DefineInfo = m_Delegate.DefineInfo : End Property
DefineInfo プロパティは、オプションです。
→ DefineInfo プロパティ
get_Object
get_TrueSample
Class ClassI_Delegator '// has_interface_of NameDelegator and ClassI
Public Name
Public Property Get TrueName() : TrueName = NameDelegator_getTrueName( Me ) : End Property
Public m_Delegate ' as ClassA or ClassB or string(before validated)
'--- Name is factory pattern.
Public Property Let Value( v ) : m_Delegate.Value = v : End Property
Public Property Get Value( ) : Value = m_Delegate.Value : End Property
Public Function Method1() : Method1 = m_Delegate.Method1() : End Function
End Class
Function new_ClassI_Delegator() '// has_interface_of NameDelegator and ClassI
Set new_ClassI_Delegator = new ClassI_Delegator
End Function
[ClassI_Delegator]
NameDelegator
一般名を持ったオブジェクト
正式名を持ったオブジェクト
→ T_NameDelegator_vbslib フォルダ
例： Windows
例： Windows7
例： Windows7
← ▼ ▲
名前の一覧
オブジェクトの名前を一覧するときは、
取得して、Name プロパティを表示します。 TrueName は、必要なら補助的に表示します。
Sub ClassI::Validate( Opt as variant )
ただし、すべてのオブジェクトを生成すると時間がかかる場合、生成時に実行する初期化処理
(Class_Initialize) を Validate メソッドに移すとよいでしょう。
get_ObjectsFormFile
で一覧するすべてのオブジェクトを
Dim samples, sample
get_ObjectsFromFile "Lib\*_obj.vbs", "ClassI", samples '// [out] samples
For Each sample In samples : echo sample.Name : Next
一覧するときは、一般名が Name プロパティに入っているオブジェクトと、正式名が Name
プロパティに入っているオブジェクトの両方を一覧します。
→ T_NameList フォルダ
→ T_NameList_vbslib フォルダ
サンプルファイル
← ▼ ▲
Item デフォルト・プロパティ : 動的定義メンバー (vbsool)
Default Property Item( Name as string ) as variant
VBScript は、ECMA Script (JavaScript) のように、動的にメンバーを定義することはできませんが、
デフォルト・プロパティと、辞書（Dictionary クラス）を使うことで、同様のことができます。
→ JavaScript のクラス
参考
→ Dictionary クラス
→ Items プロパティ
Item プロパティは、Dictionary や FolderItem などに準拠しています。
ArrayClass(vbslib) も、Item プロパティが使えます。
→ T_Item フォルダ
サンプル：
Dim obj : Set obj = new ClassA
obj.PropA = 1 '// Static defined property
obj("PropB") = 12 '// Dynamic defined property
obj("PropC") = "ABC"
Set obj("PropD") = new ClassA
WScript.Echo "PropA = "& obj.PropA
WScript.Echo "PropB = "& obj("PropB")
WScript.Echo "PropC = "& obj("PropC").Value
使用例：
Class ClassA
Public PropA '// Static defined property
'//=== Dynamic defined property : Item, Items, Keys
Public Default Property Get Item( Name ) : LetSet Item, m_Dic( Name ) : End Property
Public Property Let Item( Name, Value ) : m_Dic( Name ) = Value : End Property
Public Property Set Item( Name, Object ) : Set m_Dic( Name ) = Object : End Property
Public Property Get Keys() : Keys = m_Dic.Keys : End Property
Public Property Get Items() : Items = m_Dic.Items : End Property
Public m_Dic ' as Dictionary
Private Sub Class_Initialize()
Set m_Dic = CreateObject( "Scripting.Dictionary" )
m_Dic.CompareMode = 1 '// NotCaseSensitive
End Sub
End Class
Sub LetSet( Out, In_ )
If IsObject( In_ ) Then Set Out = In_ Else Out = In_
End Sub
定義例： Item, Items, Keys プロパティがあるクラスの定義
vbslib なし版
関連
→ Keys プロパティ
→ T_Item_vbslib フォルダ
vbslib 使用版
→ GetSetting 関数
ver2 候補
← ▼ ▲
Items プロパティ : 動的定義メンバーの値の集合 (vbsool)
Property Get Items() as array of variant
For Each item In obj.Items
If IsObject( item ) Then
WScript.Echo item.Value
Else
WScript.Echo item
End If
Next
使用例：
→ Item プロパティ
サンプル
上記は標準形ですが、処理速度が要求されるときは次のようにしてください。
For Each item In obj.m_Dic.Items
← ▼ ▲
Keys プロパティ : 動的定義メンバーのメンバー名の集合 (vbsool)
Property Get Keys() as array of string
For Each name In obj.Keys
WScript.Echo name
Next
使用例：
→ Item プロパティ
サンプル
上記は標準形ですが、処理速度が要求されるときは次のようにしてください。
For Each item In obj.m_Dic.Keys
← ▼ ▲
EventResponders : イベント応答 (vbsool)
→ FuncRedir_add (vbslib)
関連
→ １つの登録された関数を呼び出す変数、デリゲート
関数定義のオーバーライド
書きかけ
Dim ClassE::OnEventX as EventResponders
イベントとは、あるオブジェクトの状態変化のことです。
イベントが発生したときに行う処理は、アプリケーションによって異なります。
そこで、あるイベントが発生したときに行う処理を関数に記述して、その関数をオブジェクトに
登録しておくことで、必要なときに必要な処理ができるようになります。
他の言語では、関数ポインタ、コールバック関数、メソッドポインタなどと呼ばれています。
定義： イベントごとに、メソッドを登録できるメンバー変数を宣言する
ver2 候補
→ 定義： イベントごとに、メソッドを登録できるメンバー変数を宣言する
Class ClassE
Public OnEventX ' as EventResponders
Private Sub Class_Initialize()
Set Me.OnEventX = new EventResponders
End Sub
End Class
Sub ClassA::OnEventX( Caller as ClassE, Args as variant )
登録： コールバックされるメソッドを、メンバー変数に登録する
Sub main()
Dim obj : Set obj = new ClassE '// defined by Library
Dim app : Set app = new ClassA '// defined by Application
app.RespondFromClassE obj
obj.Run '// call ClassA::OnEventX
End Sub
Class ClassA
Public Sub RespondFromClassE( Caller )
Caller.OnEventX.Add GetRef( "ClassA_onEventX" ), Me
End Sub
Public Sub OnEventX( Caller, Args )
WScipt.Echo "Responded"
End Sub
End Class
Sub ClassA_onEventX( Me_, Caller, Args ) : Me_.OnEventX( Caller, Args ) : End Sub
呼び出し： イベントが発生したら、登録されているメソッドを呼び出す
Class ClassE
Public OnEventX ' as EventResponders
Public Sub Run()
Me.OnEventX.Calls Me, Empty
End Sub
End Class
OnEventX
app
ClassA_onEventX
→ 登録： コールバックされるメソッドを、メンバー変数に登録する
obj
Responded
OnEventX
OnEventX
→ 呼び出し： イベントが発生したら、登録されているメソッドを呼び出す
複数のメソッドが登録されているときは、Calls メソッドを１度呼び出すだけで、複数の
メソッドが呼び出されます。
→ イベント応答の実装方法の考察
→ EventResponders の実装例 (vbslib なし版）
→ イベント関数とパラメータ取得関数 （C言語）
OnEventX
→ ＠IT：VB.NETプログラミング　第25回 イベントとイベント・ハンドラ (Web)
参考
→ CallForEach (vbslib)
関数を複数回呼び出す
→ イベント(C#)
イベントが発生したオブジェクトのメソッドから、イベントに応答するオブジェクトのメソッドを
呼び出すコードを、通常、ライブラリが書きます。
イベントが発生したらコールバックされるメソッドを、イベントが発生するオブジェクトに登録
するコードを、通常、アプリケーションが書きます。
通常、ライブラリにあるクラスが、イベントの定義とメソッドの呼び出しを行い、アプリケーション
が、イベントに応答するメソッドの定義と、そのメソッドの登録を行います。
通常、ライブラリにあるクラスが、イベントを定義します。
ライブラリの中 （イベント発生元）
アプリケーション
呼び出し
アプリケーションが定義する ClassA クラスが応答する場合：
アプリケーションが定義する OnEventX 関数が応答する場合：
Sub main()
Dim obj : Set obj = new ClassE
obj.OnEventX.Add GetRef( "OnEventX" ), Empty
obj.Run '// call OnEventX
End Sub
Sub OnEventX( Dummy, Caller, Args )
WScipt.Echo "Responded"
End Sub
Responded
OnEventX
OnEventX
OnEventX
OnEventX
Add
EventResponders
Add
Calls
→ T_Item フォルダ
サンプル：
vbslib なし版
→ T_Item_vbslib フォルダ
vbslib 使用版
書きかけ
OnEventX
→ （vbslib 使用版）
←
↓