excel - 类方法的特定于应用程序的实现
问题描述
我有一个库(加载项),其中包含一个在一些小型应用程序中使用的类。我想为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
战略接口和实施:
数据库策略:
Public Function Save():End Function
数据库策略A:
Implements IDatabaseStrategy Private Function IDataBaseStrategy_Save() Debug.Print "Saving to database A" End Function
数据库策略B:
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
方法,然后重新转换才能使用它。我认为我使用的模式不正确,所以我的问题是 - 我如何向 a 提供a以便我不必重铸对象并且可能不实现 in ?我考虑过的替代方案:Database strategy
Save
Item
IRecord
IDatabaseStrategy
DatabaseStrategy
Record
IDatabaseStrategy
Record
- 围绕特定于
DatabaseStrategy
应用程序 ( )Record
Record
DatabaseStrategy.Create(Record).Save
- 公开
DatabaseStrategy
为成员,Record
但似乎应用程序必须知道它DatabaseStrategy
是记录的成员(Record.DatabaseStrategy.Save
)。
解决方案
design-patterns
这是关于with的一个很好的问题VBA
。
strategy pattern
可以在这里看到完整的描述,但总而言之,这是一个 UML 类和描述它的序列图:
概括
基本上,这种策略让算法独立于使用它的客户端而变化。
将关于使用哪种算法的决定推迟到运行时允许调用代码更加灵活和可重用。
您提出了这两种解决方案,我想解释一下为什么我没有使用它们:
- 围绕
DatabaseStrategy
特定于 Record 和应用程序的 Record (DatabaseStrategy.Create(Record).Save
)使用这个解决方案会降低凝聚力,因为
class
DatabaseStrategy 必须处理实例化Record
objects
(正如我稍后展示的,这可以通过应用来完成Factory-Pattern
) - 公开
DatabaseStrategy
为记录的成员,但似乎应用程序必须知道这DatabaseStrategy
是记录的成员(Record.DatabaseStrategy.Save
)这种设计模式必须知道策略,但创新之处在于它可以在运行时更改,传递实现操作方法的所需策略对象。在这种情况下,我会
DatabaseStrategy
离开Record
,因为最后提到的是object
需要保存的,但执行操作的不是代理(这可能是Database
class
我稍后将展示的)。
为了解决如何使用不接受参数objects
的 VBA构造函数来实例化 this 的问题,我使用了另一种模式:工厂模式。class
下面的代码只是为了说明如何使用这两种模式而编写的,因此省略了很多功能,并且没有真正实现数据库方法。现在这是其余的代码:
代码
IRecord
class
(接口):
Public Function getValue() As String: End Function
Public Function setValue(stringValue As String): End Function
Record
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
( Interface )
这是连接策略的接口。您的代码在这里几乎没有改变。
Public Function Save(ByVal record As IRecord): End Function
策略 A 的ConnectionStrategyA
class
类。此处的代码几乎没有更改。
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
策略 A 的ConnectionStrategyB
class
类。此处的代码几乎没有更改。
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
。
希望这可以帮助。
推荐阅读
- c# - 通过 C# LINQ 访问泛型列表中数组属性的元素
- python - 我们如何调用一个类而不在调用时传递变量?
- css - 大屏幕上的并排元素并以小屏幕为中心
- html - 如何设置 grid-auto-columns 以平均划分列?
- python-3.x - 使用 `os.system("")` 打开新窗口并单击按钮上的 cmd
- r - 如何为序数分类问题自定义 XGBoost 目标函数?
- javascript - TypeScript 类型到外部库
- javascript - 什么被归类为要传递给 useEffect 的依赖项?
- reactjs - 根据 React 中另一个字段的输入值,有条件地渲染 Formik 字段并进行验证
- r - 将 R 字符公式转换为数字