我有一个库(外接程序),其中包含一个在一些小型应用程序中使用的类。我想为该类提供一个Save
方法,
将取决于正在运行的应用程序。
为了解决这个问题,我试图使用一种策略模式(我可能会误解该模式),但是我对该主题缺乏理解。在运行时,我提供了一个策略类来处理保存。公共类公开了Save
方法,该方法将其中继到提供的策略类。但是为了保持一致性,在我看来,通用类也必须实现策略接口。
IRecord(通用类)接口:
Public Function DoSomething(): End Function
Public Function SetStrategy(ByVal Strategy As IDatabaseStrategy): End Function
记录(公共类)实现:
Private RecordStrategy As IDatabaseStrategy
Implements IRecord
Implements IDatabaseStrategy 'Implements this interface to have Save method
Private Function IRecord_DoSomething():
'does whatever the class is supposed to do
End Function
Private Function IRecord_SetStrategy(ByVal Strategy As IDatabaseStrategy)
Set RecordStrategy = Strategy
End Function
Private Function IDataBaseStrategy_Save()
RecordStrategy.Save
End Function
战略接口和实施:
IDatabaseStrategy:Public Function Save():End Function
DataBaseStrategyA:
Implements IDatabaseStrategy
Private Function IDataBaseStrategy_Save()
Debug.Print "Saving to database A"
End Function
DataBaseStrategyB:
Implements IDatabaseStrategy
Private Function IDataBaseStrategy_Save()
Debug.Print "Saving to database B"
End Function
应用程序模块:
Option Explicit
Public Sub ApplicationA()
Dim Item As IRecord
Set Item = New Record
Dim Strategy As IDatabaseStrategy
Set Strategy = New DatabaseStrategyA
Item.SetStrategy Strategy 'this would normally be done with constructor
Dim ItemToSave As IDatabaseStrategy
Set ItemToSave = Item
ItemToSave.Save
End Sub
Public Sub ApplicationB()
Dim Item As IRecord
Set Item = New Record
Dim Strategy As IDatabaseStrategy
Set Strategy = New DatabaseStrategyB
Item.SetStrategy Strategy 'this would normally be done with constructor
Dim ItemToSave As IDatabaseStrategy
Set ItemToSave = Item
ItemToSave.Save
End Sub
使用这种方法,我必须Record
实现Database strategy
才能拥有Save
方法,然后将Item
从IRecord
重铸到IDatabaseStrategy
到用它。我认为我使用的模式不正确,所以我的问题是-如何为DatabaseStrategy
提供Record
以便不必重铸对象,并且可能无需实现IDatabaseStrategy
在Record
中?
我考虑过的替代方法:
DatabaseStrategy
包裹在Record
和应用程序(Record
)专用的DatabaseStrategy.Create(Record).Save
周围DatabaseStrategy
公开为Record
的成员,但随后看来应用程序必须知道DatabaseStrategy
是记录(Record.DatabaseStrategy.Save
)的成员。答案 0 :(得分:1)
这是design-patterns
和VBA
上的一个很好的问题。
here可以看到strategy pattern
的完整描述,但总而言之,这是描述它的UML类和序列图:
基本上,此策略使算法可以独立于使用该算法的客户端而变化。
将使用哪种算法的决定推迟到运行时,才能使调用代码更加灵活和可重用。
您提出了这两种解决方案,我想解释一下为什么我不使用它们:
DatabaseStrategy
)的记录周围包裹DatabaseStrategy.Create(Record).Save
使用此解决方案将减少cohesion,因为
class
DatabaseStrategy必须考虑实例化Record
objects
(正如我稍后展示的那样,可以做到这一点应用Factory-Pattern
)
DatabaseStrategy
公开为记录的成员,但是看来应用程序必须知道DatabaseStrategy
是记录的成员(Record.DatabaseStrategy.Save
)
此设计模式必须了解策略,但创新之处在于,它可以在运行时更改,并传递实现操作方法的期望策略对象。在这种情况下,我会将
DatabaseStrategy
从Record
移开,因为最后提到的是需要保存的object
,但是执行动作的不是代理人(可能是Database
class
,我将在后面显示)。
为解决如何使用不接受参数的VBA objects
构造函数实例化此class
的问题,我使用了另一种模式:Factory Pattern。
下面的代码仅用于说明如何使用这两种模式,因此省略了许多功能,并且没有真正实现数据库方法的方法。现在,剩下的代码如下:
IRecord
class
(接口):
Public Function getValue() As String: End Function
Public Function setValue(stringValue As String): End Function
记录
class
:
此类基本上表示数据库记录。为简单起见,我们只有一个value
属性,但是实际的实现当然会有所不同。
Implements IRecord
Private value As String
Private Function IRecord_getValue() As String
IRecord_getValue = value
End Function
Private Function IRecord_setValue(stringValue As String)
value = stringValue
End Function
IConnectionStrategy
class
(接口)
这是“连接接口”策略。此处的代码几乎没有变化。
Public Function Save(ByVal record As IRecord): End Function
ConnectionStrategyA
class
策略A的类别。此处的代码几乎没有变化。
Implements IConnectionStrategy
Private connectionString As String
Private Sub Class_Initialize()
connectionString = "DRIVER=Oracle Server;SERVER=myA.server.com\DatabaseA;"
End Sub
'Implements Strayegy A
Private Function IConnectionStrategy_Save(ByVal record As IRecord)
Debug.Print "Saving to ", connectionString, "Record with value:", record.getValue
End Function
ConnectionStrategyB
class
策略A的类别。此处的代码几乎没有变化。
Implements IConnectionStrategy
Private connectionString As String
Private Sub Class_Initialize()
connectionString = "DRIVER=SQL Server;SERVER=myB.server.com\DatabaseB;"
End Sub
'Implements Strategy B
Private Function IConnectionStrategy_Save(ByVal record As IRecord)
Debug.Print "Saving to ", connectionString, "Record with value:", record.getValue
End Function
数据库
class
这是处理与数据库连接的类。连接策略定义了如何连接到数据库。
请注意,您可以更改策略而不必重铸对象,只需调用setConnectionStrategy(...)
Private connection As IConnectionStrategy
Private Sub Class_Initialize()
'Initialize everything but strategy.
End Sub
'Funzione che verrà richiamata per inizializzare le propietà della classe
Public Sub InitiateProperties(ByVal connectionStrategy As IConnectionStrategy)
Set connection = connectionStrategy
End Sub
Public Sub saveRecord(ByVal record As IRecord)
connection.Save record
End Sub
Public Sub setConnectionStrategy(ByVal strategy As IConnectionStrategy)
connection = strategy
End Sub
Private Sub Class_Terminate()
'close connections
End Sub
DatabaseFactory
Module
(VBA没有静态类,因此请使用模块)
此类负责实例化您的Database Objects
'Instantiate a Database with given Strategy
Public Function createDatabaseWithStrategy(strategy As IConnectionStrategy) As Database
Set createDatabaseWithStrategy = New Database
CreateFoglioIdro.InitiateProperties connectionStrategy:=strategy
End Function
'Instantiate a Database with Strategy A
Public Function createDatabaseWithStrategyA() As Database
Set createDatabaseWithStrategyA = New Database
createDatabaseWithStrategyA.InitiateProperties connectionStrategy:=New ConnectionStrategyA
End Function
'Instantiate a Database with Strategy B
Public Function createDatabaseWithStrategyB() As Database
Set createDatabaseWithStrategyB = New Database
createDatabaseWithStrategyB.InitiateProperties connectionStrategy:=New ConnectionStrategyB
End Function
最后是应用程序示例(App Module
):
Option Explicit
Public Sub ApplicationA()
Dim record As IRecord
Set record = New record
record.setValue ("This is a value")
Dim db As Database
Set db = DatabaseFactory.createDatabaseWithStrategyA
db.saveRecord record
'Prints-> Saving to DRIVER=Oracle Server;SERVER=myA.server.com\DatabaseA; Record with value: This is a value
End Sub
Public Sub ApplicationB()
Dim record As IRecord
Set record = New record
record.setValue ("This is a value")
Dim db As Database
Set db = DatabaseFactory.createDatabaseWithStrategyB
db.saveRecord record
'Prints-> Saving to DRIVER=SQL Server;SERVER=myB.server.com\DatabaseB; Record with value: This is a value
End Sub
如您所见,strategy-pattern
与Factory-Pattern
结合使用可帮助您消除大部分重复代码,从而为数据库class
初始化和设置策略。
希望这会有所帮助。