我相信我有一个设计问题,我希望得到你的意见。我制作了一个小程序来说明我的问题。基本上,我的程序包括一个无线电系统,可以在建筑物的每个房间听到。声音取决于接收端,取决于房间是否将自己注册到无线电系统。
我的问题是,即使房间没有注册,每个房间也会触发发送的信息。我希望在消息发送之前执行该条件,而不是在接收端。通过这样做,我可以节省自己不必要的流量。任何人都可以给我一个想法或正确的方法来解决这种情况吗?
仅仅为了记录,我宁愿不在收音机里有多个活动处理程序,因为我不知道会有多少个房间。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Radio
{
#region Speakers
public interface ISound
{
string sound { get; set; }
}
public abstract class RoomSpeaker : ISound
{
public string sound { get; set; }
}
public class Room1Speaker : RoomSpeaker
{
}
public class Room2Speaker : RoomSpeaker
{
}
public class BuildingSpeaker : RoomSpeaker
{
}
#endregion
#region Rooms
public abstract class Room
{
public Radio radioPlayer;
public string name;
public HashSet<Type> registeredSpeakers = new HashSet<Type>();
public virtual void RoomPlayer(string lyrics)
{
registeredSpeakers.Add(typeof(BuildingSpeaker));
Console.WriteLine(lyrics);
}
}
public class Room1 : Room
{
public Room1(Radio radioPlayer)
{
this.radioPlayer = radioPlayer;
name = "Room1";
registeredSpeakers.Add(typeof(Room1Speaker));
radioPlayer.onRadio += radioPlayer_onRadio;
}
// This is what I don't think I like. It will only do something if it's registered. That's fine.
// But on any radio message out, this room will get called regardless. Should I NOT be doing this? Should I go back to
// making an eventHandler for every room? rather then having one even handler for all the rooms and have a condition on the receiving end.
void radioPlayer_onRadio(object sender, ISound e)
{
if (registeredSpeakers.Contains(e.GetType()))
RoomPlayer(name + e.sound);
}
}
public class Room2 : Room
{
public Room2(Radio radioPlayer)
{
this.radioPlayer = radioPlayer;
name = "Room2";
registeredSpeakers.Add(typeof(Room2Speaker));
radioPlayer.onRadio += radioPlayer_onRadio;
}
void radioPlayer_onRadio(object sender, ISound e)
{
// same problem as in Room1.
if (registeredSpeakers.Contains(e.GetType()))
RoomPlayer(name + e.sound);
}
}
#endregion
public class Radio
{
public event EventHandler<ISound> onRadio;
public void PlayRoom1()
{
onRadio(this, new Room1Speaker() { sound = "Test" });
}
public void PlayRoom2()
{
onRadio(this, new Room2Speaker() { sound = "Test" });
}
public void PlayAllRooms()
{
onRadio(this, new BuildingSpeaker() { sound = "Test All Rooms" });
}
}
class Program
{
static void Main(string[] args)
{
var radio = new Radio();
var room1 = new Room1(radio);
var room2 = new Room2(radio);
radio.PlayRoom1();
radio.PlayRoom2();
radio.PlayAllRooms();
Console.ReadLine();
}
}
}
答案 0 :(得分:1)
好的,你正在看的是发布 - 订阅模式(AKA eventbus)。在eventbus模式中,您有一个注册侦听器并发送消息的类。听众告诉事件总线“我正在听事件X”。当事件总线“发送”事件X时,它会查询该事件的侦听器列表,如果已注册,则执行侦听器告诉它执行的方法。
public class EventBus
{
private Dictionary<Type, List<Action<IEvent>>> actions = new Dictionary<Type, List<Action<IEvent>>>();
public void Listen<T>(Action<IEvent> callback) where T : IEvent
{
if (!actions.ContainsKey(typeof(T)))
{
actions.Add(typeof(T), new List<Action<IEvent>>());
}
actions[typeof(T)].Add(callback);
}
public void ClearCallbacks<T>() where T : IEvent
{
actions[typeof (T)] = null;
}
public void Send<T>(T @event) where T : IEvent
{
if (!actions.ContainsKey(typeof(T)))
{
return;
}
foreach (var action in actions[typeof(T)])
{
action(@event);
}
}
}
public interface IEvent
{
}
用法:
public static void main () {
var eventBus = new EventBus();
var aRoom = new NoisyRoom(eventBus);
var bRoom = new NoisyRoom(eventBus);
var cRoom = new NoisyRoom(eventBus);
var dRoom = new QuietRoom(eventBus);
eventBus.Send(new NoisyEvent()); //sends to a,b,c room
}
public class EasyListeningEvent : IEvent
{
}
public class QuietRoom
{
public QuietRoom(EventBus eventBus)
{
eventBus.Listen<EasyListeningEvent>(BringTheNaps);
}
private void BringTheNaps(IEvent @event)
{
//its been brought!
}
}
class NoisyEvent : IEvent
{
}
public class NoisyRoom
{
public NoisyRoom(EventBus eventBus)
{
eventBus.Listen<NoisyEvent>(BringTheNoise);
}
private void BringTheNoise(IEvent @event)
{
//its been brought!
}
}
答案 1 :(得分:0)
尝试一下这样的事情:
编辑:请注意,这只是一个正确方向的开始。你可以进一步采取这一点。基本上你所拥有的是声源和声音发射器。显然,收音机是声源,扬声器是声音发射器,但像房间这样的东西可能都是。收音机不应该知道扬声器或房间是什么,它应该只知道发射器,它应该只向他们发送声音。基于此,房间应该有一组发射器(可能是扬声器),当一个房间从收音机发出声音时,它会简单地将它传递给它注册的任何发射器。也没有什么可以阻止你直接将收音机注册到收音机。此代码应该有助于说明如何实现所有这些。
public class Radio
{
private HashTable<string, EventHandler<ISound>> rooms = new ...;
public void RegisterRoom(string room, EventHandler<ISound> onSound)
{
rooms[room] = onSound;
}
public void UnregisterRoom(string room)
{
rooms.Remove(room);
}
public void PlayRoom(string room)
{
EventHandler<ISound> onSound;
if (rooms.TryGetValue(room, out onSound))
{
onSound(this, new BuildingSpeaker() { sound = "Test" });
}
}
public void PlayAllRooms()
{
if (rooms.Count == 0)
{
return;
}
var speaker = new BuildingSpeaker() { sound = "Test All Rooms" };
foreach (var room in rooms)
{
room.Value(this, speaker);
}
}
}