传递对Java中不鼓励的对象的引用?

时间:2012-12-09 19:05:17

标签: java user-interface object reference constructor

我是一名自学成才的程序员,就像我曾经在经典的“表单之间传递数据”问题上遇到的许多其他新手一样。大约一年前,当我用Java构建我的第一个聊天应用程序时,我再次遇到了这个问题。我通过将对正在运行的GUI的引用传递给另一个类的构造函数来解决它,因此它可以直接操作GUI。例如:

class GUI {
    Writer w;
    void initGUI() {
        w = new Writer(this);
    }
}

class Writer {
    GUI ui;
    public Writer(GUI ui) {
        this.ui = ui;
        ui.textBox.write("Yo");
        // now, instead of the "this" keyword, I can say "ui.w" or "ui.w.ui.w.ui.w..."
    }
}

我确信这是“上游”传输数据的最有效方法之一,但我在一个有同样问题的人的论坛上提出这个建议时,我感到很悲痛(并且有些赞扬)。那么在更大的应用程序上执行此操作会产生什么样的混乱?当我查看使用它的应用程序时,我注意到它们非常实用且高效,但也有点过于有机(如果你愿意)和复杂(特别是当有线程在不同时间访问GUI时,等等)。

有更好的方法吗?在使用Qt时,我采用了不同的方法,但由于使用了信号,插槽和线程,因此更复杂。请指出我正确的方向。感谢。

3 个答案:

答案 0 :(得分:4)

这种方法的主要问题是耦合。 Writer类不是一个通用的,可重用的Writer类,而是能够完成它的工作,并且如果需要的话,它可以发送有关它的功能的事件,它与这个特定的GUI紧密耦合。

如果它像所有Swing组件一样接受了侦听器,则可以在几个不同的GUI中重用Writer,或者选择更新文本区域而不是文本字段。

另一种解决方案是拉动而不是推动。您可以使用编写器的GUI调用方法来查询其状态,而不是让编写器更新GUI。这并不总是可能的,但通常是。

答案 1 :(得分:1)

  

我通过将对正在运行的GUI的引用传递给另一个类的构造函数来解决它,因此它可以直接操作GUI。

您希望将业务逻辑与表示层分离。您希望能够独立于gui独立测试业务逻辑。您希望能够更改前端gui,而无需修改后端。这称为Separation of Concerns

有许多设计模式可以帮助您实现这一目标。

其中一个是Model View Controller (MVC)

您可以直接与模型进行交互,而不是直接与GUI交互。

答案 2 :(得分:0)

是的,Java绝对是带对象的传递。

但你所做的是,Writer假设你的GUI是一成不变的,这意味着它总是会有一个名为textBox的属性。

仅仅看一下事情,Writer不应该负责访问和操纵GUI的属性。如果您更改GUI中的内容,则还需要重新编码Writer课程。

您可以将Writer重新编码为仅向GUI发送消息,因为它的责任只是告诉GUI要写什么,而不是如何写。然后将其保留到GUI以处理该消息:

class GUI
{
     Writer w;
     void initGUI()
     {
        w = new Writer(this); 
     }

     void ReceiveMessage(string message)
     {
         this.textBox.text = message;
     }
}

您的Writer班级:

class Writer
{
    GUI ui;

    public Write(GUI ui)
    {
         this.ui = ui;
         // Don't send the message in the constructor.
    }

    // The program calls this function with whatever text the user enters.
    public void SendMessage(string message)
    {
        ui.ReceiveMessage(message);
        // Writer no longer depends on ui to have a textbox Element.
    }
}

上面的代码可以通过界面进行改进。这样,您可以将任何内容传递给需要知道如何接收消息的作者:

interface IMessageReceiver
{
    void ReceiveMessage(string message);
}

现在,您的GUI成为IMessageReceiver:

class GUI implements IMessageReceiver
{
     Writer w;
     void initGUI()
     {
        w = new Writer(this); 
     }

     public void ReceiveMessage(string message)
     {
         this.textBox.text = message;
     }
}
现在

Writer课程:

class Writer
{
    IMessageReceiver receiver;

    public Write(MessageReceiver receiver)
    {
         this.receiver = receiver;
         // Don't send the message in the constructor.
    }

    // The program calls this function with whatever text the user enters.
    public void SendMessage(string message)
    {
        receiver.ReceiveMessage(message);

    }
}

这里的区别在于Writer将不再关心它是否为GUI。只要知道如何接收消息的IMessageReceiver,它就会占用任何对象。

如果您不熟悉界面,请对其进行一些阅读/研究。它们非常方便,如果没有,至关重要!