ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 3241

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

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 ( ) ;

 

 

I P r i o r i t i z a b l e

p a c k

=

f a c t . C r e a t e P a c k a g e ( ) ;

/ /

Обратите

 

 

 

// внимание

на

интерфей с

C r e a t e P a c k a g e () использует генератор случайных чисел для генерации случая го числа от 0 до 2 включительно, и применяет сгенерированное число в качестве приори тета нового объекта 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 ) .

Еще немного о фабриках

Фабрики очень удобны для генерации большого количества тестовых дани! (фабрика не обязательно использует генератор случайных чисел — он потребо вался для конкретной демонстрационной программы P r i o r i t y Q u e u e ) .

Фабрики усовершенствуют программу, изолируя создание объектов. Каш раз при упоминании имени определенного класса в вашем исходном тексте! создаете зависимость (dependency) от этого класса. Чем больше таких завися мостей, тем больше степень связности классов, тем "теснее" они связаны дм с другом. Программистам давно известно, что следует избегать тесного CBHL вания. (Один из многих методов развязки (decoupling) заключается в примеви нии фабрик посредством интерфейсов, как, например, IPrioritizable! а не с использованием конкретных классов наподобие Package . ) Программ сты постоянно создают объекты непосредственно, с применением операм new, и это нормальная практика. Однако использование фабрик может сдем| код менее тесно связанным, а следовательно, более гибким.

Построение обобщенной фабрики

А если бы у вас был класс, который мог бы создавать любые необходима! вам объекты? Эту интересную концепцию достаточно легко спрограммирсвать, как видно из демонстрационной программы G e n e r i c l n t e r f a c e a прилагаемом компакт-диске.

/ /

G e n e r i c l n t e r f а с е - и с п о л ь з о в а н и е обобщенного

и н т е р ф е й с а

/ /

д л я

р е а л и з а ц и и обобщенной

фабрики

 

 

u s i n g S y s t e m ;

 

 

 

 

u s i n g S y s t e m . C o l l e c t i o n s . G e n e r i c ;

 

 

 

n a m e s p a c e G e n e r i c l n t e r f a c e

 

 

 

 

{

 

 

 

 

 

 

 

c l a s s

P r o g r a m

 

 

 

 

 

{

 

 

 

 

 

 

s t a t i c v o i d M a i n ( 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 ( " С о з д а н и е

фабрики д л я

"

+

 

 

" п р о и з в о д с т в а B l o b б е з п а р а м е т р о в " ) ;

 

G e n e r i c F a c t o r y < B l o b > b l o b F a c t =

 

 

 

 

new G e n e r i c F a c t o r y < B l o b > ( ) ;

 

 

 

C o n s o l e . W r i t e L i n e ( " С о з д а н и е

фабрики для

"

+

 

 

" п р о и з в о д с т в а S t u d e n t s , " +

 

 

" п а р а м е т р и з о в а н н ы х с т р о к о й " ) ;

 

G e n e r i c F a c t o r y l < S t u d e n t , s t r i n g > s t u F a c t =

 

 

new G e n e r i c F a c t o r y l < S t u d e n t ,

s t r i n g > ( ) ;

 

 

366

Часть V. За базовыми классам.


//

См. д о п о л н и т е л ь н ы е

к л а с с ы

на п р и л а г а е м о м

/ / к о м п а к т - д и с к е

 

 

 

 

/ /

Готовим

м е с т о

д л я

х р а н е н и я

о б ъ е к т о в

L i s t < B l o b >

b L i s t

=

new L i s t < B l o b > ( ) ;

S t u d e n t [ ]

s t u d e n t s

=

new S t u d e n t [ 1 0 ] ;

C o n s o l e . W r i t e L i n e ( " С о з д а н и е и с о х р а н е н и е о б ъ е к т о в : " ) ; f o r ( i n t i = 0; i < 10 ; i + + )

{

C o n s o l e . W r i t e L i n e ( " ^ С о з д а н и е B l o b - " +

 

 

" в ы з о в к о н с т р у к т о р а б е з " +

 

 

" п а р а м е т р о в . " ) ;

 

 

B l o b b = b l o b F a c t . C r e a t e ( ) ;

 

 

b . n a m e = " b l o b " + i . T o S t r i n g ( ) ;

 

 

b L i s t . A d d ( b ) ;

 

 

 

C o n s o l e . W r i t e L i n e ( " ^ С о з д а н и е S t u d e n t с " +

 

 

" у с т а н о в к о й имени -

"

+

 

 

" в ы з о в

к о н с т р у к т о р а

с

одним " +

 

 

" п а р а м е т р о м . " ) ;

 

 

s t r i n g

sName

= " s t u d e n t "

+ i . T o S t r i n g ( ) ;

s t u d e n t s [ i ]

= s t u F a c t . C r e a t e ( s N a m e ) ;

 

 

/ / . . .

с м .

полный т е к с т

н а п р и л а г а е м о м

к о м п а к т - д и с к е

}

 

/ /

Вывод

р е з у л ь т а т о в .

 

 

 

 

 

 

 

 

f o r e a c h ( B l o b b i n b L i s t )

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

C o n s o l e . W r i t e L i n e ( b . T o S t r i n g ( ) ) ;

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

f o r e a c h ( S t u d e n t

s

i n s t u d e n t s )

 

 

 

 

 

 

{ C o n s o l e . W r i t e L i n e ( s . T o S t r i n g ( )

 

 

 

 

 

 

II

Ожидаем

п о д т в е р ж д е н и я

п о л ь з о в а т е л я

 

 

 

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 ( ) ;

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/ /

Классы

д а н н ы х :

S t u d e n t , B l o b

( с м .

 

также

к о м п а к т - д и с к )

//

B l o b

-

п р о с т о й

к л а с с

с к о н с т р у к т о р о м

по

умолчанию ( б е з

/ /

п а р а м е т р о в ,

 

п р е д о с т а в л я е м ы м С # ) .

Для

э к о н о м и и м е с т а к о д

//

опущен

( с м .

к о м п а к т - д и с к )

 

 

 

 

 

 

 

//

S t u d e n t

- к л а с с

с

к о н с т р у к т о р о м по

умолчанию

и

//

к о н с т р у к т о р о м с

одним п а р а м е т р о м

 

 

 

 

 

c l a s s S t u d e n t

:

ISettable<string>

//

Обобщенный

интерфейс

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/ / Ч а с т ь

к о д а

опущена,

с м .

к о м п а к т - д и с к

 

 

p u b l i c S t u d e n t ( )

{ }

 

/ / В ы

должны

о б е с п е ч и т ь

н а л и ч и е

 

 

 

 

 

 

 

/ / э т о г о к о н с т р у к т о р а

 

p u b l i c S t u d e n t ( s t r i n g

name)

/ /

к о н с т р у к т о р с

одним

{

 

 

 

 

 

 

 

 

// п а р а м е т р о м

 

 

t h i s . n a m e

 

name;

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// Реализация ISettable

 

 

 

 

 

 

 

public void SetParameter(string name)

 

 

 

классами

 

 

 

 

 

 

 

 

 

 

 

 

 

 

367


this.name

=

name;

// T o S t r i n g ( )

- на к о м п а к т - д и с к е

}

 

 

// См. также

исходный т е к с т на к о м п а к т - д и с к е

// Интерфейсы ISettable, используемые фабриками interface ISettable<U>

{

void SetParameter(U u ) ;

}

interface ISettable2<U, V>

{ void SetParameter(U u, V v ) ;

}

//Фабрика для объектов с конструктором без параметров не

//требует реализации ISettable

class GenericFactory<T> where T : new()

{ public T Create()

{

return new T ( ) ;

}

}

//Фабрика для создания объектов с конструктором с одним

//параметром

class GenericFactoryl<T, U> where T : ISettable<U>, new()

{

//Создает новый объект типа Т с параметром U и

//возвращает Т

{

 

 

 

 

 

public Т

Create(U и)

 

 

 

 

Т t = new Т ( ) ;

 

 

 

 

t.SetParameter(и);

// Т должен реализовать ISettable,

 

// так что у него есть метод SetParameter()

return

t;

 

 

 

 

}

 

 

 

 

 

}

 

 

 

 

 

/ / Н а п р и л а г а е м о м к о м п а к т - д и с к е е с т ь к о д

фабрики

дл я

/ / с о з д а н и я

о б ъ е к т о в ,

к о н с т р у к т о р которых

т р е б у е т д в а

/ / п а р а м е т р а

 

 

 

 

}

 

 

 

 

 

Демонстрационная программа

G e n e r i c l n t e r f а с е

на

самом

деле создает два

обобщенных класса.

 

 

 

 

Фабрику для создания объектов, которые имеют только конструктор по умолча­ нию, без параметров.

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

368

Часть V. За базовыми классами


произвольное число параметров. На прилагаемом компакт-диске имеется исходный текст фабрики для создания объектов, имеющих конструктор с двумя параметрами.

Обобщенное создание объектов

Создание объектов, конструктор которых не имеет параметров, очень простое, так как при этом отсутствуют аргументы, о которых вам пришлось бы беспокоиться (за ис­ ключением <Т> — параметра типа):

// Метод

C r e a t e ( ) к л а с с а G e n e r i c F a c t o r y < T >

public Т

C r e a t e ()

{

return new Т(); // Вызов конструктора без параметров

}

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

// Т

должен быть

к л а с с о м

MyBase или е г о п о д к л а с с о м

class

MyClass<T> :

w h e r e

Т:

MyBase

// Т

должен р е а л и з о в ы в а т ь

I M y l n t e r f a c e

class

M y C l a s s < T > :

w h e r e

T : I M y l n t e r f a c e

// T

может быть т о л ь к о

ссылочным типом

class

MyClass<T> :

w h e r e

Т : c l a s s

// Т

может быть т о л ь к о

т и п о м - з н а ч е н и е м

class

M y C l a s s < T > :

w h e r e

Т : s t r u c t

// Т

должен и м е т ь

к о н с т р у к т о р б е з п а р а м е т р о в

class

MyClass<T> :

w h e r e

Т.-

new( )

Именно это последнее ограничение и устанавливает пределы вашим возможностям по написанию мощных обобщенных фабрик. Оно требует, чтобы тип Т имел конструктор по умолчанию, т.е. конструктор, у которого нет параметров. Тип Т может иметь и другие конструкторы, но один из них обязательно должен быть конструктором по умолчанию — напишете ли вы его сами или он будет сгенерирован С#.

Ограничение new () представляет собой требование для каждого обобщенного класса или метода, которые хотят создавать объекты типа Т. Однако у этого ограничения нет версий наподобие new (U) или new (U, V) для конструкторов с параметрами.

Обобщенный интерфейс также может иметь ограничения:

i n t e r f a c e I S e t t a b l e < T > : w h e r e Т : n e w ( ) . . .

Поиск обобщенного решения

Вопрос в том, как поступить в случае, когда конструктору надо передавать парамет­ ры. Фабрика объектов, конструктор которых требует одного параметра, должна исполь­

зовать в методе C r e a t e ()

код наподобие приведенного:

 

public

Т

C r e a t e ( U

и)

/ / и — а р г у м е н т , к о т о р ы й мы

хотим

 

 

 

 

/ / п е р е д а т ь к о н с т р у к т о р у

 

| {

 

 

 

 

 

Т t

=

new Т ( ) ;

/ / Н о new Т( ) не может п р и н и м а т ь

а р г у м е н т ы

. . .

 

 

/ / И ч т о т е п е р ь ? . . .

 

Глава

15.

Обобщенное программирование

369


 

В результате следующий подход оказывается неработоспособным:

Т

t

=

new

T ( u ) ;

//

Не

р а б о т а е т

 

 

 

 

 

/ /

или

 

Т

t

=

new

T ( U ) ;

//

Не

р а б о т а е т

Итак, как же поступить, чтобы передать аргумент и новому объекту?

О б х од конструктора по умолчанию

Только что описанная проблема решается путем использования обобщенного интер фейса. Чтобы позволить фабрике передавать параметры новым объектам, необходимо наложить определенные ограничения на производимые объекты: они должны реализовывать интерфейс наподобие I S e t t a b l e < T > :

i n t e r f a c e I S e t t a b l e < U >

{

v o i d S e t P a r a m e t e r ( U u ) ;

}

Тогда вы можете объявить фабрику для объектов с одним параметром следующим

образом:

 

 

 

 

 

// Т —

с о з д а в а е м ы й т и п ;

U —

тип

п а р а м е т р а к о н с т р у к т о р а

 

c l a s s G e n e r i c F a c t o r y l < T ,

U>

w h e r e

T: I S e t t a b l e < U > , new()

'{ }

Любой

тип T, производимый такой фабрикой, должен реализовывать

интерфейс

I S e t t a b l e < U > c U замененным реальным типом, таким как s t r i n g .

 

Использование найденного

решения

 

 

 

 

Если вы хотите производить объекты S t u d e n t посредством такой фабрики, а конст

руктор

S t u d e n t

требует один параметр,

скажем, s t r i n g , для передачи имени студен­

та, то класс S t u d e n t должен реализовать интерфейс

I S e t t a b l e < s t r i n g > :

/ / И н с т а н ц и р о в а н и е и н т е р ф е й с а д л я т и п а s t r i n g

 

c l a s s

S t u d e n t : I S e t t a b l e < s t r i n g >

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

p r i v a t e

s t r i n g n a m e ;

 

 

 

 

 

 

p u b l i c S t u d e n t ( ) { }

 

 

/ / Т р е б у е т с я н а л и ч и е

 

 

 

 

 

 

 

/ /

к о н с т р у к т о р а

п о умолчанию

p u b l i c

S t u d e n t ( s t r i n g name)

/ /

К о н с т р у к т о р с

одним

{

 

 

 

 

 

 

// п а р а м е т р о м

 

S e t P a r a m e t e r ( n a m e ) ;

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

p u b l i c

v o i d S e t P a r a m e t e r ( s t r i n g

name)

/ / Р е а л и з а ц и я

{

 

 

 

 

 

 

 

 

II I S e t t a b l e < s t r i n g >

t h i s . n a m e = n a m e ;

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

//

Прочие

методы

и

ч л е н ы - д а н н ы е

к л а с с а

S t u d e n t

 

При этом вы можете создавать класс S t u d e n t

и так, как это делали ранее, с

 

помощью оператора new:

 

 

 

 

 

 

 

s t u d e n t s [ 0 ]

=

new

S t u d e n t ( " J u a n

V a l d e z " ) ;

370

Часть V. За базовыми классами