2011-11-03 2 views
0

Предположат, мы имеем следующую структуру класса:Слушайте конкретные события унаследованных классов

public class Fruit 
{ 
    public event EventHandler<RipeEventArgs> Ripe; 
} 

public class Apple:Fruit 
{ 
    public event EventHandler<FallEventArgs> FallFromTree; 
} 

public class Farm 
{ 
    List<Fruit> fruits; 
} 

public class Farmer 
{ 
    private Farm myFarm; 

    public Farmer() 
    { 
     // listen to all FallFromTree events coming from the farm 
     myFarm.WHAT += AppleFallen; 
    } 

    public void AppleFallen(object sender, FallEventArgs e) {} 
} 

Вопрос: Как я могу убедиться, что фермер может прослушивать все события FallFromTree от любого яблока на ферме и любое яблоко, которое будет создано в будущем?

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

+0

Это домашнее задание? –

+0

Нет, я пытаюсь найти способ НЕ создавать огромный класс «Фарм». – Marnix

+0

Почему бы просто не добавить перечисление, описывающее все, что может заинтересовать фермер. Это не отличается от фермера, который должен знать о конкретных событиях фруктов. Но с большим преимуществом, что вам сейчас нужно только одно событие. –

ответ

1

Просто дайте Farm знать о Farmer, а не Farmer знают о Farm.

public class Fruit 
{ 
    public event EventHandler<RipeEventArgs> Ripe; 
} 

public class Apple:Fruit 
{ 
    public event EventHandler<FallEventArgs> FallFromTree; 
} 

public class Farm 
{ 
    List<Fruit> fruits; 
    Farmer farmer; 

    public Farm(Farmer farmer) 
    { 
     this.farmer = farmer; 
    } 

    public void AddFruit(Fruit fruit) 
    { 
     farmer.RegisterForEvents(fruit); 
     fruits.Add(fruit); 
    } 
} 

public class Farmer 
{ 
    private Farm myFarm; 

    public Farmer() 
    { 

    } 

    public virtual void RegisterForEvents(Fruit fruit) 
    { 
     //Farmer decides what events it is interested in: can override in derived classes 
     if(fruit is Apple) 
     { 
      ((Apple)fruit).FallFromTree += AppleFallen; 
     } 
    } 

    public void AppleFallen(object sender, FallEventArgs e) {} 
} 

fruit is Apple Предложение не является идеальным, но я думаю, что единственное, что вы можете сделать, есть либо осуществить двойной отправки или имеют различные методы Farmer для каждого типа Fruit.

+0

Звучит многообещающе. Я собираюсь обсудить возможности в моей команде. – Marnix

+0

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

+0

Хорошо, спасибо за прием. По вашим общим требованиям: в конечном итоге что-то потребуется, чтобы принять решение о том, какие события должен «подписаться» фермером, поэтому пока вы сможете скрыть это знание от самого «фермера», что поведение должно жить где-то , Если эта ответственность не соответствует ни одному из ваших существующих объектов, возможно, это означает, что вам нужно ввести новый класс, выполняющий эту роль. Удачи. –

0

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

public class MakeAppleFallCommandHandler 
{ 
    public void Execute(Apple apple) 
    { 
     //This method would be called whenever any apple in the farm falls 

     FallFromTree(apple); 
    } 

    public event EventHandler<FallEventArgs> FallFromTree; 
} 

Тогда в классе фермер вы можете подписаться на MakeAppleFallCommandHandler.FallFromTree. Это вдохновляет CQRS.

+0

Куда вы оставите все эти манипуляторы? Это похоже на хороший шаблон, но я не вижу, как это не приведет к значительному увеличению кода «Farm», поскольку для каждого нового события требуется новый CommandHandler в Farm для подписки на него. – Marnix

+0

Ваша логика такова, что в любом случае у вас будет много кода в вашем приложении. Дело только в том, что у одного класса есть много кода против многих классов, имеющих некоторый код. В приведенном выше примере вы можете написать класс менеджера подписки, который содержит логику, на которой ферма подписывается на какой обработчик команд. – Suhas

0

Ну, если у фермы есть фрукты, то она может только подписаться на события из фруктов.

Определите виртуальное событие в своем базовом классе i.e Fruit, а затем переопределите его в разных классах детей Fruits, например, для apple это будет FallFromTree.

Смотреть это подробнее подробнее подробнее C#: What are virtual events and how can they be used?

+0

Это значительно увеличит класс «Фрукты», а также означает, что любой вид фруктов знает, как упасть с дерева, а некоторые фрукты даже не растут с дерева. Таким образом, это всего лишь обходной путь для гигантского класса фермы. – Marnix

+0

Нет, я имел в виду, что класс Fruit имел бы общее событие, называемое ChildEvent. Каждый ребенок будет раскрывать его по-своему. Как и яблоко, он будет раскрывать FallFromTree для ChildEvent. Другие фрукты, будут отменять свои собственные ChildEvents, как в соответствии с их собственностью. Как Фрукты, выращенные в корне, выставляют GrownFromRoot – Anand

+0

Но это будет означать, что у каждого фрукта может быть только одно событие. И это, конечно, не так. Я хочу, чтобы у них было несколько событий. – Marnix

Смежные вопросы