我们可以同时使用接口和事件吗? [英] Can we use Interfaces and Events together at the same time?

查看:233
本文介绍了我们可以同时使用接口和事件吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我还在尝试围绕VBA中的接口和事件如何协同工作(如果有的话)。我即将在Microsoft Access中构建一个大型应用程序,我希望尽可能灵活和可扩展。为此,我想使用 MVC 界面 2 )( 3 ),自定义集合类使用自定义集合引发事件类,找到更好的方法来集中化管理由表单上的控件触发的事件,以及一些额外的 VBA设计模式

I'm still trying to wrap my head around how Interfaces and Events work together (if at all?) in VBA. I'm about to build a large application in Microsoft Access, and I want to make it as flexible and extendable as possible. To do this, I want to make use of MVC, Interfaces (2) (3) , Custom Collection Classes, Raising Events Using Custom Collection Classes, finding better ways to centralize and manage the events triggered by the controls on a form, and some additional VBA design patterns.

我预计这个项目会变得非常毛茸茸,所以我想尝试在VBA中共同使用接口和事件的限制和好处,因为它们是两个主要方式(我认为)真正实现VBA中的松散耦合。

I anticipate that this project is going to get pretty hairy so I want to try to grok the limits and benefits of using interfaces and events together in VBA since they are the two main ways (I think) to really implement loose-coupling in VBA.

首先,这个问题关于在VBA中尝试一起使用接口和事件时引发的错误。答案指出显然不允许事件通过接口类传递到具体类中,就像你想使用'Implements'一样。

To start with, there is this question about an error raised when trying to use interfaces and events together in VBA. The answer states "Apparently Events are not allowed to be passed through an interface class into the concrete class like you want to using 'Implements'."

然后我发现了这个声明在在另一个论坛上回答:在VBA6中,我们只能引发在类的默认接口中声明的事件 - 我们不能引发在Implemented接口中声明的事件。

Then I found this statement in an answer on another forum: "In VBA6 we can only raise events declared in a class's default interface - we can't raise events declared in an Implemented interface."

因为我还在寻找接口和事件(VBA是我真正有机会在现实环境中尝试OOP的第一种语言,我知道 shudder ),我无法完全理解在VBA中将事件和接口一起使用的所有方法。听起来你可以同时使用它们,听起来有点像你不能。 (例如,我不确定上面的一个类的默认接口与一个已实现的接口是什么意思。)

Since I'm still groking interfaces and events (VBA is the first language I've really had a chance to try out OOP in a real-world setting, I know shudder), I can't quite work through in my mind what all this means for using events and interfaces together in VBA. It kinda sounds like you can use them both at the same time, and it kinda sounds like you can't. (For instance, I'm not sure what is meant above by "a class's default interface" vs "an Implemented interface.")

有人可以给我一些基本的例子在VBA中一起使用接口和事件的真正好处和局限性?

Can someone give me some basic examples of the real benefits and limitations of using Interfaces and Events together in VBA?

推荐答案

这是一个完美的用例适配器:在内部调整一组合同(接口)的语义,并将它们作为自己的外部API公开;可能根据其他合同。

This is a perfect use-case for an Adapter: internally adapting the semantics for a set of contracts (interfaces) and exposing them as its own external API; possibly according to some other contract.

定义类模块IViewEvents:

Define class modules IViewEvents:

Option Compare Database
Option Explicit

Private Const mModuleName   As String = "IViewEvents"

Public Sub OnBeforeDoSomething(ByVal Data As Object, ByRef Cancel As Boolean):  End Sub
Public Sub OnAfterDoSomething(ByVal Data As Object):                            End Sub

Private Sub Class_Initialize()
    Err.Raise 5, mModuleName, AccessError(5) & "-Interface class must not be instantiated."
End Sub

IViewCommands:

IViewCommands:

Option Compare Database
Option Explicit

Private Const mModuleName   As String = "IViewCommands"

Public Sub DoSomething(ByVal arg1 As String, ByVal arg2 As Long):   End Sub

Private Sub Class_Initialize()
    Err.Raise 5, mModuleName, AccessError(5) & "-Interface class must not be instantiated."
End Sub

ViewAdapter:

ViewAdapter:

Option Compare Database
Option Explicit

Private Const mModuleName   As String = "ViewAdapter"

Public Event BeforeDoSomething(ByVal Data As Object, ByRef Cancel As Boolean)
Public Event AfterDoSomething(ByVal Data As Object)

Private mView       As IViewCommands

Implements IViewCommands
Implements IViewEvents

Public Function Initialize(View As IViewCommands) As ViewAdapter
    Set mView = mView
    Set Initialize = Me
End Function

Private Sub IViewCommands_DoSomething(ByVal arg1 As String, ByVal arg2 As Long)
    mView.DoSomething arg1, arg2
End Sub

Private Sub IViewEvents_OnBeforeDoSomething(ByVal Data As Object, ByRef Cancel As Boolean)
    RaiseEvent BeforeDoSomething(Data, Cancel)
End Sub
Private Sub IViewEvents_OnAfterDoSomething(ByVal Data As Object)
    RaiseEvent AfterDoSomething(Data)
End Sub

和Controller:

and Controller:

Option Compare Database
Option Explicit

Private Const mModuleName       As String = "ViewAdapter"

Private WithEvents mViewAdapter As ViewAdapter

Private mData As Object

Public Function Initialize(ViewAdapter As ViewAdapter) As Controller
    Set mViewAdapter = ViewAdapter
    Set Initialize = Me
End Function

Private Sub mViewAdapter_AfterDoSomething(ByVal Data As Object)
    ' Do stuff
End Sub

Private Sub mViewAdapter_BeforeDoSomething(ByVal Data As Object, ByRef Cancel As Boolean)
    Cancel = Not Data Is Nothing
End Sub

加上标准模块构造函数:

plus Standard Modules Constructors:

Option Compare Database
Option Explicit
Option Private Module

Private Const mModuleName   As String = "Constructors"

Public Function NewViewAdapter(View As IViewCommands) As ViewAdapter
    With New ViewAdapter:   Set NewViewAdapter = .Initialize(View):         End With
End Function

Public Function NewController(ByVal ViewAdapter As ViewAdapter) As Controller
    With New Controller:    Set NewController = .Initialize(ViewAdapter):   End With
End Function

和MyApplication:

and MyApplication:

Option Compare Database
Option Explicit

Private Const mModuleName   As String = "MyApplication"

Private mController As Controller

Public Function LaunchApp() As Long
    Dim frm As IViewCommands 
    ' Open and assign frm here as instance of a Form implementing 
    ' IViewCommands and raising events through the callback interface 
    ' IViewEvents. It requires an initialization method (or property 
    ' setter) that accepts an IViewEvents argument.
    Set mController = NewController(NewViewAdapter(frm))
End Function

注意如何使用适配器模式与接口编程相结合,可以实现非常灵活的结​​构,可以在运行时替换不同的Controller或View实现。每个Controller定义(在需要不同实现的情况下)使用相同ViewAdapter实现的不同实例,因为依赖注入用于在运行时为每个实例委派事件源和命令接收器。

Note how use of the Adapter Pattern combined with programming to interfaces results in a very flexible structure, where different Controller or View implementations can be substituted in at run time. Each Controller definition (in the case of different implementations being required) uses different instances of the same ViewAdapter implementation, as Dependency Injection is being used to delegate the event-source and command-sink for each instance at run time.

可以重复相同的模式来定义Controller / Presenter / ViewModel和Model之间的关系,尽管在COM中实现MVVM会变得相当繁琐。我发现MVP或MVC通常更适合基于COM的应用程序。

The same pattern can be repeated to define the relationship between the Controller/Presenter/ViewModel and the Model, though implementing MVVM in COM can get rather tedious. I have found MVP or MVC is usually better suited for COM-based applications.

生产实现还会在支持的范围内添加适当的错误处理(至少) VBA,我只是暗示了每个模块中mModuleName常量的定义。

A production implementation would also add proper error handling (at a minimum) to the extent supported by VBA, which I have only hinted at with the definition of the mModuleName constant in each module.

这篇关于我们可以同时使用接口和事件吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆