Издатель-подписчик (шаблон наблюдателя) со слабыми ссылками - PullRequest
0 голосов
/ 16 марта 2019

У меня есть ситуация, когда у нас есть долгоживущий набор данных (издатель), который предоставляется пользователю с помощью WinForms (подписчики).Поскольку данные модифицируются, мы хотим, чтобы пользовательский интерфейс также обновлялся.Первоначальная идея заключалась в том, чтобы использовать события и подписывать пользовательский интерфейс на события на издателе.Однако это приведет к утечке памяти, поскольку данные устаревают из различных частей пользовательского интерфейса, которые могут приходить и уходить, представляя его.

Выполняя небольшое копание, я наткнулся на WeakEventManager и связанный с ним шаблон на MSDN .Хотя это выглядит как решение, оно вводит не совсем базовое изменение шаблона использования посредника (пользовательская реализация WeakEventManager) между издателем и подписчиком.В нашем магазине разработчики постоянно переключаются между продуктами и языками, и я обеспокоен тем, что через 10 лет бедному разработчику, обслуживающему код, придется потратить слишком много времени, пытаясь понять WeakEventManager и этот шаблон.

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

Подписчики будут реализовывать такой интерфейс, как:

public interface IDataChangedListener
{
    void OnDataChanged(Object model);
}

И у издателя будет что-то вроде этого:

    private static List<WeakReference> listeners = new List<WeakReference>();

    public static void AddListener(IDataChangedListener listener)
    {
        lock (listener)
        {
            listeners.Add(new WeakReference(listener));
        }
    }

    public static void RemoveListener(IDataChangedListener listener)
    {
        lock (listener)
        {
            listeners.RemoveAll(x => x.Target == listener);
        }
    }

    private static void NotifyListeners(object model)
    {
        lock (listeners)
        {
            listeners.RemoveAll(x => !x.IsAlive); //Purge
            foreach (IDataChangedListener listener in listeners)
            {
                if (listener != null)
                {
                    listener.OnDataChanged(model);
                }
            }
        }
    }

Мысли?

...