Ужасные "Обратные цепи" в приложении winforms - PullRequest
2 голосов
/ 29 сентября 2011

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

В качестве примера, свободно основанного на этом коде, может существовать класс «Manager», который порождает класс «SetUpWorkerThreads», который создает поток «HandleWorker» для, скажем, 10 рабочих. Рабочий поток должен иногда вызывать класс менеджера, для этого код выглядит так:

public class Manager
{
    public delegate void SomethingHappenedHandler();

    private void Init()
    {
        var x = new SetUpWorkerThreads(SomethingHappened);
    }

    private void SomethingHappened()
    {
        // Handle something happened
    }

}

public class SetUpWorkerThreads
{
    private readonly Manager.SomethingHappenedHandler _somethingHappened;

    public SetUpWorkerThreads(Manager.SomethingHappenedHandler somethingHappened)
    {
        _somethingHappened = somethingHappened;
    }

    public void SetupTheThreads()
    {
        // Contrived!
        for (int x=0; x<10; x++)
        {
            var worker = new Worker(_somethingHappened);
            new Thread(worker.DoingSomething).Start();
        }
    }
}

public class Worker
{
    private readonly Manager.SomethingHappenedHandler _somethingHappened;

    public Worker(Manager.SomethingHappenedHandler somethingHappened)
    {
        _somethingHappened = somethingHappened;
    }

    public void DoingSomething()
    {
        // ... Do Something
        _somethingHappened();
    }
}

В действительности может быть задействовано гораздо больше классов, каждый из которых передает массу обратных вызовов для разных вещей. Я понимаю, что плохой дизайн классов / приложений играет в этом роль, но есть ли более эффективные способы обработки этих взаимодействий между классами, особенно в приложениях winforms и когда происходит много потоков?

1 Ответ

2 голосов
/ 29 сентября 2011

Я не вижу, что многопоточность делает его более или менее проблематичным.
Одна альтернатива - использовать события вместо обратных вызовов, но это не разорвет длинные цепочки и даст вам ад отписки.

Один из возможных подходов - создать объект, отвечающий за обработку всех событий. Либо как одиночный объект, либо как отдельный объект, который вы передаете всем своим потокам (вместо обратных вызовов). Тогда вы можете иметь простой интерфейс для объекта EventRouter для вызова событий из потоков. Затем вы можете подписаться на события в EventRouter, где вам нужно обрабатывать «что-то случилось».

Редактировать
Что-то паттерн GoF Mediator , но с поворотом издателя-подписчика.

...