Использование делегатов: бизнес-приложения - PullRequest
6 голосов
/ 10 марта 2009

Фон

Учитывая, что «большинство» разработчиков являются разработчиками бизнес-приложений, функции наших любимых языков программирования используются в контексте того, что мы делаем с ними.

Как разработчик приложений на C # / ASP.NET, я склонен использовать делегатов только при работе с событиями пользовательского интерфейса. На самом деле (и это часть моего показа неопытности), я даже не знаю хорошего контекста, кроме событий для использования делегатов в! Это довольно страшно; но я понимаю, что в этой лодке есть и другие разработчики.

NB : ответы должны относиться к .NET 2.0. .NET 3.0 переносит делегатов на совершенно другой уровень, и это, вероятно, будет отдельным вопросом.

Вопрос:

Помимо событий, насколько полезны делегаты и в каких контекстах бизнес-приложений они наиболее полезны?

Обновление : Джаррод Диксон полезно связан с документацией MSDN относительно использования делегата , и я должен признать, что мой любимая книга шаблонов проектирования вообще не вызывала делегатов, поэтому я не видел их в использовании, кроме как для событий пользовательского интерфейса. Чтобы расширить этот вопрос (чуть-чуть!), Какие примеры вы можете привести для бизнес-приложений (или, на самом деле, для любого приложения, имеющего дело с соответствующей проблемой), которые облегчили бы усвоение документации MSDN по теме?

Ответы [ 8 ]

4 голосов
/ 10 марта 2009

Я думаю, что этот вопрос отражает множество способов кожи кошки. Я считаю, что делегаты (и лямбды) почти так же фундаментальны, как и цикл for.

Вот один контекст, в котором я недавно использовал делегатов (форматирование и имена изменены в целях презентации:)

protected T[] SortLines<T>(Func<T> createLine, IEnumerable<T> unsorted)
where T : LineType
{
    Func<IEnumerable<T>, IEnumerable<T>> sorter = (lines => lines);

    switch (settings.OrderSort)
    {
        case OrderSort.ByA: 
            sorter = (lines => lines.OrderBy(x => x.A)); break;
        case OrderSort.ByB:
            sorter = (lines => lines.OrderBy(x => x.B)); break;

        // and so on... a couple cases have several levels of ordering
    }

    bool requiresSplit = // a complicated condition
    if (requiresSplit)
    {
        var positives = unsorted.Where(x => x.Qty >= 0);
        var negatives = unsorted.Where(x => x.Qty <  0);

        return sorter(negatives).Concat(
               new T[] { createLine.Invoke() }).Concat(
               sorter(positives)).ToArray();
    }
    else
        return sorter(unsorted).ToArray();
}

Таким образом, это сортирует группу элементов на основе некоторых критериев, а затем либо возвращает весь отсортированный список, либо разбивает его на две части, сортирует обе половины по отдельности и помещает разделитель между ними. Удачи в том, чтобы делать это элегантно, если вы не можете выразить концепцию «способа сортировки чего-либо», для чего и нужен делегат.

РЕДАКТИРОВАТЬ: Я думаю, Concat и OrderBy специфичны для 3.0, но это все еще основная идея.

2 голосов
/ 10 марта 2009

Еще одно замечательное использование делегатов в качестве конечных автоматов. Если логика вашей программы содержит повторяющиеся операторы if ... then для управления ее состоянием или если вы используете сложные блоки переключателей, вы можете легко использовать их для репликации шаблона State.

enum State {
  Loading,
  Processing,
  Waiting,
  Invalid
}

delegate void StateFunc();

public class StateMachine  {
  StateFunc[] funcs;   // These would be initialized through a constructor or mutator
  State curState;

  public void SwitchState(State state)  {
    curState = state;
  }

  public void RunState()  {
    funcs[curState]();
  }
}

Мой синтаксис делегата 2.0 может быть ржавым, но это довольно простой пример диспетчера состояний. Также помните, что делегаты в C # могут выполнять более одной функции, что позволяет вам иметь конечный автомат, который выполняет произвольно много функций каждая RunState ().

2 голосов
/ 10 марта 2009

Насколько мне известно, делегат .NET - это, по сути, реализация интерфейса с одним методом, без всякого объявления класса. Я бы хотел, чтобы они были на Яве, лично. Подумайте о классе компаратора:

class MyComparator<Circle> extends Comparator<Circle> {
    public int compare(Circle a, Circle b) {
        return a.radius - b.radius;
    }
}

В любом случае этот шаблон полезен, вместо него может быть полезен делегат.

Я надеюсь, что я прав, но продолжайте и проголосуйте за меня, если я ошибаюсь; прошло слишком много времени с тех пор, как я увидел C #:)

2 голосов
/ 10 марта 2009

Кроме графического интерфейса ...

  1. отправка событий; некоторые из моих бизнес-приложений довольно сложны, общаются с аппаратными устройствами и полагаются на очереди событий, чтобы все синхронизировать. Эти приложения используются делегатами для отправки событий.
  2. бизнес-правила; некоторые из моих бизнес-приложений имеют возможность частичного программного кодирования, когда определенные события вызывают определенные правила, которые хранятся в базе данных. Делегаты (в словаре) используются для выполнения правил на стороне клиента. (Плагины могут поддерживаться, но ток не требуется).
  3. общие вторичные потоки (конечно, используя класс SafeThread!)
1 голос
/ 10 марта 2009

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

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

1 голос
/ 10 марта 2009

Делегаты становятся чрезвычайно могущественными, когда вы начинаете рассматривать их как функциональные конструкции

.Net 2.0 включал поддержку анонимных делегатов, которые сформировали ядро ​​некоторых функциональных концепций, которые были расширены Linq. Синтаксис для анонимного делегата несколько громче, чем у Lambda, но в 2.0 есть множество основных функциональных шаблонов.

В универсальном типе List у вас есть следующие элементы, с которыми вы можете работать:

  1. ConvertAll () - использует делегата для преобразования всех членов списка в другой тип (T). Это в основном реализация функции карты
  2. Find () и FindAll, оба принимают делегатов и возвращают вам либо один элемент (в случае Find ()), либо все элементы, из-за которых переданный делегат оценивается как true. Это обеспечивает функцию фильтра, а также определение предиката (функция, которая оценивает логическое значение)
  3. Существует реализация метода ForEach (), который принимает делегат. Позволяет вам выполнить произвольную операцию против каждого элемента в списке.

Appart from List, если вы используете контекст анонимных делегатов правильно, так что вы можете реализовать Closure как структуры. Или, на более практическом уровне, сделайте что-то вроде:

ILog logger = new Logger();
MyItemICareAbout.Changed += delegate(myItem) { logger.Log(myItem.CurrentValue); };    

И это просто работает.

Существует также материал DynamicMethod, который позволяет вам определять биты IL (используя Reflection.Emit) и компилировать их как делегаты. Это дает вам хорошую альтернативу чистому отражению для таких вещей, как слои отображения и код доступа к данным.

Делегаты - это действительно конструкция, которая позволяет вам представлять исполняемый код в виде данных. Как только вы поймете, что это значит, можно сделать множество вещей. Поддержка этих конструкций в 2.0 была зачаточной по сравнению с 3.5, но все еще существует и все еще довольно мощна.

1 голос
/ 10 марта 2009

Один из распространенных шаблонов, которые я видел на протяжении многих лет (на разных языках), - это «заморозить» результат решения переместить логику из цикла в установку. В псевдокоде (поскольку техника зависит от языка):

some_condition = setup_logic
...
while (not terminated) {
    data = obtain_data
    if (some_condition)
        process_one (data)
    else
        process_two (data)
}

Дело в том, что если some_condition не изменяется в зависимости от чего-либо в цикле, то его повторное тестирование действительно бесполезно. Делегаты / закрытия / и т.д.. позвольте вышеупомянутому быть замененным этим:

some_condition = setup_logic
if (some_condition)
    selected_process = process_one
else
    selected_process = process_two
...
while (not terminated) {
    data = obtain_data
    selected_process (data)
}

(Конечно, настоящий функциональный программист написал бы установку как:

selected_process = if (some_condition) process_one else process_two

; -)

Это хорошо обобщает несколько вариантов (вместо двух). Основная идея заключается в том, чтобы заранее решить, какое действие предпринять в будущем (или точках), а затем запомнить выбранное действие , а не значение , на котором было основано решение.

1 голос
/ 10 марта 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...