Пример управления доступом
Приведенная далее демонстрационная программа DoubleBankAccount указывает потенциальные изъяны программы BankAccount .
// |
DoubleBankAccount |
- с о з д а н и е |
б а н к о в с к о г о |
с ч е т а |
с |
/ / |
и с п о л ь з о в а н и е м п е р е м е н н о й т и п а double д л я |
х р а н е н и я |
|
баланса |
с ч е т а ( о н а |
о б ъ я в л е н а |
к а к private , |
ч т о б ы |
с к р ы т ь |
// |
баланс |
от в н е ш н е г о |
м и р а ) |
|
|
|
using System;
namespace DoubleBankAccount
{
{
public class Program |
|
|
public static v o i d Main(string[] |
args) |
{ |
|
|
/ / О т к р ы т и е б а н к о в с к о г о с ч е т а |
|
C o n s o l e . W r i t e L i n e ( "Создани е |
о б ъ е к т а " + |
" б а н к о в с к о г о с ч е т а " ) ; |
BankAccount ba = n e w B a n k A c c o u n t ( ) ; |
b a . I n i t B a n k A c c o u n t ( ) ; |
|
|
/ / В к л а д н а с ч е т |
|
|
double dDeposit = 1 2 3 . 4 5 4 ; |
|
|
C o n s o l e . W r i t e L i n e ( " В к л а д { 0 : C } " , d D e p o s i t ) ; |
b a . D e p o s i t ( d D e p o s i t ) ; |
|
|
/ / Б а л а н с с ч е т а |
{ о } " , |
ba . GetString()) ; |
C o n s o l e . W r i t e L i n e ( " С ч е т = |
//Вот где имеетс я неприятность
double dAdditio n = |
0.002; |
|
C o n s o l e . W r i t e L i n e ( " В к л а д { 0 : C } " , d A d d i t i o n ) ; |
b a . D e p o s i t ( d A d d i t i o n ) ; |
|
|
/ / Р е з у л ь т а т |
|
|
|
Console . WriteLine( "В |
р е з у л ь т а т е с ч е т |
= { о } " , |
|
b a . G e t S t r i n g ( ) ) ; |
|
/ / Ожидаем |
п о д т в е р ж д е н и я |
п о л ь з о в а т е л я |
C o n s o l e . W r i t e L i n e ( "Нажмит е <Enter> |
д л я " + |
|
|
" з а в е р ш е н и я п р о г р а м м ы . . . " ) ; |
C o n s o l e . R e a d ( ) ; |
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/ / BankAccount |
- о п р е д е л е н и е |
к л а с с а , п р е д с т а в л я ю щ е г о |
/ / п р о с т е й ш и й б а н к о в с к и й с ч е т public class BankAccount
{
private static int n N e x t A c c o u n t N u m b e r = 1 0 0 0 ; private int n A c c o u n t N u m b e r ;
// хранение баланса в виде одной переменной типа double private double d B a l a n c e ;
// Init |
- инициализация банковского счета с нулевым |
// балансом и использованием очередного глобального |
•// номера |
public |
void InitBankAccount() |
{ |
|
n A c c o u n t N u m b e r = + + n N e x t A c c o u n t N u m b e r ; |
dBalance = 0.0; |
} |
|
// GetBalance - получение текущего баланса |
public |
double GetBalance() |
{ |
|
return dBalance;, |
} |
|
// A c c o u n t N u m b e r |
public |
int GetAccountNumber() |
{ |
|
return n A c c o u n t N u m b e r ; |
} |
|
public |
void SetAccountNumber(int nAccountNumber) |
{ |
|
this . nAccountNumber = n A c c o u n t N u m b e r ; - |
}
// Deposit - позволен любой положительный вклад
public void |
D e p o s i t ( d o u b l e dAmount) |
{ |
|
|
|
|
|
if (dAmount |
> |
0.0) |
|
|
{ |
|
|
|
|
|
dBalance |
+= |
d A m o u n t ; |
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// W i t h d r a w |
- |
вы |
можете |
снять |
со счета любую сумму, не |
// превьшающую |
баланс; |
функция |
возвращает реально снятую |
//сумму
public double Withdraw(doubl e dWithdrawal)
{ |
|
|
if (dBalance |
<= |
dWithdrawal) |
{ |
|
|
dWithdrawal |
= |
d B a l a n c e ; |
}
dBalance -= d W i t h d r a w a l ; return d W i t h d r a w a l ;
}
// GetStrin g - возвращает информацию о состоянии счета в
//виде строки
public string GetString()
238 |
Часть |
IV. |
Объектно-ориентированное программирование |
{
string s = String . Format("#{0} = { l : C } " ,
G e t A c c o u n t N u m b e r ( ) , G e t B a l a n c e ( ) ) ;
return s;
}
}
Функция Mai n () создает банковский счет и вносит на него сумму 123.454 — т.е.
}сумму с дробным количеством копеек. Затем функция Mai n () вносит на счет еще одну долю копейки и выводит баланс счета.
Вывод программы выглядит следующим образом:
|
|
|
|
|
|
|
|
Создание |
о б ъ е к т а |
б а н к о в с к о г о |
с ч е т а |
Вклад |
$123 .45 |
|
|
|
|
|
Счет = |
#1001 |
= |
$123 .45 |
|
Вклад |
$0.00 |
|
|
|
|
|
В р е з у л ь т а т е |
с ч е т |
= |
#1001 = |
$123.46 |
Нажмите |
<Enter> |
д л я |
з а в е р ш е н и я п р о г р а м м ы . . . |
Пользователь начинает жаловаться на некорректные расчеты. Лично я ничего не имею против округления счета до ближайшей сотни сверху, но ведь не все клиенты такие покладистые... В общем, что греха таить — в программе действительно имеется ошибка.
Проблема, конечно, в том, что 123.454 выводится как 123.45. Чтобы избе жать проблем, банк принимает решение округлять вклады и снятия до бли жайшей копейки. Простейший путь осуществить это — конвертировать сче та в decimal и использовать метод Decimal . Round ( ) , как это сделано в демонстрационной программе DecimalBankAccount .
// DecimalBankAccount - с о з д а н и е б а н к о в с к о г о
/ / |
и с п о л ь з о в а н и е м п е р е м е н н о й т и п а decimal д л я |
// |
баланса с ч е т а |
using System;
с ч е т а с х р а н е н и я
namespace DecimalBankAccount
{
public class Program
{
public static voi d Main(string[] args)
{
/ / О т к р ы т и е б а н к о в с к о г о с ч е т а
C o n s o l e . W r i t e L i n e ( " С о з д а н и е о б ъ е к т а " +
|
" б а н к о в с к о г о с ч е т а " ) ; |
BankAccount ba = |
n e w B a n k A c c o u n t ( ) ; |
b a . I n i t B a n k A c c o u n t ( ) ; |
/ / В к л а д н а с ч е т |
|
double dDeposit = |
1 2 3 . 4 5 4 ; |
C o n s o l e . W r i t e L i n e ( " В к л а д { 0 : C } " , d D e p o s i t ) ; b a . D e p o s i t ( d D e p o s i t ) ;
/ / Б а л а н с с ч е т а
C o n s o l e . W r i t e L i n e ( " С ч ет = { o } " ( |
b a . G e t S t r i n g ( ) ) ; |
// Добавляем очень |
малую |
величину |
double dAdditio n = |
0.002; |
|
Console . WriteLine("Вклад |
{ 0 : C } " , |
d A d d i t i o n ) ; |
b a . D e p o s i t ( d A d d i t i o n ) ; |
|
|
//Результат
Console . WriteLine(" В результате счет = { о } " , ba .GetString ()'');
// Ожидаем подтверждения пользователя Console . WriteLine("Нажмите <Enter> для " +
"завершения п р о г р а м м ы . . . " ) ;
C o n s o l e . R e a d ( ) ;
}
//BankAccount - определение класса, представляющего
//простейший банковский счет
public class |
BankAccount |
{ |
|
|
p r i v a t e |
static int n N e x t A c c o u n t N u m b e r = 1000 ; |
p r i v a t e |
int |
n A c c o u n t N u m b e r ; |
// хранение |
баланса в виде одной переменной типа decimal |
p r i v a t e |
decimal m B a l a n c e ; |
// Init - инициализация банковского счета с нулевым
//балансом и использованием очередного глобального
//номера
public v o i d InitBankAccount()
{
nAccountNumber = + + n N e x t A c c o u n t N u m b e r ; mBalance = 0;
}
// G e t B a l a n c e - получение текущего баланса public double GetBalance()
return (double)mBalance;
// A c c o u n t N u m b e r
public int GetAccountNumber()
{
return n A c c o u n t N u m b e r ;
}
public void SetAccountNumber(int nAccountNumber)
this . nAccountNumber = n A c c o u n t N u m b e r ;
}
240 |
Часть IV. Объектно-ориентированное программирование |
Глава |