应用程序特定的类方法实现

问题描述 投票:6回答:1

我有一个库(加载项),其中包含一些在小型应用程序中使用的类。我想为该类提供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 strategySave方法,然后重新ItemIRecordIDatabaseStrategyto使用它。我认为我使用的模式不正确,所以我的问题是 - 如何向DatabaseStrategy提供Record,这样我就不必重新制作对象,也可能没有在IDatabaseStrategy中实现Record?我考虑过的替代方案:

  • DatabaseStrategy周围的Record包装Record和应用程序(DatabaseStrategy.Create(Record).Save
  • 揭露DatabaseStrategy作为Record的成员,但似乎应用程序必须知道DatabaseStrategy是记录的成员(Record.DatabaseStrategy.Save)。
excel vba design-patterns strategy-pattern
1个回答
1
投票

这是design-patternsVBA的一个非常好的问题。

可以看到strategy pattern的完整描述here,但总而言之,这是一个描述它的UML类和序列图:

enter image description here

  • 摘要

基本上,此策略允许算法独立于使用它的客户端。

推迟决定使用哪种算法直到运行时允许调用代码更灵活和可重用。

你提出了这两个解决方案,我想解释为什么我没有使用它们:

  • 围绕记录和应用程序特定的记录包装DatabaseStrategyDatabaseStrategy.Create(Record).Save) 使用此解决方案将减少cohesion,因为class数据库策略将不得不照顾实例化Record objects(正如我稍后展示,这可以使用Factory-Pattern完成)
  • 揭露DatabaseStrategy作为记录的成员,但似乎应用程序必须知道DatabaseStrategy是记录的成员(Record.DatabaseStrategy.Save) 这种设计模式必须知道策略,但创新是它可以在运行时更改,传递实现动作方法的desidered策略对象。在这种情况下,我会将DatabaseStrategyRecord移开,因为最后提到的是需要保存的object,但它不是执行动作的代理人(可能是Database class,我将在稍后展示)。

为了解决如何使用不接受参数的VBA objects构造函数来实例化这个class的问题,我使用了另一种模式:Factory Pattern

enter image description here

下面的代码是为了说明如何使用这两个模式而编写的,因此省略了许多函数,并且没有真正实现数据库方法。现在这是代码的其余部分:

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没有静态类,所以请改用Module) 这个类负责你的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设置策略。

希望这可以帮助。

© www.soinside.com 2019 - 2024. All rights reserved.