русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Функции с побочным эффектом


Дата добавления: 2013-12-23; просмотров: 1318; Нарушение авторских прав


Пример: класс 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);

}

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);

}

 

Функция называется функцией с побочным эффектом, если помимо результата, вычисляемого функцией и возвращаемого ей в операторе return, она имеет выходные аргументы с ключевыми словами ref и out. В языках C/C++ функции с побочным эффектом применяются сплошь и рядом. Хороший стиль ОО-программирования не рекомендует использование таких функций. Выражения, использующие функции с побочным эффектом, могут потерять свои прекрасные свойства, присущие им в математике. Если f(a) - функция с побочным эффектом, то a+f(a) может быть не равно f(a) +a, так что теряется коммутативность операции сложения.

 

public void TestSideEffect() { // тестирование побочного эффекта

int a = 0, b=0, c=0;

a =1; b = a + f(ref a);

a =1; c = f(ref a)+ a;

Console.WriteLine("a={0}, b={1}, c={2}",a,b,c);

}

 

Результаты работы этого метода:

a=2, b=2, c=3;

Обратите внимание на полезность указания ключевого слова ref в момент вызова. Его появление оправдывает некоммутативность сложения.



<== предыдущая лекция | следующая лекция ==>
Вызов метода. Семантика | Процедуры и массивы


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.005 сек.