1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 43
Текст из файла (страница 43)
Вы ни в коем случае не должны вносить изменения в устройство,в частности, отключать блокировки.Почти все кухонное оборудование любой степени сложности, включая микроволновые печи, имеет пломбы, препятствующие проникновению пользователя внутрь. Еслитакая пломба повреждена, это указывает, что крышка устройства была снята, и вся ответственность с производителя тем самым снимается. Если вы каким-либо образом изменили внутреннее устройство печи, вы сами несете ответственность за все последующие неприятности, которые могут произойти.Аналогично, класс должен иметь возможность контролировать доступ к своим членамданным.
Никакая последовательность вызовов членов класса не должна приводить программук аварийному завершению, однако класс не в состоянии гарантировать это, если внешниеобъекты имеют доступ к внутреннему состоянию класса. Класс должен иметь возможностьпрятать критические члены-данные и делать их недоступными для внешнего мира.Итак, как же С# реализует объектно-ориентированное программирование? Впрочем,это не совсем корректный вопрос. С# является объектно-ориентированным языком про-Глава10.Что такое объектно-ориентированное программирование229граммирования, но не реализует его — это делает программист.
Как и на любом другомгомязыке,выможетенаписатьнаС#программу,неявляющуюсяобъект!ориентированной (например, вставив весь код Word в функцию M a i n O ) . Иногданужно писать и такие программы, но все же главное предназначение С# — создаетобъектно-ориентированных программ.С# предоставляет программисту следующие необходимые для написания объект!ориентированных программ возможности.Управляемый доступ. С# управляет обращением к членам класса. Ключе»слова С# позволяют объявить некоторые члены открытыми для всех, а другиезащищенными или закрытыми.
Подробнее эти вопросы рассматриваются в главе 11, "Классы".Специализация. С# поддерживает специализацию посредством механизма, iвестного как наследование классов. Один класс при этом наследует члены другакласса. Например, вы можете создать класс С а г , как частный случай класса Vih i c l e . Подробнее эти вопросы рассматриваются в главе 12, "Наследование".Полиморфизм. Эта возможность позволяет объекту выполнить операцию так, какэто требуется для его корректного функционирования. Например, класс Rocketунаследованный от V e h i c l e , может реализовать операцию S t a r t совершенноиначе, чем С а г , унаследованный от того же V e h i c l e . По крайней мере, будемнадеяться, что это справедливо хотя бы по отношению к вашему автомобилюхотя с некоторыми автомобилями никогда ни в чем нельзя быть уверенным...|просьгполиморфизмарассматриваютсявглавах 13,"Полиморфизм", 1"Интерфейсы и структуры".230ЧастьIV.Объектно-ориентированноепрограммировалГлава 11КлассыУ Защита класса посредством управления доступом> Инициализация объекта с помощью конструктора> Определение нескольких конструкторов в одном классе> Конструирование статических членов и членов классаласе должен сам отвечать за свои действия.
Так же как микроволновая печь недолжна вспыхнуть, объятая пламенем, из-за неверного нажатия кнопки, таки класс не должен скончаться (или прикончить программу) при предоставлении некорректных данных.Чтобы нести ответственность за свои действия, класс должен убедиться в корректности своего начального состояния и в дальнейшем управлять им так, чтобы оно всегда оставалось корректным. С# предоставляет для этого все необходимое.Простые классы определяют все свои члены как p u b l i c .
Рассмотрим программуBankAccount, которая поддерживает член-данные b a l a n c e для хранения информации о балансе каждого счета. Сделав этот член p u b l i c , вы допускаете любого в святаясвятых банка, позволяя каждому самому указывать сумму на счету.Неизвестно, в каком банке храните свои сбережения вы, но мой банк и близко не настолько открыт и всегда строго следит за моим счетом, самостоятельно регистрируя каждое снятие денег со счета и вклад на счет. В конце концов, это позволяет уберечься отвсяких недоразумений, если вас вдруг подведет память.Управление доступом дает возможность избежать больших и малых ошибокв работе банка.
Обычно программисты, привыкшие к функциональному программированию, говорят, что достаточно лишь определить правило, согласнокоторому никакие другие классы не должны обращаться к члену b a l a n c e непосредственно. Увы, теоретически это, может быть, и так, но на практике такойподход никогда не работает. Да, программисты начинают работу, будучи переполненными благими намерениями, которые вскоре непонятно куда исчезаютпод давлением сроков сдачи проекта...Пример программы с использованием открытых членовВ приведенной демонстрационной программе класс B a n k A c c o u n t объявляет все методы как p u b l i c , в то же время члены-данные nAccountNumb e r и d B a l a n c e сделаны p r i v a t e . Эта демонстрационная программамкорректна и не будет компилироваться, так как создана исключительно в дидактических целях.// B a n k A c c o u n t - с о з д а н и е б а н к о в с к о г о счета с и с п о л ь з о в а н и е м/ / п е р е м е н н о й т и п а d o u b l e д л я х р а н е н и я б а л а н с а с ч е т а (она// объявлена как private, чтобы скрыть баланс от внешнего// мира)// Примечание: пока в программу не будут внесены// исправления, она не будет компилироваться, так как// функция Main() обращается к private-члену класса// BankAccount.using System;namespaceBankAccount{publicclassProgram{publicstatic void Main(string[]args){Console.WriteLine("В текущем состоянии эта " +"программа не к о м п и л и р у е т с я .
" ) ;// Открытие банковского счетаConsole.WriteLine("Создание объекта " +"банковского с ч е т а " ) ;BankAccount ba = new B a n k A c c o u n t ( ) ;ba.InitBankAccount();// Обращение к балансу при помощи метода Deposit()// вполне корректно; Deposit() имеет право доступа ко// всем членам-даннымba.Deposit(10);// Н е п о с р е д с т в е н н о е обращение к ч л е н у - д а н н ы м вызывает// ошибку компиляцииC o n s o l e . W r i t e L i n e ( " З д е с ь вы п о л у ч и т е " +"ошибку к о м п и л я ц и и " ) ;ba.dBalance += 10;// Ожидаем подтверждения пользователяConsole.WriteLine("Нажмите <Enter> для " +" з а в е р ш е н и я п р о г р а м м ы . . . ") ;Console.Read();}}// BankAccount - определение класса,// простейший банковский счетpublic class BankAccount232ЧастьIV.представляющегоОбъектно-ориентированноепрограммированиеprivate s t a t i c i n t n N e x t A c c o u n t N u m b e r =private i n t n A c c o u n t N u m b e r ;10 0 0 ;// хранение б а л а н с а в в и д е о д н о й п е р е м е н н о й типа d o u b l eprivate d o u b l e d B a l a n c e ;// Init - и н и ц и а л и з а ц и я б а н к о в с к о г о с ч е т а с н у л е в ы м// б а л а н с о м и и с п о л ь з о в а н и е м о ч е р е д н о г о г л о б а л ь н о г о// номераpublic v o i dInitBankAccount(){nAccountNumber =dBalance = 0.0;++nNextAccountNumber;// G e t B a l a n c e - п о л у ч е н и е т е к у щ е г о б а л а н с аpublic d o u b l e G e t B a l a n c e ( ){return d B a l a n c e ;// Номер с ч е т аpublic int G e t A c c o u n t N u m b e r ( ){return n A c c o u n t N u m b e r ;}public v o i d S e t A c c o u n t N u m b e r ( i n tnAccountNumber){this.nAccountNumber= nAccountNumber;// Deposit - п о з в о л е н л ю б о й п о л о ж и т е л ь н ы й в к л а дpublic v o i d D e p o s i t ( d o u b l e d A m o u n t ){if(dAmount>0.0){dBalance+= d A m o u n t ;// Withdraw - вы м о ж е т е с н я т ь со с ч е т а л ю б у ю с у м м у , не// превышающую б а л а н с ; ф у н к ц и я в о з в р а щ а е т р е а л ь н о с н я т у ю// суммуpublic d o u b l e W i t h d r a w ( d o u b l edWithdrawal){if(dBalance <= d W i t h d r a w a l ){dWithdrawal= dBalance;dBalance -= d W i t h d r a w a l ;return d W i t h d r a w a l ;Глава 11.
Классы233private static int n N e x t A c c o u n t N u m b e r =private int nAccountNuraber;1000;// хранение б а л а н с а в виде одной п е р е м е н н о й типа d o u b l eprivate d o u b l e d B a l a n c e ;// Init - и н и ц и а л и з а ц и я б а н к о в с к о г о с ч е т а с н у л е в ы м// б а л а н с о м и и с п о л ь з о в а н и е м о ч е р е д н о г о г л о б а л ь н о г о// н о м е р аpublic v o i d I n i t B a n k A c c o u n t ( )nAccountNumber =dBalance = 0.0;++nNextAccountNumber;}// G e t B a l a n c e - п о л у ч е н и е т е к у щ е г о б а л а н с аpublic d o u b l e G e t B a l a n c e ( )return d B a l a n c e ;// Н о м е р с ч е т аpublicint G e t A c c o u n t N u m b e r ( )return n A c c o u n t N u m b e r ;public v o i d S e t A c c o u n t N u m b e r ( i n tnAccountNumber)this.nAccountNumber = nAccountNumber;// D e p o s i t - п о з в о л е н л ю б о й п о л о ж и т е л ь н ы й в к л а дpublic v o i d D e p o s i t ( d o u b l e d A m o u n t ){if(dAmount>0.0){dBalance+= d A m o u n t ;// W i t h d r a w - вы м о ж е т е с н я т ь со с ч е т а л ю б у ю с у м м у , не// превьшающую б а л а н с ; функция возвращает реально снятую// суммуpublic d o u b l e W i t h d r a w ( d o u b l e d W i t h d r a w a l )if( d B a l a n c e <= d W i t h d r a w a l )dWithdrawal= dBalance;dBalance -= d W i t h d r a w a l ;return d W i t h d r a w a l ;233// G e t S t r i n g - в о з в р а щ а е т//-виде строкиpublic string GetString()информацию осостоянии счета в{stringsreturns;=String.Format("#{0} = {l:C}",GetAccountNumber(),GetBalance());В этом коде выражение d B a l a n c e -= d W i t h d r a w a l означает то же, чтяи d B a l a n c e = d B a l a n c e - d W i t h d r a w a l .
Обычно программисты на C#стараются использовать наиболее короткую запись из возможных.Объявляя член как p u b l i c , вы делаете его доступным для любого кода вашей программы.Класс B a n k A c c o u n t предоставляет метод I n i t B a n k A c c o u n t () для инициализа-1ции членов класса, метод D e p o s i t () — для обработки вкладов на счет и метод With-Id r a w ( ) — для снятия денег со счета. Методы D e p o s i t ( ) и W i t h d r a w ( ) дажеобес-1печивают выполнение некоторых рудиментарных правил — "нельзя вкладывать отрица-1тельные суммы" и "нельзя снимать больше, чем есть на счету".