独自のクラスに引数を直接渡すオブジェクトをどのように構築できますか?
このようなもの:
Dim this_employee as Employee
Set this_employee = new Employee(name:="Johnny", age:=69)
これができないのは非常に煩わしく、これを回避するための汚いソリューションになってしまいます。
独自のクラスに引数を直接渡すオブジェクトをどのように構築できますか?
このようなもの:
Dim this_employee as Employee
Set this_employee = new Employee(name:="Johnny", age:=69)
これができないのは非常に煩わしく、これを回避するための汚いソリューションになってしまいます。
これは私が最近使っているちょっとしたトリックで、良い結果をもたらします。VBAでよく戦わなければならない人たちと共有したいと思います。
1.-各カスタム クラスにパブリック開始サブルーチンを実装します。私はすべてのクラスでこれを InitiateProperties と呼んでいます。このメソッドは、コンストラクターに送信する引数を受け入れる必要があります。
2.- factoryと呼ばれるモジュールを作成し、「Create」という単語に加えてクラスと同じ名前、およびコンストラクターが必要とするのと同じ入力引数を使用してパブリック関数を作成します。この関数は、クラスをインスタンス化し、ポイント (1) で説明した開始サブルーチンを呼び出して、受け取った引数を渡す必要があります。最後に、インスタンス化および開始されたメソッドを返しました。
例:
カスタムクラス Employee があるとしましょう。前の例のように、名前と年齢でインスタンス化する必要があります。
これが InitiateProperties メソッドです。m_name と m_age は、設定するプライベート プロパティです。
Public Sub InitiateProperties(name as String, age as Integer)
m_name = name
m_age = age
End Sub
そして今、ファクトリモジュールで:
Public Function CreateEmployee(name as String, age as Integer) as Employee
Dim employee_obj As Employee
Set employee_obj = new Employee
employee_obj.InitiateProperties name:=name, age:=age
set CreateEmployee = employee_obj
End Function
そして最後に、従業員をインスタンス化する場合
Dim this_employee as Employee
Set this_employee = factory.CreateEmployee(name:="Johnny", age:=89)
複数のクラスがある場合に特に便利です。モジュールファクトリにそれぞれの関数を配置し、 factory.CreateClassA (arguments)、factory.CreateClassB(other_arguments)などを呼び出すだけでインスタンス化します。
stenci が指摘したように、コンストラクター関数でローカル変数を作成することを避けることで、より簡潔な構文で同じことを行うことができます。たとえば、CreateEmployee 関数は次のように記述できます。
Public Function CreateEmployee(name as String, age as Integer) as Employee
Set CreateEmployee = new Employee
CreateEmployee.InitiateProperties name:=name, age:=age
End Function
どちらがいいです。
各クラスのメンバーを呼び出すクラスごとFactory
に 1 つ (または複数)のコンストラクターを含む 1つのモジュールを使用します。Init
たとえば、Point
クラス:
Class Point
Private X, Y
Sub Init(X, Y)
Me.X = X
Me.Y = Y
End Sub
Line
クラス_
Class Line
Private P1, P2
Sub Init(Optional P1, Optional P2, Optional X1, Optional X2, Optional Y1, Optional Y2)
If P1 Is Nothing Then
Set Me.P1 = NewPoint(X1, Y1)
Set Me.P2 = NewPoint(X2, Y2)
Else
Set Me.P1 = P1
Set Me.P2 = P2
End If
End Sub
そしてFactory
モジュール:
Module Factory
Function NewPoint(X, Y)
Set NewPoint = New Point
NewPoint.Init X, Y
End Function
Function NewLine(Optional P1, Optional P2, Optional X1, Optional X2, Optional Y1, Optional Y2)
Set NewLine = New Line
NewLine.Init P1, P2, X1, Y1, X2, Y2
End Function
Function NewLinePt(P1, P2)
Set NewLinePt = New Line
NewLinePt.Init P1:=P1, P2:=P2
End Function
Function NewLineXY(X1, Y1, X2, Y2)
Set NewLineXY = New Line
NewLineXY.Init X1:=X1, Y1:=Y1, X2:=X2, Y2:=Y2
End Function
このアプローチの良い点の 1 つは、式の中でファクトリ関数を簡単に使用できることです。たとえば、次のようなことが可能です。
D = Distance(NewPoint(10, 10), NewPoint(20, 20)
また:
D = NewPoint(10, 10).Distance(NewPoint(20, 20))
それはきれいです: ファクトリはほとんど何もせず、すべてのオブジェクトで一貫して行います。作成と各CreatorInit
の 1 つの呼び出しだけです。
そして、かなりオブジェクト指向ですInit
。関数はオブジェクト内で定義されます。
編集
これにより静的メソッドを作成できることを付け加えるのを忘れていました。たとえば、次のようなことができます (パラメータをオプションにした後):
NewLine.DeleteAllLinesShorterThan 10
残念ながら、オブジェクトの新しいインスタンスが毎回作成されるため、静的変数は実行後に失われます。行のコレクションと、この疑似静的メソッドで使用されるその他の静的変数は、モジュールで定義する必要があります。
別のアプローチ
クラス clsBitcoinPublicKey を作成するとします。
クラス モジュールで、実際のコンストラクターの動作を希望するように動作する ADDITIONAL サブルーチンを作成します。以下では、ConstructorAdjunct と名付けました。
Public Sub ConstructorAdjunct(ByVal ...)
...
End Sub
From the calling module, you use an additional statement
Dim loPublicKey AS clsBitcoinPublicKey
Set loPublicKey = New clsBitcoinPublicKey
Call loPublicKey.ConstructorAdjunct(...)
唯一のペナルティは余分な呼び出しですが、クラス モジュールにすべてを保持できるという利点があり、デバッグが容易になります。