2008-12-16 92 views
1

我有两个类,每个类都需要彼此的实例才能运行。通常如果一个对象需要运行另一个对象,我喜欢在构造函数中传递它。但在这种情况下我不能这样做,因为一个对象必须在另一个之前实例化,因此第二个对象不存在传递给第一个对象的构造函数。如何构造两个对象,彼此作为参数/成员

我可以通过将第一个对象传递给第二个对象的构造函数,然后调用第一个对象的setter来传递第二个对象来解决这个问题,但这似乎有点笨拙,我想知道是否有更好的方法:

backend = new Backend(); 
panel = new Panel(backend); 
backend.setPanel(); 

我从来没有把任何研究放入MVC;我想我正在处理一个模型(后端)和视图或控制器(面板)。我可以从MVC获得任何见解吗?

+0

您的后端/数据层不需要知道任何关于您的表示层。事实上,它应该没有UI层的概念。让它们像这样耦合只会导致很多问题。 – 2008-12-16 16:00:31

回答

8

现在该查看MVC了。 :-)当你有一个模型 - 视图 - 控制器的情况时,一致认为模型不应该知道视图 - 控制器(MVC经常演示为M-VC),但视图总是知道模型。

如果模型需要告诉视图的东西,它会通过通知它的听众,它可能有多个。你的看法应该是其中之一。

2

在一个循环的施工场景中,我会使用工厂类/工厂方法。我通常会将构造逻辑变为工厂专用(使用朋友构造,包级别保护或类似方法),以确保没有人可以在不使用工厂的情况下构建实例。

setter/constructor的使用实际上是两个类和工厂之间的契约的一部分,所以我只是使用任何方便的。

正如已经指出的那样,您应该尝试找到非循环解决方案。

1

最好避免循环引用。我会亲自尝试重新思考我的对象。

+0

这个答案并不是特别有用,有些情况下孩子需要知道他的父母是谁。当你需要这样做时,有安全的解决方案(如代理)。 – 2008-12-16 16:13:36

+0

嗯,这对我很有帮助,它证实了我的怀疑,我需要重新思考我的对象。 :)我想我要去一个MVC监听器/事件通知类型设计,如另一个答案中所建议的。我认为这仍然是循环的,但稍好一些。 – skiphoppy 2008-12-16 16:24:38

2

首先,与其他人在此说的相反,循环引用没有固有的问题。例如,一个Order对象应该有一个对放置Order的人的Customer对象的引用。同样,Customer对象有自己的订单列表是很自然的。

在基于引用的语言(如Java或C#)中,完全没有问题。在基于价值的语言(如C++)中,你必须小心设计它们。

这就是说,你设计的:

backend = new Backend(); 
panel = new Panel(backend); 
backend.setPanel(panel); 

它几乎做到这一点的唯一途径。

0
panel = new Panel(backend); 

你这样做,在该例程类似

Public Sub Panel(ByVal BackEnd as BackEnd) 
     Me.MyBackEnd = BackEnd 
     BackEnd.MyPanel = Me 
    End Sub 

你不需要BackEnd.SetPanel

最好是使用代理服务器。代理通过引发事件将一个对象链接到另一个对象。父母将孩子交给代理人。当孩子需要父母时,它会在代理上调用GetRef方法。然后,代理引发父母用来将自己返回给代理的事件,然后将代理交给孩子。

使用Event/Delegate机制避免了任何循环引用问题。

所以,你必须(假设后端是“父”在这里)

Public Sub Panel(ByVal BackEnd as BackEnd) 
     Me.MyBackEnd = BackEnd.Proxy 
     BackEnd.MyPanel = Me 
    End Sub 

    Public Property MyBackEnd() as BackEnd 
    Set (ByVal Value as BackEnd) 
     priBackEndProxy = BackEnd.Proxy 
    End Set 
    Get 
     Return priBackEndProxy.GetRef 
    End Get 
    End Property 

这里是一个循环引用的问题更详细的讨论。虽然它专注于在Visual Basic 6.0中修复它。

Dynamic Memory Allocation

另外另一溶液聚集板和后端成另一个对象。如果两个元素都是UI控件并且需要以协调方式运行,这很常见。

最后,就MVC而言,我推荐使用模型视图展示器方法。

基本上你有你的表单实现一个IPanelForm接口。它向一个名为Panel的类注册自己,它完成所有的UI逻辑。 BackEnd应该具有面板可以在模型更改时挂钩的事件。 Panel处理事件并通过IPanelForm接口更新表单。

  1. 用户点击一个按钮

  2. 的形式传递到面板,该用户点击一个按钮

  3. 面板处理按钮并检索从后端数据

  4. 面板格式数据。

  5. 面板使用IPanelForm接口在窗体上显示数据。

0

我一直在推迟实施在这里学到的经验教训,给了我足够的时间来思考确切的正确方式来做到这一点。正如其他人所说,如果后端对象在其属性发生更改时有明确的分隔,这绝对是一种可行的方法。它不仅解决了我在这个问题中提出的具体问题,而且还会让这些代码中的许多其他不良设计气味看起来更好。实际上有很多不同的Backend类(通过我的例子中使用的泛型类名),每个类都有自己相应的Panel类。甚至还有一些地方可以将一些东西移动到其他类中,按照相同的模式将其他类对分离为后端/面板对,并减少大量传递垃圾的参数。

这个答案的其余部分将使用特定语言,因为我使用Java。

我对“JavaBeans”并没有太多的担心,但是我发现以下基本的JavaBean约定对我来说非常有帮助:基本上,使用属性的标准getter和setter。结果发现有一个JavaBean约定我不知道哪一个真的会在这里帮助:绑定属性。绑定属性是通过标准获取器和设置器可用的属性,它们在更改时触发PropertyChangeEvents。 [我不确定,但JavaBeans标准可能会指定所有属性都应该是“绑定属性”。在这一点上与我无关。请注意,通过使用BeanInfo类来定义一个JavaBean的确切接口,“标准”getter和setter可能非常不标准,但我从来不会使用它。](我选择遵循的主要的其他JavaBean约定或在每种情况下都不合适是一个无参数的构造函数;我已经在此项目中关注它,因为这些后端对象中的每一个都必须是可序列化的。)

我找到了this blog entry,这对于提示非常有帮助我进入绑定的属性/ PropertyChangeEvents问题,并帮助我构建一个计划,以便我将如何重写此代码。

现在我所有的后端对象都继承了一个名为Model的公共类,它在本系统需要的每个后端都提供了几件事情,包括序列化支持。我将创建一个额外的类JavaBean作为Model的超类,它将提供我需要的PropertyChangeEvent支持,并由每个Model继承。我将更新每个模型中的setter以在调用时触发PropertyChangeEvent。我也可能有一些JavaBean继承了几个类,这些类在技术上并不像这些模型那样具有同样的意义,但也可以将其他类注册为侦听器。 JavaBean类可能不完全实现JavaBean规范;正如我所说,有几个细节我不在乎。但对于这个项目来说这已经足够了。这听起来像我可以通过从java.awt.Component继承来获得所有这些,但这些不是我可以证明的任何组件,所以我不想这样做。 (我也不知道可能需要什么开销)。

一旦每个Model都是一个JavaBean,并且支持PropertyChangeEvent,我会做很多代码清理:当前保持对Panel的引用的模型将会是更新,小组将自己注册为听众。非常干净!该模型不需要知道(也不应该知道首先)当财产更新时小组应该自己调用什么方法。

相关问题