Да, но программирование шаблона наблюдателя явно и, следовательно, без использования делегатов и событий, может привести к более легкой отладке вашего кода.
Рассмотрим разницу:
public void NotifyObservers()
{
foreach(Product product in ProductList)
{
if (product is IProductObserver)
{
product.Update(this)
}
}
}
Здесь очень ясно, какие продукты в списке получают уведомления об изменениях. Во время отладки вы можете проверить ProductList ...
С использованием делегатов и событий может быть более громоздким узнать, сколько "делегатов" было фактически "подписано" для обработки события.