|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Практичний
приклад: спеціалізоване сортування
Попередні приклади виглядають штучно і відносяться до категорії «іграшкових програм». У цьому розділі ми покажемо, як використовувати делегати при спеціалізованому сортуванні — одній із стандартних сфер застосування функцій зворотного виклику. Загальна ідея полягає в тому, що один метод сортування залежно від ситуації може використовувати різні критерії сортування. Припустимо, у вас є масив імен: «Mike Item», «Dave Mendlen», «Alan Carter», «Tony Goodhew», «Ari Bixhorn», «Susan Warren»-. Якщо викликати
метод Sort класу Array, сортування буде проведено по іменах. А якщо ви хочете
відсортувати масив по прізвищах? Щоб
масив підтримував сортування по іменах, слід визначити клас з декількома
методами 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 а 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 а 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 і дізнається, по якому критерію повинне здійснюватися
порівняння.
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||