
- •Лабораторная работа № 5 Тема: Функции и процедуры в с#
- •Теоретические сведения Процедуры и функции - методы класса
- •Процедуры и функции. Отличия
- •Описание методов (процедур и функций). Синтаксис
- •Список формальных аргументов
- •Тело метода
- •Вызов метода. Синтаксис
- •Вызов метода. Семантика
- •Почему у методов мало аргументов?
- •Поля класса или функции без аргументов?
- •Пример: класс Account
- •Функции с побочным эффектом
- •Оператор return
- •Рекурсия
- •Процедуры и массивы
- •Задача №1
- •Задача №2
- •Задача №3
- •Задача №4
- •3. Содержание отчета.
- •4. Вопросы для защиты по лабораторной работе:
Почему у методов мало аргументов?
Все дело в том, что методы класса- это не простопроцедуры; этопроцедуры, обслуживающие данные. Все поля доступны любому методу по определению. Нужно четко понимать, что в момент выполнения программной системы работа идет не склассом, а с объектами - экземплярамикласса. Из полей соответствующего объекта - цели вызова - извлекается информация, нужная методу в момент вызова, а работа метода чаще всего сводится к обновлению значений полей этого объекта. Поэтому очевидно, что методу не нужно черезвходные аргументыпередавать информацию, содержащуюся в полях. Если в результате работы метода обновляется значение некоторого поля, то, опять-таки, не нужен никакойвыходной аргумент.
Поля класса или функции без аргументов?
Поля хранят информацию о состоянии объектов класса. Состояние объекта динамически изменяется в ходе вычислений - обновляются значения полей. Часто возникающая дилемма при проектированиикласса: что лучше - создать ли поле, хранящее информацию, или создатьфункциюбез аргументов, вычисляющую значение этого поля всякий раз, когда это значение понадобится. Решение дилеммы - это вечный для программистов выбор между памятью и временем. Если предпочесть поле, то это приводит к дополнительным расходам памяти. Они могут быть значительными, когда создается большое число объектов - ведь свое поле должен иметь каждый объект. Если предпочестьфункцию, то это потребует временных затрат на вычисление значения, и затраты могут быть значительными в сравнении с выбором текущего значения поля.
Пример: класс Account
Помимо двух основных полей creditиdebit, хранящих приход и расход счета, введем полеbalance, которое задает текущее состояние счета, и два поля, связанных с последней выполняемой операцией. Полеsumбудет хранить сумму денег текущей операции, а полеresult- результат выполнения операции.
Описание нашего класса:
/// Класс Account определяет банковский счет. Простейший
/// вариант с возможностью трех операций: положить деньги
/// на счет, снять со счета, узнать баланс. Вариант с полями
public class Account {
//закрытые поля класса
int debit=0, credit=0, balance =0;
int sum =0, result=0;
/// Зачисление на счет с проверкой
public void putMoney(int sum) {
this.sum = sum;
if (sum >0) {
credit += sum; balance = credit - debit; result =1;
}
else result = -1;
Mes();
}
/// Снятие со счета с проверкой
public void getMoney(int sum) {
this.sum = sum;
if(sum <= balance) {
debit += sum; balance = credit - debit; result =2;
}
else result = -2;
Mes();
}
/// Уведомление о выполнении операции
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;
}
}
}
Как можно видеть, только у методов getMoneyиputMoneyимеется одинвходной аргумент. Это тот аргумент, который нужен по сути дела, поскольку только клиент может решить, какую сумму он хочет снять или положить на счет. Других аргументов у методовклассанет - вся информация передается через полякласса. Уменьшение числа аргументов приводит к повышению эффективности работы с методами, так как исчезают затраты на передачу фактических аргументов. Но за все надо платить. В данном случае, усложняются сами операции работы со вкладом, поскольку нужно в момент выполнения операции обновлять значения многих полейкласса.Закрытый методMesвызывается после выполнения каждой операции, сообщая о том, как прошла операция, и информируя клиента о текущем состоянии его баланса.
А теперь спроектируем аналогичный классAccount1, отличающийся только тем, что у него будет меньше полей. Вместо поляbalanceвклассепоявится соответствующаяфункцияс этим же именем, вместо полейsumиresultпоявятся аргументы у методов, обеспечивающие необходимую передачу информации. Вот как выглядит этоткласс:
/// Класс Account1 определяет банковский счет.
/// Вариант с аргументами и функциями
public class Account1{
//закрытые поля класса
int debit=0, credit=0;
/// Зачисление на счет с проверкой
public void putMoney(int sum) {
int res =1;
if (sum >0)credit += sum;
else res = -1;
Mes(res,sum);
}
/// Снятие со счета с проверкой
public void getMoney(int sum) {
int res=2;
if(sum <= balance())debit += sum;
else res = -2;
balance();
Mes(res, sum);
}
/// вычисление баланса
/// <returns>текущий баланс</returns>
int balance() {
return(credit - debit);
}
/// Уведомление о выполнении операции
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;
}
}
}
Сравнивая этот класссклассом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);
}