0

我正在开发一个 TCP 客户端应用程序。我想分享我的问题并想知道

为应用程序中使用的数据包提供更好的设计方法。

目前我将它设计为:消费者类,一旦从套接字接收到数据包就被激活。PacketReceived 事件在消费者类识别并建立有效数据包后被触发。

现在:我所有需要使用数据包的表单(和用户控件)都订阅了这个事件

得到通知,然后通过检查特定的 packetID 来消费感兴趣的数据包。

这个设计的坏处是,它需要编写事件订阅代码和packetID

每个表单(和用户控件)上的验证码。

有没有更好的方法来完成工作,请建议。

我正在使用 C#.net,框架 3.5。

谢谢。穆罕默德·伊德里斯

4

1 回答 1

1

听起来您应该改用观察者模式,让消费者决定将哪个数据包发送到哪里。

// implement this interface in all forms
public interface IPacketSubscriber
{
    void HandlePacket(Packet packet);
}

// like this
public class SomeForm : Form, IPacketSubscriber
{
    public SomeForm()
    {
        // subscribe in some way here.
        YouSingleton.Consumer.Subscribe(1, this);
        YouSingleton.Consumer.Subscribe(12, this);
        YouSingleton.Consumer.Subscribe(25, this);
    }

    public void HandlePacket(Packet packet)
    {
        // got packet here
    }
}

// Keeps track of all subscribers
public class SubscriberList
{
    Dictionary<int, List<IPacketSubscriber>> _subscribers 
        = new Dictionary<int, List<IPacketSubscriber>>();

    public void Subscribe(int packetId, IPacketSubscriber subscriber)
    {
        List<IPacketSubscriber> subscribers;
        if (!_subscribers.TryGetValue(packetId, out subscribers))
        {
            subscribers = new List<IPacketSubscriber>();
            _subscribers.Add(packetId, subscribers);
        }

        subscribers.Add(subscriber);
    }

    public void Publish(Packet packet)
    {
        List<IPacketSubscriber> subscribers;
        if (!_subscribers.TryGetValue(packet.FunctionId, out subscribers))
        {
            subscribers = new List<IPacketSubscriber>();
            _subscribers.Add(packet.FunctionId, subscribers);
        }

        foreach (var subscriber in subscribers)
        {
            subscriber.HandlePacket(packet);
        }
    }

}

// changes in the consumer class
// composite pattern & law of demeter, do not expose the subscriberlist
public class Consumer
{
    SubscriberList _subscribers = new SubscriberList();

    public void Subscribe(int packetId, IPacketSubscriber subscriber)
    {
        if (subscriber == null) throw new ArgumentNullException("subscriber");
        _subscribers.Subscribe(packetId, subscriber);
    }

    protected void OnReceivedCompletePacket(Packet packet)
    {
        _subscribers.Publish(packet);
    }
}

但是,您可以将事情进一步解耦。表单并不需要真正了解消费者,只需知道它们可以从某个地方接收事件。让我们使用这些知识并创建另一个接口:

public interface IPacketDispatcher
{
    void Subscribe(int packetId, IPacketSubscriber);
}

然后简单地更改以便表单使用接口(取决于您如何将调度程序/消费者暴露给表单)。

这个微小的改变使得测试你的表单和改变你将来接收数据包的方式变得非常容易。

于 2012-08-29T05:24:18.950 回答