我稍微调整了Quote of the Moment(QOTM),并希望构建一个GUI前端。将对象从DatagramClientHandler传递到GUI非常简单。但是,GUI引用处理程序似乎很棘手。

QuotesGUI类扩展了JFrame,以利用Netbeans拖放面板轻松添加Swing组件。太冗长了。

显然,解决方案是:


  好吧,这取决于有不止一种解决方案。一个可能是
  向ChannelHandler注入侦听器,然后将得到通知
  收到邮件后。另一种解决方案是发送
  收到邮件并注册
  对此主题感兴趣的秋千部分,因此他们会收到通知。


https://stackoverflow.com/a/8780410/262852

DatagramClientHandler:

package net.bounceme.dur.netty;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.logging.Logger;
import net.bounceme.dur.client.gui.QuotesGUI;

public class DatagramClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    private static final Logger log = Logger.getLogger(DatagramClientHandler.class.getName());
    private final QuotesGUI gui = new QuotesGUI();
    private volatile Channel channel = null;

    DatagramClientHandler() {
        log.info("starting..");
        gui.setVisible(true);
    }

    private DatagramPacket getNext() {
        DatagramPacket packet = new DatagramPacket(
                Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
                new InetSocketAddress("localhost", 4454));
        return packet;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
        String response = msg.content().toString(CharsetUtil.UTF_8);
        log.info(response);
        gui.setQuote(response);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.severe(cause.toString());
        ctx.close();
    }
}


GUI中的示例方法。

public void setQuote(String packet) {
    text.setText(packet);
}

最佳答案

首先分开您的责任层...

我可能会先定义某种可以向interface实例注册的侦听器DatagramClientHandler。该interface可以将DatagramClientHandler中的更改或事件通知感兴趣的各方,并在他们认为合适的情况下处理这些事件...

public interface MessageListener {
    public void quoteRecieved(SimpleChannelInboundHandler source, String quote);
    public void errorOccured(SimpleChannelInboundHandler source, Throwable cause);
}


然后,您需要为监听器提供支持...

public class DatagramClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    private static final Logger log = Logger.getLogger(DatagramClientHandler.class.getName());
    //private final QuotesGUI gui = new QuotesGUI();
    private volatile Channel channel = null;
    private List<MessageListener> listeners;

    DatagramClientHandler() {
        listeners = new ArrayList<MessageListener>(25);
        //...
    }

    public synchronized void addMessageListener(MessageListener listener) {
        listeners.add(listener);
    }

    public synchronized void removeMessageListener(MessageListener listener) {
        listeners.remove(listener);
    }

    protected synchronized void fireQuoteRecieved(String quote) {
        for (MessageListener listener : listeners) {
            listener.quoteRecieved(this, quote);
        }
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
        String response = msg.content().toString(CharsetUtil.UTF_8);
        log.info(response);
        fireQuoteRecieved(response);
    }

    //...etc...


现在,当您想接收通知时,可以将MessageListener实例注册为DatagramClientHandler实例...

您将遇到的问题是,确保您对UI所做的所有更新均在EDT中正确执行...

//...
public void quoteRecieved(SimpleChannelInboundHandler source, final String quote) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            text.setText(packet);
        }
    });
}


现在,如果您真的想要,可以进一步将代码与另一个interface分离。

public interface QuoteFactory {
    public synchronized void addMessageListener(MessageListener listener);
    public synchronized void removeMessageListener(MessageListener listener);
}


然后,这将由DatagramClientHandler实现,并且您的用户界面将需要将QuoteFactory实例传递给它,以便它可以在发生某些事情时注册对通知的兴趣...

07-24 22:18