2015-05-26 5 views
1

Я считаю, что у меня вопрос дизайна, и я надеюсь получить ваш вход. Я сделал небольшую программу, чтобы проиллюстрировать мой вопрос. В принципе, моя программа состоит из радиосистемы, которая слышится в каждой комнате здания. Звук зависит от принимающего конца, в зависимости от того, входит ли камера в радиосистему.Conditional EventHandling

Проблема заключается в том, что отправленное сообщение запускается в каждой комнате, даже если номер не зарегистрирован. Я бы предпочел выполнить условие до того, как сообщение будет отправлено, а не на принимающей стороне. Делая это, я мог бы сэкономить ненужный трафик. Может ли кто-нибудь дать мне идею или правильный способ решить эту ситуацию?

Как раз для записи, я бы предпочел не иметь в радио нескольких обработчиков событий, так как я не знаю, сколько комнат будет.

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(); 
    } 
} 
} 
+1

У вас есть некоторые проблемы с основным дизайном для разработки. Во-первых, ваше радио не должно знать о конкретных комнатах. Радио должно быть в состоянии нормально работать * независимо от того, в какую комнату вы его положили *. Конечно, как вы должны это делать правильно, зависит от ваших фактических требований, и мы не знаем, каковы ваши требования. – Servy

+0

radioPlayer.onRadio + = radioPlayer_onRadio; это в основном регистрация для радио звука. Не регистрируйтесь, если вы не хотите слышать радио. Механизм обработки событий - это, в основном, потребительский шаблон производителя событий. –

+0

Я ищу, чтобы в комнате N слушали только сообщения, предназначенные для его комнаты. Мой способ разрешить это - сделать условие на принимающей стороне. Все номера должны регистрироваться, но я хочу избежать ненужного трафика. – MIJ1974

ответ

1

Хорошо, что вы смотрите на шаблон публикации публикации (AKA eventbus). В шаблоне eventbus у вас есть класс, который регистрирует слушателей и отправляет сообщения. Слушатели сообщают автобусу событий «Я слушаю событие X». Когда eventbus «отправляет» событие 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! 
    } 
} 
+0

Зачем изобретать событие, если у C# уже есть один? –

+0

В этом контексте события связаны с шаблоном eventbus. Я не знаком с «событием» в C#, о котором вы говорите. –

+0

https://msdn.microsoft.com/en-us/library/aa645739%28v=vs.71%29.aspx?f=255&MSPPError=-2147217396 –

0

Попробуйте что-то немного больше, как это:

Edit: Обратите внимание, что это только начало в правильном направлении. Вы можете принять это намного дальше. В принципе, у вас есть источник звука и звуковой излучатель. Очевидно, что радио является источником звука, а динамик - звуковым излучателем, но что-то вроде комнаты может быть и тем, и другим. Радио не должно знать, что такое громкоговоритель или комната, он должен знать только об эмиттерах, и он должен только посылать звуки им. Исходя из этого, комната должна иметь коллекцию излучателей (которая, вероятно, будет динамиками), и когда комната получает звук с радио, она просто передаст это всем зарегистрированным им эмиттерам. Также не будет ничего, что помешает вам зарегистрировать динамик непосредственно на радио. Этот код должен помочь показать, как вы могли бы реализовать все это.

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); 
     } 
    } 
} 
+0

Я только что увидел и применил ваше решение. Это было просто, и это также решило мою проблему. Надеюсь, меня не накажут за то, что я изменил свой ответ на этот вопрос. Спасибо огромное! – MIJ1974

+0

@ MIJ1974 no вы не будете наказаны, но вы все равно можете поддержать этот ответ, если вам это нравится. –

+1

Я не могу выдвигать, потому что у меня нет 15 репутации. Могу ли я просто сказать, что GleneBob и C Bauer чрезвычайно полезны, .. Спасибо, ребята. – MIJ1974