如何在不保持视图活动的情况下实现 MVC 模式
我想在困难的情况下实现 MVC 模式。困难在于我的模型(生成事件的实体)是长期存在的,而视图(事件的接收者)是短暂的。我的问题是,通过两者之间的连接,长期存在的模型使我短暂的视图保持活动状态,即它们不能被垃圾收集。
[MODEL] ------- <weak> -------> [VIEW]
|
<strong>
|
v
[CONTROLLER]
解决此问题的一种方法是将模型中的连接存储在 WeakHashMap
[MODEL] ------- <weak> -------> [VIEW]
| ^
<strong> |
| |
v |
[CONTROLLER] ----------- <strong> ---/
是否有另一种方法可以将侦听器附加到我的模型,但不会使我的视图(和控制器)保持活动状态?
更新:回答mdma的问题:控制器保留对视图的引用,因为它需要更新视图。此引用可能很弱,但我希望控制器成为 View 类的匿名内部类,在这种情况下,Controller 实例具有对 View 实例的隐式强引用。
I'd like to implement the MVC pattern in a difficult situation. The difficulty is that my Models (the entities generating the events) are long-lived, while the Views (the receivers of the events) are short-lived. My problem is that through the connection between the two, the long-lived Models keep my short lived Views alive, i.e. they cannot be garbage-collected.
[MODEL] ------- <weak> -------> [VIEW]
|
<strong>
|
v
[CONTROLLER]
A way to work around this is to store the connections in the Model in a WeakHashMap<View, Controller>. This essentially lets the View to be garbage collected, and when that happens, the WeakHashMap will throw the corresponding Controller out, too. That is, if the Controller doesn't hold a (strong) reference to the View -- which it usually does. In this case the Views are kept alive through the strong references until the Model goes out of scope.
[MODEL] ------- <weak> -------> [VIEW]
| ^
<strong> |
| |
v |
[CONTROLLER] ----------- <strong> ---/
Is there another way to attach listeners to my models that won't keep my views (and controllers) alive?
UPDATE: To answer mdma's question: the Controller keeps a reference to the View, because it needs to update the View. This reference can be weak, but I would like to have the Controllers to be anonymous inner-classes of the View class, in which case the Controller instance has an implicit strong reference to the View instance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
有几种方法可以实现 MVC。
最后一个给出了视图、控制器和模型之间最弱的耦合。对控制器进行单元测试是一个混蛋,因为您最终必须存根事件处理程序。您甚至无法使用模拟框架来模拟它们,因为您需要始终引发事件。不过,它确实有效。
我喜欢 MVCP:
演示者的伟大之处在于您可以仅封装视图所需的内容。演示者的界面几乎完全由视图驱动。您甚至可以为不同的视图创建不同的演示者,并通过一个接口方法填充它们,如下所示:
Presenter.PopulateWith(model,controller)
。这为您提供了一个执行所有表示逻辑(将日期转换为字符串、没有.
的登录名等)的好地方,而不会污染您可爱的模型。并且您可以免费获得弱参考!这与现在惯用的 WPF 中使用的 MVVM 模式非常相似。在 Java 中运行良好,在 Web 中也运行良好。无论如何,希望这些能给你一些想法。
There are a few ways to do MVC.
The last one gives the weakest coupling between views, controllers and models. It's a bastard to unit-test the controller because you end up having to stub event handlers. You can't even mock them using mocking frameworks, because you need to raise events the whole time. It does work, though.
I like MVCP:
The great thing about presenters is that you can encapsulate just the stuff that the view needs. The interface for a presenter is almost entirely driven by the view. You can even do stuff like create different presenters for different views, and populate them all through one interface method like this:
Presenter.PopulateWith(model, controller)
. This gives you a great place to do all the presentation logic (dates into strings, login names without the.
, etc.) without polluting your lovely Model. And you get your weak reference for free!This is very similar to the MVVM pattern now used in idiomatic WPF. Works well in Java, also with Web. Hope these give you some ideas, anyway.
这里您已经获得了 MVC 模式的出色实现。您的问题可能有解决方案。
Here you've got a great implementation of the MVC pattern. There is probably a solution for your problem.
我认为你的方向非常正确。我看到两种可能的解决方案来正确回收视图:
将视图生命周期设计到系统中,以便显式地完成视图解构,然后所有感兴趣的各方都可以释放对视图的引用。
删除控制器中的强引用。控制器可以使用 WeakReference 来保留视图,每次访问都必须检查该视图,或者向控制器传递一个委托给真实视图的 View 实现,通过弱引用保留它。如果引用已被回收(为空),则方法调用是无操作的。
I think you're very much on the right track. I see two possible solutions to getting views properly reclaimed:
Design the view lifetime into the system, so that view descruction is done explicitly, and all interested parties can then release their references to the view.
Remove the strong reference in the controller. The controller can either use a WeakReference to hold on to the view, which must be checked with each access, or instead, pass the controller a View implementation that delegates to your real view, holding on to it via a weak reference. If the reference has been reclaimed (is null) the method call is a no-op.
根据问题中的图表,这根本行不通。
Model
中对Controller
的常规引用以及Controller
中对 View 的常规引用足以意味着View< /code> 是强可达的。因此,
Controller
中对View
的弱引用不会被破坏......直到Model
本身符合垃圾回收条件。由于匿名内部类永远不可能是静态的,因此您没有明智的选择 (
*
),只能使 Controller 成为静态嵌套类或非嵌套类。另一种选择是使从模型到控制器的链接成为弱引用。
(
*
实际上,有一个可能有效的技巧...尽管它太可怕了,无法提及。您可以找出保存 Controller 对象链接的隐藏属性的名称到其父对象,也许可以使用反射来查找Field
,然后使用它将属性设置为null
。)编辑
这就是 JLS 关于匿名类的说法 - JLS 15.9.1
我很难将这一点与OP的评论相协调......
That simply won't work ... based on the diagrams in the question.
A regular reference in the
Model
to theController
and another in theController
to the View will be sufficient to mean that theView
is strongly reachable. As a result the weak reference in theController
to theView
won't be broken ... until theModel
itself becomes eligible for garbage collection.Since an anonymous inner class can never be static, you have no sensible choice (
*
) but to make the Controller a static nested class or a non-nested class.The other alternative would be to make the link from the Model to the Controller a weak reference.
(
*
Actually there is an trick that might possibly work ... though it is almost too horrible to mention. You could figure out what the name of the hidden attribute that holds the Controller object's link to its parent object, and maybe use reflection to find theField
and then use that to set the attribute tonull
.)EDIT
This is what the JLS says about anonymous classes - JLS 15.9.1
I'm having difficulty reconciling this with the OP's comment ...