Практический пример: специализированная сортировка
Практический пример: специализированная сортировка
Предыдущие примеры выглядят искусственно и относятся к категории «игрушечных программ». В этом разделе мы покажем, как использовать делегаты при специализированной сортировке — одной из стандартных областей применения функций обратного вызова. Общая идея заключается в том, что один метод сортировки в зависимости от ситуации может использовать разные критерии сортировки. Предположим, у вас имеется массив имен: «Mike Item», «Dave Mendlen», «Alan Carter», «Tony Goodhew», «Ari Bixhorn», «Susan Warren»-.
Если вызвать метод Sort класса Array, сортировка будет произведена по именам. А если вы хотите отсортировать массив по фамилиям?
Возможный подход к решению этой задачи описан в главе 5 — вы можете написать собственную реализацию интерфейса IComparer и передать ее Sort. Применение обратного вызова на базе делегатов выглядит чуть более элегантно и теоретически обладает большей гибкостью, поскольку программист может определить собственные процедуры сортировки, которые в конкретной ситуации работают эффективнее стандартных алгоритмов.
Чтобы массив поддерживал сортировку по именам, следует определить класс с несколькими методами Compare и при помощи делегата связать алгоритм сортировки с нужным методом Compare через механизм обратного вызова. В частности, это позволит динамически изменять критерий сортировки во время работы программы.
Прежде всего определяется класс, выполняющий сортировку. Чтобы избежать подробного обсуждения различных алгоритмов сортировки, мы воспользуемся простейшим алгоритмом волновой сортировки:
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 и узнает, по какому критерию должно осуществляться сравнение.