Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Что нужно знать о методах?






Знания формального синтаксиса и семантики недостаточно, чтобы эффективно работать с методами. Рассмотрим сейчас несколько важных вопросов, касающихся различных сторон работы с методами класса.

Почему у методов мало аргументов?

Методы класса имеют значительно меньше аргументов, чем процедуры и функции в классическом процедурном стиле программирования, когда не используется концепция классов. За счет чего происходит уменьшение числа аргументов у методов? Ведь аргументы играют важную роль - они передают методу информацию, нужную ему для работы, и возвращают информацию - результаты работы метода - программе, вызвавшей метод.

Все дело в том, что методы класса - это не просто набор процедур и функций, это методы, обслуживающие данные класса. Все поля класса доступны любому методу по определению. Нужно четко понимать, что в момент выполнения программной системы работа идет с объектами - экземплярами класса. Из полей соответствующего объекта - цели вызова - извлекается информация, нужная методу в процессе работы, а работа метода чаще всего сводится к обновлению значений полей этого объекта. Поэтому понятно, что методу не нужно через входные аргументы передавать информацию, содержащуюся в полях. Если в результате работы метода обновляется значение некоторого поля, то, опять-таки, не нужен никакой выходной аргумент.

Поля класса или функции без аргументов?

Поля хранят информацию о состоянии объектов класса. Состояние объекта динамически изменяется в ходе вычислений - обновляются значения полей. Часто возникающая дилемма при проектировании класса: что лучше - создать ли поле, хранящее информацию, или создать функцию без аргументов, вычисляющую значение этого поля всякий раз, когда это значение понадобится. Решение дилеммы - это вечный для программистов выбор между памятью и временем. Если предпочесть поле, то неизбежны дополнительные расходы памяти. Они могут быть значительными, когда создается большое число объектов, ведь поле должен иметь каждый объект. Если предпочесть функцию, то это потребует временных затрат на вычисление значения, они могут быть значительными, если функция вызывается многократно, а ее вычисление требует значительно больших затрат в сравнении с выбором текущего значения поля.

Пример: Две версии класса 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, можно видеть, что число полей сократилось с 5 до двух, упростились основные методы getMoney и putMoney. Но в качестве платы у класса появился дополнительный метод balance(), у метода Mes теперь появились два аргумента. Какой класс лучше? Однозначно сказать нельзя, все зависит от контекста, приоритетов, заданных при создании конкретной системы.

Ресурсы для выражений

Говоря о ресурсах, требуемых программе P, часто используют термины " временная" и " емкостная сложность" - T(P) и V(P). Выражения представляют хорошую начальную базу для оценивания этих характеристик.

Характеристики T(P) и V(P) обычно взаимосвязаны. Увеличивая расходы памяти, можно уменьшить время решения задачи или, выбирая другое решение, сократить расходы памяти, увеличивая время работы. Одна из реальных задач, стоящих перед профессиональным программистом - это нахождение нужного компромисса между памятью и временем.

Как этот компромисс достигается на уровне выражений? Если в исходном выражении можно выделить повторяющиеся подвыражения, то для них следует ввести временные переменные. Увеличивая расходы памяти на введение дополнительных переменных, уменьшаем общее время вычисления выражения, поскольку каждое из подвыражений будет вычисляться только один раз. Этот прием целесообразно применять и тогда, когда не преследуется цель экономии времени. Введение дополнительных переменных уменьшает сложность выражения, что облегчает его отладку и способствует повышению надежности программы. Вероятность допустить ошибку в записи громоздкого выражения значительно выше, чем при записи нескольких простых выражений.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.