( q u e u e M e d i u m . C o u n t = = 0 ) & ( q u e u e L o w . C o u n t = = 0 ) ;
/}/ C o u n t - С к о л ь к о в с е г о э л е м е н т о в
|
|
|
|
p u b l i c i n t C o u n t / / |
Р е а л и з у е м к а к |
{ |
// |
д л я ч т е н и я |
|
g e t { r e t u r n q u e u e H i g h . C o u n t |
+ |
|
q u e u e M e d i u m . C o u n t + |
|
q u e u e L o w . C o u n t ; |
} |
в о в с е х о ч е р е д я х ? |
} |
|
с в о й с т в о т о л ь к о |
|
}
}
/ / P a c k a g e |
- пример |
к л а с с а , |
который может быть р а з м е щ е н в |
// о ч е р е д и с п р и о р и т е т а м и |
|
c l a s s P a c k a g e : I P r i o r i t i z a b l e |
{ |
|
|
|
p r i v a t e |
P r i o r i t y |
p r i o r i t y ; |
/ / К о н с т р у к т о р |
|
|
p u b l i c P a c k a g e ( P r i o r i t y |
p r i o r i t y ) |
{ |
|
|
|
t h i s . p r i o r i t y = |
p r i o r i t y ; |
}
/ / P r i o r i t y - в о з в р а щ а е т п р и о р и т е т п а к е т а ; т о л ь к о д л я / / ч т е н и я
p u b l i c |
P r i o r i t y |
P r i o r i t y |
|
|
g e t |
{ r e t u r n p r i o r i t y ; } |
|
|
} |
|
|
|
|
/ / А также методы |
T o A d d r e s s , |
F r o m A d d r e s s , |
I n s u r a n c e , |
/ / и |
д р у г и е . . . |
|
|
|
} |
|
|
|
|
// К л а с с |
P a c k a g e F a c t o r y опущен |
- с м . полную |
версию на |
/ / п р и л а г а е м о м к о м п а к т - д и с к е
}
Демонстрационная программа P r i o r i t y Q u e u e несколько длиннее прочих демон
страционных программ в книге, поэтому внимательно рассмотрите каждую ее часть.
Распаковка пакета
Класс P a c k a g e преднамеренно очень прост и написан исключительно для данной демонстрационной программы. Основное в нем — часть с приоритетом, хотя реаль ный класс P a c k a g e , несомненно, должен содержать массу других членов. Все, что требуется классу P a c k a g e для участия в данном пакете — это член-данные для хра нения приоритета, конструктор для создания пакета с определенным приоритетом и метод (реализованный здесь как свойство только для чтения) для возврата значения приоритета.
Требуют пояснения два аспекта класса P a c k a g e : тип приоритета и интерфейс
I P r i o r i t i z a b l e , реализуемый данным классом.
Оп р еделение возможных приоритетов
Приоритеты представляют собой перечислимый тип (enum) под названием Prior i t y . Он выглядит следующим образом:
352 |
Часть V. За базовыми классами |
//Priority - в м е с т о ч и с л о в ы х п р и о р и т е т о в н а п о д о б и е 1, 2, // 3, . . . и с п о л ь з у е м п р и о р и т е т ы с именами
e n u m P r i o r i t y
{
Low, Medium, H i g h
{
Реализация интерфейса IPrioritizable
Любой объект, поступающий в P r i o r i t y Q u e u e , должен знать собственный при оритет (общий принцип объектно-ориентированного программирования гласит, что кажцый объект отвечает сам за себя).
Можно просто неформально убедиться, что класс P a c k a g e имеет член для получения его приоритета, но лучше заставить компилятор проверять это требование, т.е. то, что у любого объекта, помещаемого в P r i o r i t y Q u e u e , имеется этот член.
Один из способов обеспечить это состоит в требовании, чтобы все объекты реализовывали интерфейс I P r i o r i t i z a b l e :
// I P r i o r i t i z a b l e - о п р е д е л я е м п о л ь з о в а т е л ь с к и й и н т е р ф е й с :
// |
классы, |
к о т о р ы е |
м о г у т |
быть |
д о б а в л е н ы в P r i o r i t y Q u e u e , |
II |
должны |
р е а л и з о в ы в а т ь |
э т о т |
и н т е р ф е й с |
interface |
I P r i o r i t i z a b l e |
|
|
|
P r i o r i t y P r i o r i t y |
{ g e t ; |
} |
|
|
Запись { g e t ; } определяет, |
как должно быть описано свойство в объявлении |
интерфейса. Обратите внимание, что тело функции доступа g e t отсутствует, но интерфейс указывает, что свойство P r i o r i t y — только для чтения и воз вращает значение перечислимого типа P r i o r i t y .
Класс |
P a c k a g e |
реализует интерфейс путем предоставления реализации свойства |
Priority: |
|
public |
P r i o r i t y |
P r i o r i t y |
get { |
r e t u r n |
p r i o r i t y ; } |
Функция Main()
Перед тем как приступить к исследованию класса P r i o r i t y Q u e u e , стоит посмот реть, как он применяется на практике. Вот исходный текст функции Main ( ) :
//Main |
- |
з а п о л н я е м |
о ч е р е д ь |
с п р и о р и т е т а м и |
п а к е т а м и , |
// затем |
и з в л е к а е м |
из о ч е р е д и их с л у ч а й н о е |
к о л и ч е с т в о |
s t a t i c |
v o i d Main ( s t r i n g [ ] |
a r g s ) |
|
{
C o n s o l e . W r i t e L i n e ( " С о з д а н и е о ч е р е д и с п р и о р и т е т а м и : " ) ; P r i o r i t y Q u e u e < P a c k a g e > pq =
new P r i o r i t y Q u e u e < P a c k a g e > ( ) ;
C o n s o l e . W r i t e L i n e ( " Д о б а в л я е м с л у ч а й н о е к о л и ч е с т в о " + |
|
Глава 15. Обобщенное программирование |
353 |
" (0 - 20) случайных п а к е т о в " +
|
|
* |
|
" в о ч е р е д ь : " ) ; |
P a c k a g e p a c k ; |
|
|
|
|
|
P a c k a g e F a c t o r y f a c t |
= |
new P a c k a g e F a c t o r y ( ) ; |
// |
Нам |
нужно |
с л у ч а й н о е |
ч и с л о , |
меньшее 2 0 |
Random |
r a n d = |
new Random () ; |
|
|
/ / |
Случ айно е |
ч и с л о |
в |
д и а п а з о н е |
0 - 2 0 |
i n t n u m T o C r e a t e = r a n d . N e x t ( 2 0 ) ; |
|
C o n s o l e . W r i t e L i n e ( " ^ С о з д а н и е |
{0} |
п а к е т о в : " , |
|
|
|
n u m T o C r e a t e ) ; |
|
f o r ( i n t i = 0; i < n u m T o C r e a t e ; i + + )
{
C o n s o l e . W r i t e ( " \ t \ t T e H e p a u H H и д о б а в л е н и е " + " с л у ч а й н о г о п а к е т а { о } " , i ) ;
p a c k = f a c t . C r e a t e P a c k a g e ( ) ;
C o n s o l e . W r i t e L i n e ( " с п р и о р и т е т о м { о } " , p a c k . P r i o r i t y ) ;
p q . E n q u e u e ( p a c k ) ;
}
C o n s o l e . W r i t e L i n e ( " Ч т о п о л у ч и л о с ь : ") ; i n t n T o t a l = p q . C o u n t ;
C o n s o l e . W r i t e L i n e ( " П о л у ч е н о п а к е т о в : { о } " , n T o t a l ) ; C o n s o l e . W r i t e L i n e ( " И з в л е к а е м с л у ч а й н о е к о л и ч е с т в о " +
|
|
|
|
" п а к е т о в : 0-2 0 : " ) ; |
i n t |
numToRemove |
= |
r a n d . N e x t ( 2 0 ) ; |
|
C o n s o l e . W r i t e L i n e ( " ^ И з в л е к а е м |
{0} |
п а к е т о в " , |
|
|
|
|
numToRemove); |
|
|
f o r |
( i n t i |
= 0; |
i |
< numToRemove; |
i + + ) |
{ |
|
|
|
|
|
|
|
p a c k = p q . D e q u e u e ( ) ; |
|
|
|
i f |
( p a c k |
! = n u l l ) |
|
|
|
{ |
|
|
|
|
|
|
|
|
C o n s o l e . W r i t e L |
|
|
i n e ( " \ t \ t Д о с т а в к а п а к е т а |
|
|
|
|
" с |
п р и о р и т е т о м {О}", |
|
|
|
|
p a c k . P r i o r i t y ) ; |
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/ / С к о л ь к о п а к е т о в " д о с т а в л е н о " |
|
|
C o n s o l e . W r i t e L i n e ( " Д о с т а в л е н о { о } |
п а к е т о в " , |
|
|
|
|
n T o t a l - p q . C o u n t ) ; |
/ / Ожидаем |
п о д т в е р ж д е н и я |
п о л ь з о в а т е л я |
C o n s o l e . W r i t e L i n e ( " Н а ж м и т е < E n t e r > д л я " +
" з а в е р ш е н и я п р о г р а м м ы . . . " ) ;
C o n s o l e . R e a d ( ) ;
Итак, что же происходит в функции Main () ?
1. Инстанцируется объект P r i o r i t y Q u e u e для типа P a c k a g e .
2.Создается объект P a c k a g e F a c t o r y , работа которого состоит в формировании новых пакетов со случайно выбранными приоритетами. (Фабрика— это класс или метод, который создает для вас объекты.)
354 |
Часть V. За базовыми классами |
3.Для генерации случайного числа используется класс Random из библиотеки
.NET, а затем вызывается P a c k a g e F a c t o r y для создания соответствующего
количества новых объектов P a c k a g e со случайными приоритетами.
4.Выполняется добавление созданных пакетов в P r i o r i t y Q u e u e с помощью вы зова p g . E n q u e u e ( p a c k ) .
5.Выводится число созданных пакетов, после чего некоторое случайное их количе ство извлекается из P r i o r i t y Q u e u e .
6.Функция завершается выводом количества извлеченных из P r i o r i t y Q u e u e па кетов.
Написание обобщенного кода
Как же написать собственный обобщенный класс со всеми этими <Т>? Выглядит это, конечно, устрашающе, но все не так уж и страшно.
Простейший путь написания обобщенного класса состоит в создании сначала его необобщенной версии, а затем расстановки в ней всех этих <Т>. Так, на пример, вы можете написать класс P r i o r i t y Q u e u e для объектов P a c k a g e , протестировать его, а затем "обобщить".
Вот небольшая часть необобщенного класса P r i o r i t y Q u e u e для иллюстрации ска
занного: |
|
|
|
|
|
|
public c l a s s |
P r i o r i t y Q u e u e |
|
|
|
{ |
|
|
|
|
|
|
//Queues |
- |
т р и в н у т р е н н и е ( о б о б щ е н н ы е ! ) |
о ч е р е д и |
p r i v a t e 1 |
Q u e u e < P a c k a g e > |
q u e u e H i g h |
= |
new |
Q u e u e < P a c k a g e > ( ) ; |
p r i v a t e |
Q u e u e < P a c k a g e > |
q u e u e M e d i u m |
= |
new |
Q u e u e < P a c k a g e > ( ) ; |
p r i v a t e |
Q u e u e < P a c k a g e > |
queueLow |
= |
new |
Q u e u e < P a c k a g e > ( ) ; |
//Enqueue - н а о с н о в а н и и п р и о р и т е т а P a c k a g e д о б а в л я е м е г о // в соответствующую о ч е р е д ь
p u b l i c v o i d E n q u e u e ( P a c k a g e i t e m )
{
s w i t c h ( i t e m . P r i o r i t y ) / / P a c k a g e и м е е т э т о с в о й с т в о
{
c a s e P r i o r i t y . H i g h :
q u e u e H i g h . E n q u e u e ( i t e m ) ; b r e a k ;
c a s e P r i o r i t y . L o w :
q u e u e L o w . E n q u e u e ( i t e m ) ; b r e a k ;
c a s e P r i o r i t y . M e d i u m :
q u e u e M e d i u m . E n q u e u e ( i t e m ) ; b r e a k ;
}
}
/ / и т а к д а л е е . . .
Написание необобщенного класса упрощает тестирование его логики. Затем, после тести рования и исправления всех ошибок, вы можете сделать контекстную замену P a c k a g e на <Т> (конечно, все не так прямолинейно, но и не очень отличается от сказанного).
355
Обобщенная очередь с приоритетами
Теперь пришло время разобраться с основным классом, из-за которого все и затева лось — с обобщенным классом P r i o r i t y Q u e u e .
Внутренние очереди
Класс P r i o r i t y Q u e u e — оболочка, за которой скрываются три обычных объекта Queue<T>, по одному для каждого уровня приоритета. Вот первая часть исходного тек ста P r i o r i t y Q u e u e , в которой показаны эти три внутренние очереди:
/ / P r i o r i t y Q u e u e |
- обобщенный |
к л а с с о ч е р е д и с п р и о р и т е т а м и ; |
// типы данных, |
д о б а в л я е м ы х в |
о ч е р е д ь , о б я з а н ы |
/ / р е а л и з о в ы в а т ь и н т е р ф е й с I P r i o r i t i z a b l e c l a s s P r i o r i t y Q u e u e < T >
w h e r e T : I P r i o r i t i z a b l e
{
/ / Q u e u e s - т р и в н у т р е н н и е ( о б о б щ е н н ы е ! ) о ч е р е д и
p r i v a t e |
Queue<T> |
q u e u e H i g h |
= |
new |
Q u e u e < T > ( ) ; |
p r i v a t e |
Queue<T> |
queueMedium |
= |
new |
Q u e u e < T > ( ) ; |
p r i v a t e |
Queue<T> |
queueLow |
= |
new |
Q u e u e < T > ( ) ; |
/ / Все |
о с т а л ь н о е |
м ы в о т - в о т |
р а с с м о т р и м . . . |
В данных строках объявляются три закрытых члена-данных типа Queue<Т>, ини циализируемые путем создания соответствующих объектов Queue<T>.
Метод Enqueue()
E n q u e u e О добавляет элемент типа Т в P r i o r i t y Q u e u e . Работа состоит в том, чтобы выяснить приоритет элемента и поместить его в соответствующую приоритету очередь. В первой строке метод получает приоритет элемента и использует конструкцию s w i t c h для определения целевой очереди исходя из полученного значения. -Например, получив элемент с приоритетом P r i o r i t y . H i g h , метод E n q u e u e () помещает его в очередь q u e u e H i g h . Вот исходный текст метода P r i o r i t y Q u e u e . E n q u e u e ():
// |
Д о б а в л я е т э л е м е н т Т в о ч е р е д ь на о с н о в а н и и з н а ч е н и я е г о |
/ / |
п р и о р и т е т а |
p u b l i c v o i d E n q u e u e ( Т i t e m ) |
{ |
|
|
s w i t c h ( i t e m . P r i o r i t y ) |
/ / |
Т р е б у е т р е а л и з а ц и и |
{ |
/ / |
I P r i o r i t i z a b l e |
c a s e P r i o r i t y . H i g h : |
|
|
q u e u e H i g h . E n q u e u e ( i t e m ) ; b r e a k ;
c a s e P r i o r i t y . L o w :
q u e u e L o w . E n q u e u e ( i t e m ) ; b r e a k ;
c a s e P r i o r i t y . M e d i u m :
q u e u e M e d i u m . E n q u e u e ( i t e m ) ; b r e a k ;
d e f a u l t :
t h r o w new
A r g u m e n t O u t O f R a n g e E x c e p t i o n ( i t e m . P r i o r i t y . T o S t r i n g ( ) ,
356 |
Часть V. За базовыми классам |