Пример: две версии класса Account

Проиллюстрируем рассмотренные выше вопросы на примере проектирования классов Account и Account1, описывающих такую абстракцию данных, как банковский счет. Определим на этих данных две основные операции - занесение денег на счет и снятие денег. В первом варианте - классе Account - будем активно использовать поля класса. Помимо двух основных полей credit и debit, хранящих приход и расход счета, введем поле balance, которое задает текущее состояние счета, и два поля, связанных с последней выполняемой операцией. Поле sum будет хранить сумму денег текущей операции, а поле result - результат выполнения операции. Полей у класса много, и как следствие, у методов класса аргументов будет немного. Вот описание нашего класса:

/// <summary>

/// Класс Account определяет банковский счет. Простейший

/// вариант с возможностью трех операций: положить деньги

/// на счет, снять со счета, узнать баланс. Вариант с полями

/// </summary>

public class Account

{

//закрытые поля класса

int debit=0, credit=0, balance =0;

int sum =0, result=0;

/// <summary>

/// Зачисление на счет с проверкой

/// </summary>

/// <param name="sum">зачисляемая сумма</param>

public void putMoney(int sum)

{

this.sum = sum;

if (sum >0)

{

credit += sum; balance = credit - debit; result =1;

}

else result = -1;

Mes();

}//putMoney

/// <summary>

/// Снятие со счета с проверкой

/// </summary>

/// <param name="sum"> снимаемая сумма</param>

public void getMoney(int sum)

{

this.sum = sum;

if(sum <= balance)

{

debit += sum; balance = credit - debit; result =2;

}

else result = -2;

Mes();

}//getMoney

/// <summary>

/// Уведомление о выполнении операции

/// </summary>

void Mes()

{

switch (result)

{

case 1:

Console.WriteLine("Операция зачисления денег

прошла успешно!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}",sum, balance);

break;

case 2:

Console.WriteLine("Операция снятия денег

прошла успешно!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance);

break;

case -1:

Console.WriteLine("Операция зачисления денег

не выполнена!");

Console.WriteLine("Сумма должна быть больше нуля!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance);

break;

case -2:

Console.WriteLine("Операция снятия денег

не выполнена!");

Console.WriteLine("Сумма должна быть

не больше баланса!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance);

break;

default:

Console.WriteLine("Неизвестная операция!");

break;

}

}

}//Account

Как можно видеть, только у методов getMoney и putMoney имеется один входной аргумент. Это тот аргумент, который нужен по сути дела, поскольку только клиент может решить, какую сумму он хочет снять или положить на счет. Других аргументов у методов класса нет - вся информация передается через поля класса. Уменьшение числа аргументов приводит к повышению эффективности работы с методами, так как исчезают затраты на передачу фактических аргументов. Но за все надо платить. В данном случае, усложняются сами операции работы со вкладом, поскольку нужно в момент выполнения операции обновлять значения многих полей класса. Закрытый метод Mes вызывается после выполнения каждой операции, сообщая о том, как прошла операция, и информируя клиента о текущем состоянии его баланса.

А теперь спроектируем аналогичный класс Account1, отличающийся только тем, что у него будет меньше полей. Вместо поля balance в классе появится соответствующая функция с этим же именем, вместо полей sum и result появятся аргументы у методов, обеспечивающие необходимую передачу информации. Вот как выглядит этот класс:

/// <summary>

/// Класс Account1 определяет банковский счет.

/// Вариант с аргументами и функциями

/// </summary>

public class Account1

{

//закрытые поля класса

int debit=0, credit=0;

/// <summary>

/// Зачисление на счет с проверкой

/// </summary>

/// <param name="sum">зачисляемая сумма</param>

public void putMoney(int sum)

{

int res =1;

if (sum >0)credit += sum;

else res = -1;

Mes(res,sum);

}//putMoney

/// <summary>

/// Снятие со счета с проверкой

/// </summary>

/// <param name="sum"> снимаемая сумма</param>

public void getMoney(int sum)

{

int res=2;

if(sum <= balance())debit += sum;

else res = -2;

balance();

Mes(res, sum);

}//getMoney

/// <summary>

/// вычисление баланса

/// </summary>

/// <returns>текущий баланс</returns>

int balance()

{

return(credit - debit);

}

/// <summary>

/// Уведомление о выполнении операции

/// </summary>

void Mes(int result, int sum)

{

switch (result)

{

case 1:

Console.WriteLine("Операция зачисления денег прошла успешно!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance());

break;

case 2:

Console.WriteLine("Операция снятия денег

прошла успешно!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance());

break;

case -1:

Console.WriteLine("Операция зачисления денег

не выполнена!");

Console.WriteLine("Сумма должна быть больше нуля!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance());

break;

case -2:

Console.WriteLine("Операция снятия денег не выполнена!");

Console.WriteLine("Сумма должна быть

не больше баланса!");

Console.WriteLine("Cумма={0},

Ваш текущий баланс={1}", sum,balance());

break;

default:

Console.WriteLine("Неизвестная операция!");

break;

}

}

}//Account1

Сравнивая этот класс с классом Account, можно видеть, что число полей сократилось с пяти до двух, упростились основные методы getMoney и putMoney. Но, в качестве платы, у класса появился дополнительный метод balance(), многократно вызываемый, и у метода Mes теперь появились два аргумента. Какой класс лучше? Однозначно сказать нельзя, все зависит от контекста, от приоритетов, заданных при создании конкретной системы.

Приведу процедуру класса Testing, тестирующую работу с классами Account и Account1:

public void TestAccounts()

{

Account myAccount = new Account();

myAccount.putMoney(6000);

myAccount.getMoney(2500);

myAccount.putMoney(1000);

myAccount.getMoney(4000);

myAccount.getMoney(1000);

//Аналогичная работа с классом Account1

Console.WriteLine("Новый класс и новый счет!");

Account1 myAccount1 = new Account1();

myAccount1.putMoney(6000);

myAccount1.getMoney(2500);

myAccount1.putMoney(1000);

myAccount1.getMoney(4000);

myAccount1.getMoney(1000);

}

На рис. 9.1 показаны результаты работы этой процедуры.

Пример: две версии класса Account - student2.ru

Рис. 9.1.Тестирование классов Account и Account1

Наши рекомендации