1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 50
Текст из файла (страница 50)
Наследованиеmlnitial,mlnterestRate)265{InitBankAccount(mlnitial);this.mlnterestRate = mlnterestRate/100;}// A c c u m u l a t e l n t e r e s t - в ы з ы в а е т с я о д н о к р а т н о в конце// периода начисления процентовpublicvoidAccumulatelnterest(){imBalance = Balance +(decimal) (Balance*mInterestRate);}// T o S t r i n g - с т р о к а с и н ф о р м а ц и е й о с о с т о я н и иpublicstringToSavingsAccountString()r e t u r nсчетаString.Format("{0}({l}%)"(ToBankAccountStringO ,mlnterestRate *100);}}publicclassProgram{publics t a t i cvoidMain(string[]args){// Создание банковского счета и вывод на экранBankAccount ba = new B a n k A c c o u n t ( ) ;ba.InitBankAccount(10 0);ba.Deposit(100);Console.WriteLine("Счет{о}",ba.ToBankAccountString());// Теперь — депозитный с ч е тSavingsAccountsa=new S a v i n g s A c c o u n t ( ) ;sa.InitSavingsAccount(100,12.5M);sa.Accumulatelnterest();Console.WriteLine("Счет{о}",sa.ToSavingsAccountString());// Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +" з а в е р ш е н и я п р о г р а м м ы .
. . ") ;Console.Read();}}}К л а с с 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 lо д н о й д л я п р о и з в о л ь н о г о н а ч а л ь н о г о з н а ч е н и я б а л а н с а , д р у г о й — д л я н у л е в о г о баламО б р а т и т е в н и м а н и е , ч т о з д е с ь н е и с п о л ь з о в а н ы к о н с т р у к т о р ы , к о т о р ы е б ы л и в поемн е й р а с с м а т р и в а в ш е й с я в е р с и и э т о г о к л а с с а в г л а в е 1 1 , " К л а с с ы " . П о з ж е в ы пойме!почему сделан такой шаг назад.С в о й с т в о B a l a n c e п о з в о л я е т д р у г и м ч и т а т ь з н а ч е н и е б а л а н с а , з а п р е щ а я при этом!и з м е н я т ь .
М е т о д D e p o s i t п р и н и м а е т л ю б о й п о л о ж и т е л ь н ы й вклад, а м е т о д W i t h d r a wп р е д о с т а в л я е т в о з м о ж н о с т ь с н я т ь со с ч е т а л ю б у ю с у м м у (в п р е д е л а х н а л и ч н о г о балансМетод T o B a n k A c c o u n t S t r i n g ()266с о з д а е т с т р о к у с о п и с а н и е м с о с т о я н и я счета.Часть IV. Объектно-ориентированное программирован*Класс S a v i n g s A c c o u n tнаследуетвсе,чтоможно,отклассаBankAccount.К этому он добавляет п р о ц е н т н у ю с т а в к у и в о з м о ж н о с т ь н а к о п л е н и я п р о ц е н т о в .Функция M a i n ( )делает минимально в о з м о ж н у ю работу. Она создает счет B a n k -Аccount, выводит и н ф о р м а ц и ю о н е м , с о з д а е т с ч е т S a v i n g s A c c o u n t , о д и н р а з н а числяет проценты и в ы в о д и т р е з у л ь т а т .
П о л н о с т ь ю в ы в о д п р о г р а м м ы в ы г л я д и т с л е дующим образом:Счет 1001-$2 0 0 . 0 0Счет 1002-$112.50(12.500%),Нажмите < E n t e r > д л я з а в е р ш е н и я п р о г р а м м ы . . .Обратитевнимание,чтометодI n i t S a v i n g s A c c o u n t ()вызываетметодI n i t B a n k A c c o u n t ( ) , который инициализирует члены-данные банковскогосчета. М е т о д I n i t 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 с а м о с т о я т е л ь н о и н и ц и а л и з и р о вать свои ч л е н ы . К а ж д ы й к л а с с д о л ж е н о т в е ч а т ь з а с е б я с а м .Отношения м е ж д у 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 п р е д с т а в л я ю т с о б о й ф у н д а нтальное о т н о ш е н и е Я В Л Я Е Т С Я , к о т о р о е п р и с у щ е н а с л е д о в а н и ю .
Ч у т ь п о з ж е б у д е трассмотрено а л ь т е р н а т и в н о е о т н о ш е н и е С О Д Е Р Ж И Т .Отношение Я В Л Я Е Т С ЯОтношение Я В Л Я Е Т С Я ( I S _ A ) м е ж д у S a v i n g s A c c o u n tи BankAccountможноремонстрировать п у т е м с л е д у ю щ е г о и з м е н е н и я в к л а с с е P r o g r a m д е м о н с т р а ц и о н ной программы S i m p l e S a v i n g s A c c o u n t из п р е д ы д у щ е г о р а з д е л а ,public class Program{// Добавим:// D i r e c t D e p o s i t public s t a t i c v o i dа в т о м а т и ч е с к и й в к л а д на с ч е тD i r e c t D e p o s i t (BankAccount ba,decimal mPay){ba.Deposit(mPay);}publicstaticvoidMain ( s t r i n g []args){II Создание б а н к о в с к о г о с ч е т а и вывод на э к р а нBankAccount ba = new B a n k A c c o u n t ( ) ;ba.
I n i t B a n k A c c o u n t ( 1 0 0 ) ;DirectDeposit(ba,100);Console.WriteLine("Счет{0}",ba.ToBankAccountString());// Теперь - д е п о з и т н ы й с ч е тSavingsAccountsa=new S a v i n g s A c c o u n t ( ) ;sa.InitSavingsAccount(100,12.5M);DirectDeposit(sa,100);sa. A c c u m u l a t e l n t e r e s t ( ) ;\m 12. Наследование267Console.WriteLine("Счет{0}",sa.ToSavingsAccountString());// Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +"завершения программы...");Console.Read();}}П о ч т и н и ч е г о не и з м е н и л о с ь . Е д и н с т в е н н о е р е а л ь н о е о т л и ч и е з а к л ю ч а е т с я в том, Jт е п е р ь в с е в к л а д ы д е л а ю т с я п р и п о м о щ и л о к а л ь н о й ф у н к ц и и D i r e c t D e p o s i t (),iт о р а я н е я в л я е т с я ч а с т ь ю к л а с с а B a n k A c c o u n t .
А р г у м е н т а м и э т о й ф у н к ц и и являшбанковский счет и величина вклада.Обратите внимание (начинается интересное!), что функция M a i n ()функции D i r e c t D e p o s i t ()скольку S a v i n g s A c c o u n tможет передк а к о б ы ч н ы й б а н к о в с к и й счет, т а к и депозитный,ЯВЛЯЕТСЯBankAccountи , т а к и м о б р а з о м , имеемп р а в а и п р и в и л е г и и п о с л е д н е г о . П о с к о л ь к у S a v i n g s A c c o u n t Я В Л Я Е Т С Я BankAtc o u n t , вы можете присвоить 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 лиспользовать его в качестве аргумента B a n k A c c o u n t .Доступ к BankAccount через содержаниеК л а с с 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 и другУс п о с о б о м , к а к п о к а з а н о в п р и в е д е н н о м д а л е е ф р а г м е н т е к о д а ( к л ю ч е в а я с т р о к а здесьяделена полужирным шрифтом).// S a v i n g s A c c o u n t - б а н к о в с к и й с ч е т с н а к о п л е н и е м процентовp u b l i c c l a s s SavingsAccount_ // Обратитевнимание на// подчеркивание:э т о не класс{//SavingsAccount.public BankAccount bankAccount; // Содержит BankAccountpublicdecimalmlnterestRate;// I n i t S a v i n g s A c c o u n t - ввод процентной ставки как// в е л и ч и н ы от 0 до 100publicvoidInitSavingsAccount(BankAccountbankAccount,decimalmlnterestRate)this.bankAccount= bankAccount;this.mlnterestRate = mlnterestRate// A c c u m u l a t e l n t e r e s t - выполняется// начислении процентовpublicvoidAccumulatelnterest()/100;однократноприbankAccount.mBalance= bankAccount.Balance+(bankAccount.Balance * mlnterestRate);// D e p o s i t - р а з р е ш е н любойpublicvoid Deposit(decimal//ДелегированиеположительныйmAmount)содержащемусяобъектувкладBankAccountbankAccount.Deposit(mAmount);268Часть IV.
Объектно-ориентированное программирова//Withdraw/ / счету;'public-можнометодdoublereturnснятьневозвращаетболееснятуюWithdraw (decimalтого,классимеетсянаmWithdrawal)bankAccount .Withdraw (mWithdrawal)В этом случаечтосуммуSavingsAccount_содержит;член-данныеbankAccountв м е с т о наследования о т B a n k A c c o u n t ) . О б ъ е к т b a n k A c c o u n t в к л ю ч а е т н о м е р с ч е т абаланс, необходимые для функционирования SavingsAccount_.
Класс Savingaccount_ содержит данные, специфичные для депозитного счета и делегирует принеобходимостиз а п р о с ы к с о д е р ж а щ е м у с я в н е м о б ъ е к т у B a n k A c c o u n t (т.е. к о г д а к л а с -| 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 ) .В этом случае речь идет о т о м , что 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 .Отношение СОДЕРЖИТОтношение С О Д Е Р Ж И Т ф у н д а м е н т а л ь н о о т л и ч а е т с я о т о т н о ш е н и я Я В Л Я Е Т С Я . Э т оотличие кажется не с т о л ь с у щ е с т в е н н ы м в с л е д у ю щ е м ф р а г м е н т е и с х о д н о г о т е к с т а :/ / СозданиеновогоBankAccount b a/ / Особая=депозитногоnewверсиясчетаB a n k A c c o u n t ()SavingsAccount:SavingsAccount_ sa=newS a v i n g s A c c o u n t _ () ;s a .
I n i t S a v i n g s A c c o u n t ( b a , 5) ;/ / Вкладываем100насчетsa.Deposit ( 1 0 0 ) ;/ / Подсчитываем п р о ц е н т ыs a . A c c u m u l a t e l n t e r e s t () ;Проблема в т о м , ч т о т е п е р ь S a v i n g s A c c o u n t _ н е м о ж е т и с п о л ь з о в а т ь с я к а кBankAccount,посколькунеявляетсяегонаследником.ОнтеперьсодержитBankAccount, а это д а л е к о не о д н о и то ж е . Н а п р и м е р , с л е д у ю щ и й к о д к о м п и л и роваться не будет://DirectDeposit-автоматическийвкладнасчетvoid DirectDeposit(BankAccount ba, int nPay){ba.Deposit (nPay) ;}void SomeFunctionO{/ / ЭтоткоднеSavingsAccount_скомпилируетсяsaDirectDeposit (sa,=newS a v i n g s A c c o u n t _ () ;100);// .
. продолжение . . .}Функция D i r e c t D e p o s i t ( )неможетпринятьSavingsAccount_вместоBankAccount. М е ж д у этими классами нет такого очевидного о т н о ш е н и я , как вслучае наследования.Глава 12. Наследование269Р а з л и ч и е м е ж д у о т н о ш е н и я м и Я В Л Я Е Т С Я и С О Д Е Р Ж И Т г о р а з д о глубже, чем просто п р е д м е т п р о г р а м м н о г о с о г л а ш е н и я . Э т и о т н о ш е н и я п р о и с т е к а ю т и з отношений в р е аальном мире.Например, " З а п о р о ж е ц " Я В Л Я Е Т С Я автомобилем.
Автомобиль СОДЕРЖИТ моторЕ с л и в а ш з н а к о м ы й с к а ж е т , ч т о б ы в ы з а е х а л и з а н и м н а а в т о м о б и л е , и в ы приедете" З а п о р о ж ц е " , е м у б у д е т не на ч т о п о ж а л о в а т ь с я — вы п р и е х а л и на автомобиле. Но есливы п р и т а щ и т е к н е м у д в и г а т е л ь от " З а п о р о ж ц а " , у н е г о б у д у т в с е о с н о в а н и я обидеться наглупую шутку.К л а с с Z a p o r o z h e t s д о л ж е н р а с ш и р я т ь к л а с с С а г н е т о л ь к о д л я т о г о , чтобы п о лч и т ь д о с т у п к м е т о д а м С а г , н о и ч т о б ы в ы р а з и т ь ф у н д а м е н т а л ь н ы е отношения м е ж д уэтими классами.К с о ж а л е н и ю , н а ч и н а ю щ и й п р о г р а м м и с т м о ж е т унаследовать С а г от M o t o r , как прос т е й ш и й с п о с о б п о л у ч е н и я доступа к ч л е н а м M o t o r , к о т о р ы е н у ж н ы классу С а г для управл е н и я .
Н а п р и м е р , С а г м о ж е т унаследовать у класса M o t o r м е т о д G o ( ) . Однако этот п р и м е рв с к р ы в а е т о д н у и з п р о б л е м , в о з н и к а ю щ и х п р и т а к о м подходе. Н е с м о т р я н а т о что " п о е х а лзвучит о д и н а к о в о и в м а ш и н е , и д а ж е в ракете, " п о е х а л и " по о т н о ш е н и ю к машине совсемто, что " п о е х а л и " по о т н о ш е н и ю к мотору. Д л я т о г о ч т о б ы поехала м а ш и н а , надо обязательнозавести м о т о р , но это д а л е к о не о д н о и то же — ведь д л я того ч т о б ы поехала машина, ие щ е отпустить т о р м о з , п е р е к л ю ч и т ь с я на п е р в у ю передачу, отпустить сцепление и т.д.Словом, автомобиль просто не является видом мотора, и этого достаточно.Э л е г а н т н о с т ь п р о г р а м м н о г о о б е с п е ч е н и я — э т о н е п р о с т о эстетический ф а ктор. О н а способствует п о н и м а н и ю кода, п о в ы ш а е т его надежность, облегчаетподдержку, снижает количество возможных ошибок.С п е ц и а л и с т ы в о б л а с т и о б ъ е к т н о - о р и е н т и р о в а н н о г о п р о г р а м м и р о в а н и я для прос т о т ы д и з а й н а р е к о м е н д у ю т о т д а в а т ь п р е д п о ч т е н и е о т н о ш е н и ю СОДЕРЖИТ.С# имеет ряд возможностей, разработанных для поддержки наследования.Изменение классаП р о г р а м м а м о ж е т и з м е н и т ь к л а с с о б ъ е к т а .