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

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

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

Добавлен: 11.12.2025

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

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

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

Вы можете решить, что последующие поколения программистов недостойны рая рять написанный вами класс. Заблокировать его от возможных расширений можно nocgj ством ключевого слова s e a l e d — такой класс не сможет выступать в качестве базовой

Рассмотрим следующий фрагмент исходного текста:

u s i n g

S y s t e m ;

p u b l i c

c l a s s B a n k A c c o u n t

{

/ / W i t h d r a w a l - в ы м о ж е т е с н я т ь с о с ч е т а л ю б у ю с у м м у , н е / / п р е в ы ш а ю щ у ю б а л а н с . В о з в р а щ а е т р е а л ь н о с н я т у ю с о / / с ч е т а с у м м у

v i r t u a l p u b l i c v o i d W i t h d r a w ( d e c i m a l m W i t h d r a w )

{

C o n s o l e . W r i t e L i n e ( " В ы з о в B a n k A c c o u n t . W i t h d r a w ( ) " ) ;

}

}

p u b l i c s e a l e d c l a s s S a v i n g s A c c o u n t : B a n k A c c o u n t

{

o v e r r i d e p u b l i c v o i d W i t h d r a w ( d e c i m a l m W i t h d r a w a l )

{

 

C o n s o l e . W r i t e L i n e ( " В ы з о в S a v i n g s A c c o u n t . W i t h d r a w ( )

11) ;

}

}

p u b l i c c l a s s S p e c i a l S a l e A c c o u n t

: S a v i n g s A c c o u n t

{

 

o v e r r i d e p u b l i c v o i d W i t h d r a w ( d e c i m a l m W i t h d r a w a l )

{

C o n s o l e . W r i t e L i n e ( " В ы з о в " +

" S p e c i a l S a l e A c c o u n t . W i t h d r a w () 11) ;

}

}

П р и компиляции данного исходного текста вы получите следующее сообщение ошибке:

' S p e c i a l S a l e A c c o u n t ' : c a n n o t i n h e r i t f r o m s e a l e d c l a s s ' S a v i n g s A c c o u n t '

Ключевое слово s e a l e d дает возможность защитить класс от вмешательства мето дов некоторых подклассов. Например, позволяя программисту расширять класс, реал зующий систему безопасности, вы, по сути, разрешаете создать черный ход, минующий эту систему.

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

308

Часть IV. Объектно-ориентированное программировал


Часть V

З а б а з о в ы м и к л а с с а м и


В а ши объекты до сих пор были простыми вещами наподобие целых чисел или строк, в крайнем случае — счетов B a n k A c c o u n t . Но в С# имеются и другие объекты. Из этой части вы узнаете, как писать соб­ ственные объекгы типов-значений (работающие подобно типам i n t или f l o a t ) , и познакомитесь с интерфейсами, которые позволяют сделать ваши объекты более обобщенными и гибкими. Вместе с аб­ страктными классами, рассмотренными в главе 13, "Полиморфизм", интерфейсы предоставляют ключ к передовым методам проектиро­ вания программ. Так что читайте внимательно!

Однако интерфейсы — не единственный способ сделать обобщенный и гибкий код. Новые возможности С# позволяют создавать обобщен­ ные (generic) о б ъ е к т ы — например, контейнеры, в которых могут храниться различные данные других типов. Пока что это звучит для вас сплошной абстракцией, но к концу части абстракция наполнится конкретным содержанием, так что запаситесь терпением.

Глава 14

Интерфейсы и структуры

Отношение М О Ж Е Т _ И С П О Л Ь З О В А Т Ь С Я _ К А К

Определение интерфейса

Использование интерфейса для выполнения распространенных операций

Определение структуры

Использование структуры для объединения классов, интерфейсов и встроенных типов в одну иерархию классов

ласе может содержать ссылку на другой класс. Это — простое отношение СО­ ДЕРЖИТ. Один класс может расширять другой класс с п о м о щ ь ю наследования.

Ь—отношение Я В Л Я Е Т С Я . Интерфейсы С# реализуют еще одно, не менее важное яношение — М О Ж Е Т _ И С П О Л Ь З О В А Т Ь С Я _ К А К .

Если вы хотите написать памятку, вы можете взять ручку и обрывок бумаги, можете Епользоваться органайзером или сделать это посредством своего компьютера. Все эти ккты реализуют операцию "написать памятку" — T a k e A N o t e . Используя магию нашедования, на языке С# это можно реализовать следующим образом:

::stract class ThingsThatRecord

{

abstract p u b l i c v o i d T a k e A N o t e ( s t r i n g s N o t e ) ;

}

public class Pen : ThingsThatRecord

{

override public void TakeANote (string sNote)

{

II. . . Написание заметки ручкой . . .

}

}

public class PDA : ThingsThatRecord

override

p u b l i c v o i d T a k e A N o t e ( s t r i n g s N o t e )

I I . .

. п р и п о м о щ и о р г а н а й з е р а . . . "

)

 


}

p u b l i c c l a s s L a p t o p

:

T h i n g s T h a t R e c o r d

{

 

 

 

o v e r r i d e

p u b l i c v o i d

T a k e A N o t e ( s t r i n g s N o t e )

{

 

 

 

II... еще каким-то образом . . .

 

}

 

 

 

}

 

 

 

Если

ключевое

слово a b s t r a c t вас с м у щ а е т — обратитесь к главе

" П о л и м о р ф и з м " , за пояснениями . Если вам непонятно, что такое наследова ние — перечитайте главу 12, "Наследование" .

Решение с использованием наследования выглядит неплохо до тех пор, пока интерес вызывает только операция T a k e A N o t e ( ) . Функция наподобие показанной далее Re c o r d T a s k () может использовать метод T a k e A N o t e () для того, чтобы записать спи сок необходимых покупок в зависимости от того, какое средство есть у вас под рукой: v o i d R e c o r d T a s k ( T h i n g s T h a t R e c o r d t h i n g s )

{

/ / Э т о т а б с т р а к т н ы й м е т о д р е а л и з о в а н в о в с е х к л а с с а х , / / к о т о р ы е н а с л е д у ю т T h i n g s T h a t R e c o r d

t h i n g s . T a k e A N o t e ( " С п и с о к п о к у п о к " ) , - // . . . и т а к д а л е е . . .

}

Однако это решение сталкивается с двумя большими проблемами.

Первая проблема — фундаментальная. Дело в том, что реально связать ручку

органайзер и компьютер соотношением Я В Л Я Е Т С Я невозможно . Знание того, как работает ручка, не дает никаких сведений о том, как записывают информацию компьютер или органайзер.

Вторая проблема чисто техническая. Гораздо лучше описать L a p t o p как под

класс класса C o m p u t e r . Хотя PDA также можно наследовать от того же класса C o m p u t e r , этого нельзя сказать о классе Р е п . Вы можете охарактеризовать pyчку как некоторый тип M e c h a n i c a l W r i t e D e v i c e (механическое пишущее y c т р о й ство) или D e v i c e T h a t S t a i n s Y o u r S h i r t (устройство, пачкающее ваши шта­ ны). Однако в С# класс не может быть наследован от двух разных классов одно временно — класс С# может быть вещью только одного сорта.

В е р н е м с я

к т р е м и с х о д н ы м к л а с с а м .

Е д и н с т в е н н о е о б щ е е , что

у них есть —

то, что все

о н и м о г у т и с п о л ь з о в а т ь с я

для

з а п и с и чего - либо .

Отношение МО

Ж Е Т _ И С П О Л Ь З О В А Т Ь С Я _ К А К R e c o r d a b l e

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

и х

пригодность

некоторой цели без применения наследования.

 

 

 

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

312

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


interface IRecordable

 

 

{

 

 

v o i d T a k e A N o t e ( s t r i n g

s N o t e )

 

{

 

 

Обратите внимание на ключевое

слово i n t e r f a c e там, где обычно стоит ключевое

слово c l a s s . В фигурных скобках

интерфейса приведен список абстрактных

методов.

Интерфейсы не содержат определения никаких членов-данных.

 

Метод T a k e A N o t e () записан без реализации. Ключевые слова p u b l i c и

v i r t u a l

ни a b s t r a c t не являются необходимыми . Все методы интерфейса открыты,

а сам он

не включается ни в какое обычное наследование — это интерфейс, а не класс.

 

Класс, который реализует интерфейс, должен предоставить реализацию для каждого злемента интерфейса. Метод, реализующий метод интерфейса, не использует ключевое слово o v e r r i d e — это не похоже на перекрытие виртуальной функции.

По соглашению имена интерфейсов начинаются с буквы I, Кроме того, для них, как правило, используются прилагательные (в то время как для имен клас­ сов — существительные). Как обычно, это только соглашение — С# совершен­ но все равно, как именно вы назовете ваш интерфейс.

Далее приведено объявление, указывающее, что класс PDA реализует интерфейс

IRecordable.

 

public c l a s s

PDA : I R e c o r d a b l e

{

 

public v o i d

T a k e A N o t e ( s t r i n g s N o t e )

{

 

II . . .

Н а п и с а н и е п а м я т к и . . .

Как видите, не существует отличий между синтаксисом объявления наследования базового класса T h i n g s T h a t R e c o r d и объявлением о реализации интерфейса I R e c o r d a b l e .

В этом и заключается основная причина соглашения об именовании интерфей­ сов — чтобы сразу отличать их от классов.

Вывод из всего сказанного — интерфейс описывает возможности и свойства. Кроме иго, он представляет собой контракт. Если вы согласны реализовать все методы, опре­ деленные в интерфейсе, вы получите все его возможности .

Класс реализует интерфейс, предоставляя определения всех методов интерфейса, как показано в приведенном далее фрагменте исходного текста,

public class Pen : IRecordable

{

public

v o i d

T a k e A N o t e ( s t r i n g

s N o t e )

{

 

 

 

I I .

. .

З а п и с ь р у ч к о й . . .

}

 

 

 

Глава 14. Интерфейсы и структуры

313