Cамоучитель по VB.NET

       

Практический пример: специализированная сортировка



Предыдущие примеры выглядят искусственно и относятся к категории «игрушечных программ». В этом разделе мы покажем, как использовать делегаты при специализированной сортировке — одной из стандартных областей применения функций обратного вызова. Общая идея заключается в том, что один метод сортировки в зависимости от ситуации может использовать разные критерии сортировки. Предположим, у вас имеется массив имен: «Mike Item», «Dave Mendlen», «Alan Carter», «Tony Goodhew», «Ari Bixhorn», «Susan Warren»-.

Если вызвать метод Sort класса Array, сортировка будет произведена по именам. А если вы хотите отсортировать массив по фамилиям?

Возможный подход к решению этой задачи описан в главе 5 — вы можете написать собственную реализацию интерфейса IComparer и передать ее Sort. Применение обратного вызова на базе делегатов выглядит чуть более элегантно и теоретически обладает большей гибкостью, поскольку программист может определить собственные процедуры сортировки, которые в конкретной ситуации работают эффективнее стандартных алгоритмов.

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

Прежде всего определяется класс, выполняющий сортировку. Чтобы избежать подробного обсуждения различных алгоритмов сортировки, мы воспользуемся простейшим алгоритмом волновой сортировки:

  1. Начать с первого элемента.
  2. Последовательно просмотреть все остальные элементы. Если очередной элемент окажется меньше текущего первого элемента, поменять их местами.
  3. Начать со второго элемента, просмотреть все остальные элементы.
  4. Продолжать до последнего элемента. Основной код волновой сортировки выглядит так:

For i =bottom To (top - bottom) For j =i + 1 To top

If Stuff(j) < Stuff(i))Then

temp = Stuff(i)

Stuff(i) = Stuff(j)

Stuff(j) = temp

End If

Next j

Next I

Чтобы реализовать этот алгоритм с применением функций обратного вызова, необходимо определить класс Special Sort с делегатом, используемым при обратном вызове. Код этого класса приведен ниже:

1 Public Class Special Sort

2 ' Определение делегата

3 Public Delegate Function SpecialCompareCallback(ByVal flrstString _

As String,ByVal secondString As String) As Boolean

4 ' Определение процедуры, вызываемой делегатом

5 Public Shared Sub IfySort(ByVal Stuff As String()._

ByVal MyCompare As SpecialCompareCallback)

6 Dim i, j As Integer

7 Dim temp As String

8 Dim bottom As Integer = Stuff.GetLowerBound(0)

9 Dim top As Integer = Stuff.GetUpperBound(0)

10 For i = bottom To (top = bottom)

11 For j = i + 1 To top

12 If MyCompare(Stuff(j). Stuff(i)) Then

13 temp = Stuff(i)

14 Stuff(1) - Stuff (j)

15 Stuff(j) = temp

16 End If

17 Next j

18 Next i

19 End Sub

20 End Class

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

В строке 5 определяется общая процедура, одним из параметров которой является переменная с типом делегата. Таким образом, в ключевой строке 12:

If MyCompare(Stuff(j). Stuff(i)) Then

функция сравнения, инкапсулированная в делегате MyCompare, может относиться к другому классу! Например, если определить приведенный ниже класс, эта схема позволит использовать любой из его методов Compare (обратите внимание: методы Compare объявлены общими, поэтому для их вызова нам даже не нужно создавать конкретный экземпляр класса):

Public Class MyCustomCompare

Public Shared Function TheBasicComparetByVal firstString As String,

ByVal secondString As String) As Boolean

Return (firstString <- secondString)

End Function

Public Shared Function TheSpecialCompare(ByVal firstString As String.

ByVal secondString As String)As Boolean Dint tokensl,tokens2 As String()

tokensl = firstString.Split(Chr(32))

tokens2 = secondString.Split(Chr(32))

Return (tokensl(l) <- tokens2(l))

' Сравнение по фамилии!

End Function

End Class

Класс содержит две общие функции, которые ниже будут использованы для создания делегатов. Первая функция, TheBasicCompare, просто сравнивает строки в алфавитном порядке. Более интересная функция TheSpecialCompare предполагает, что строка передается в формате «имя фамилия», и сравнивает фамилии, выделяя их при помощи удобной функции Split.

Остается лишь создать экземпляры класса SpecialSort и делегаты. Это происходит в следующей функции Main (ключевые строки выделены жирным шрифтом):

1 Module Modulel

2 Sub Main()

3 Dim test()As String ={"Mike Iem"."Dave Mendlen"."Alan Carter".

4 "Tony Goodhew","An Bixhorn"."Susan Warren"}

5 ' Объявить переменную обратного вызова в форме класс.делегат

6 Dim MyCallBack As Special Sort.SpecialCompareCal1back

7 MyCallBack = AddressOf MyCustomCompare.TheBasicCompare

8 SpecialSort.MySort(test,MyCallBack)

9 Console.WriteLine("Here is a basic sort by FIRST name")

10 Dim temp As String

11 For Each temp In test

12 Console.WriteLine(temp)

13 Next

14 ' Передать другую процедуру сравнения

15 MyCallBack = AddressOf MyCustomCompare.TheSpecialCompare

16 Sped al Sort. MySort (test. MyCallBack)

17 Console.WriteLine()

18 Console.WriteLineC'Here is a sort by LAST name")

19 For Each temp In test

20 Console.WriteLine(temp)

21 Next

22 Console. ReadLine()

23 End Sub

24 End Module

В строке 6 объявляется «псевдоуказатель на функцию». Чтобы задать его значение, мы передаем адрес функции с правильной сигнатурой (строки 7-15). Поскольку функции объявлены общими, создавать экземпляр класса MyCustomCompare для этого не нужно. После создания делегата в строках 8 и 16 вызывается нужная процедура сортировки класса Special Sort. Поскольку при вызове MySort передается делегат, процедура обращается к классу MyCustomCompare и узнает, по какому критерию должно осуществляться сравнение.





Содержание раздела