Как реорганизовать дубликаты кода обработки событий
У меня есть следующий класс, который позволяет определенным объектам подписаться на событие изменения. Проблема в том, что у меня также есть классы B и C, которые нуждаются в этой функциональности, которая позволяет объектам подписываться на такие же вещи. Мы, конечно, не хотим копировать и вставлять это поведение.
Мы рассмотрели наследование от общего базового класса, но все наши классы, включая A, B и C, уже наследуют от общего BaseClass. И мы не хотим добавлять это поведение в BaseClass, потому что другие наши классы E,F,G, которые наследуются от BaseClass, не нуждаются в этом поведении.
Есть ли лучшее решение?
public class A : BaseClass
{
/*other properties and code */
public event EventHandler OnChange;
private bool _hasChanged;
public bool HasChanged
{
get { return _hasChanged; }
set
{
_hasChanged = value;
//only need to notify when we've changed.
if (value)
{
if (OnChange != null)
OnChange(this, EventArgs.Empty);
}
}
}
}
4 ответа
Что если мы не будем использовать наследование на мгновение?
Предположим, вместо того чтобы наследовать от общего базового класса, составьте свой клиентский класс, для которого требуется механизм событий, с объектом, реализующим механизм событий.
Предположим, наш класс
public class EventNotifier
{
public event EventHandler OnChange;
private bool _hasChanged;
public bool HasChanged
{
get { return _hasChanged; }
set
{
_hasChanged = value;
//only need to notify when we've changed.
if (value)
{
if (OnChange != null)
OnChange(this, EventArgs.Empty);
}
}
}
}
2-
public class A
{
private EventNotifier eventNotifier;
public EventNotifier MyEventNotifier { get { return eventNotifier; } }
public A()
{
eventNotifier = new EventNotifier();
}
}
3- Теперь ваши пользователи класса A (класс, который унаследован / составлен класс A)
это для, если B содержит A
public class b
{
A obj ;
public b()
{
obj = new A();
obj.MyEventNotifier.OnChange += new EventHandler(delegate { Console.WriteLine("Hi"); });
obj. MyEventNotifier.HasChanged = true;
}
}
Рассмотрим подход аспектно-ориентированного программирования, подобный тому, который использовался в этом примере PostSharp. Это позволит вам внедрить такой тип шаблонного кода с использованием атрибутов.
Если вы создали соответствующий аспект, вы могли бы иметь такой код:
public class A : BaseClass
{
public event EventHandler OnChanged;
[ChangedNotify("OnChanged")]
public bool HasChanged { get; set; }
}
или, если идея состоит в том, чтобы иметь один OnChange
событие для нескольких свойств, вы можете просто жестко закодировать это в аспекте, сократив ваш код до
public class A : BaseClass
{
[NotifyOnChanged]
public bool HasChanged { get; set; }
}
Вы могли бы рассмотреть введение промежуточного класса между BaseClass и A,B,C, который содержит общее поведение. Таким образом, вы не будете загрязнять E,F,G, которые не нуждаются в поведении.
BaseClass
-----------------------------
| |
----- NotifyBaseClass
E,F,G |
-----
A,B,C
NB. Несмотря на то, что AOP выглядит аппетитно, у меня были серьезные проблемы при попытке заставить Postsharp работать с другими технологиями, такими как MS Code Analysis и MSBuild.
Подкласс для объектов, подлежащих уведомлению, может быть хорошим способом, но он может быть сложным с аспектами, умножающими этот путь в широком диапазоне различных классов. Другой способ - включить его в базовый класс и определить интерфейс для него, после чего вы можете просто прикрепить интерфейс для соответствующих классов.
Когда вы запускаете, вы просто проверяете, является ли это IChangeable (или чем-то еще), и затем подключаетесь только к событию.