C# Шаблон наблюдателя с обобщениями - PullRequest
2 голосов
/ 19 июня 2020

Я пытаюсь изучить шаблон Observer после прочтения документации MSDN: https://docs.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern. При использовании с наследованием он вызывает ошибки и не позволяет мне создавать общих наблюдателей. Ниже мой код:

interface Book { }

class ComicBook : Book { }
class ComicBookObserver : IObserver<ComicBook>
{
    public void OnCompleted() { throw new NotImplementedException(); }
    public void OnError(Exception error) { throw new NotImplementedException(); }
    public void OnNext(ComicBook value) { throw new NotImplementedException(); }
}

class Publisher : IObservable<Book>
{
    private List<IObserver<ComicBook>> ComicBookObservers = new List<IObserver<ComicBook>>();
    public IDisposable Subscribe(IObserver<Book> observer) 
    {
        if (observer is IObserver<ComicBook>)
            ComicBookObservers.Add(observer);
        return null;
    }
}

class Main
{
    public static void main(string[] args)
    {
        Publisher p = new Publisher();
        p.Subscribe(new ComicBookObserver());
    }
}

Я получаю сообщение об ошибке на p.Subscribe(new ComicBookObserver());:

Cannot convert from 'ComicBookObserver' to 'System.IObserver<Book>'

Почему это так, ведь комикс - это тоже книга. Разве это не разрешено? Придется ли мне создавать Subcribe методов для всех типов книг?

Ответы [ 2 ]

2 голосов
/ 19 июня 2020

В вашем примере ComicBookObserver реализует IObserver<ComicBook>, поэтому он хочет видеть ComicBook.

Publisher реализует IObservable<Book>, поэтому он выводит Book.

Интерфейс Book не соответствует более производному типу ComicBook, необходимому для ComicBookObserver.

Если вам нужно соблюдать определенные типы c, тогда да, вам нужно будет подписаться несколько раз с подписчиками укажите c для этих типов.

Вы можете использовать метод Rx OfType<ComicBook>() для создания нового наблюдаемого из вашего IObservable<Book>.

Например:

Publisher p = new Publisher();
p.OfType<ComicBook>().Subscribe(new ComicBookObserver());

Это имеет то преимущество, что будут наблюдаться только элементы типа ComicBook, и вам не нужно будет выполнять какие-либо дополнительные проверки типа.

2 голосов
/ 19 июня 2020

Думаю, вы можете продолжить узор, но добавить одну морщинку. Я бы сделал, чтобы наблюдатель ComicBook реализовал IObserver<Book>, а затем в вашей реализации вам нужно было бы обработать ComicBook элементов и отбросить остальные. возможно, вы будете подписывать других наблюдателей на другие типы книг. они также будут следовать этому образцу.

interface Book { }

class ComicBook : Book { }
class OtherBook : Book { }
class ComicBookObserver : IObserver<Book>
{
    public void OnCompleted() { throw new NotImplementedException(); }
    public void OnError(Exception error) { throw new NotImplementedException(); }
    public void OnNext(Book value) 
    {   
        if (value is ComicBook)
        {
            // logic for Comic Book values
        }
    }
}

class OthereBookObserver : IObserver<Book>
{
    public void OnCompleted() { throw new NotImplementedException(); }
    public void OnError(Exception error) { throw new NotImplementedException(); }
    public void OnNext(Book value) 
    {   
        if (value is OtherBook)
        {
            // logic for other book values
        }
    }
}

class Publisher : IObservable<Book>
{
    public IDisposable Subscribe(IObserver<Book> observer) { throw new NotImplementedException(); }
}

class Main
{
    public static void main(string[] args)
    {
        Publisher p = new Publisher();
        p.Subscribe(new ComicBookObserver());
        p.Subscribe(new OtherBookObserver());
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...