代わりにオブザーバー パターンを使用し、消費者にどのパケットをどこに送信するかを決定させる必要があるようです。
// 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);
}
次に、フォームが代わりにインターフェイスを使用するように変更するだけです (ディスパッチャー/コンシューマーをフォームに公開する方法によって異なります)。
この小さな変更により、フォームのテストと、将来のパケットの受信方法の変更が非常に簡単になります。