0

私は TCP クライアント アプリケーションに取り組んでいます。私の問題を共有し、知りたい

アプリケーションで消費されるパケットのより良い設計アプローチ。

現在、私はそれを次のように設計しています: Consumer クラスは、ソケットからパケットを受信するとアクティブになります。PacketReceived イベントは、有効なパケットを認識して構築すると、消費者クラスによって発生します。

今:パケットを消費する必要があるすべてのフォーム(およびユーザーコントロール)は、このイベントを購読しています

通知を受け取り、特定の packetID をチェックすることで、目的のパケットを消費します。

この設計の悪い点は、イベント サブスクリプション コードと packetID を記述する必要があることです。

すべてのフォーム (およびユーザー コントロール) の確認コード。

仕事をやり遂げるためのより良い方法はありますか、提案してください。

C#.net、Framework 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);
    }
}

ただし、物事をもう少し切り離すことができます。フォームは、Consumer について実際に知る必要はありません。どこかからイベントを受け取ることができるということだけです。その知識を使用して、別のインターフェイスを作成しましょう。

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

次に、フォームが代わりにインターフェイスを使用するように変更するだけです (ディスパッチャー/コンシューマーをフォームに公開する方法によって異なります)。

この小さな変更により、フォームのテストと、将来のパケットの受信方法の変更が非常に簡単になります。

于 2012-08-29T05:24:18.950 に答える