Помощь в написании студенческих работ
Антистрессовый сервис

Средства взаимодействия с объектами

РефератПомощь в написанииУзнать стоимостьмоей работы

Кроме традиционного для объектно-ориентированных языков применения специальных методов, обеспечивающих обращение к закрытым полям, язык C# позволяет получить к ним доступ с помощью механизма свойств. Однако свойство это не просто средство доступа к полям класса или его объекта. У свойств более широкие возможности. Дело в том, что в ряде случаев объекты класса могут иметь признаки, вторичные… Читать ещё >

Средства взаимодействия с объектами (реферат, курсовая, диплом, контрольная)

Принцип инкапсуляции и свойства классов

Объектно-ориентированное программирование базируется на трех принципах: полиморфизм, инкапсуляция и наследование. С проявлениями полиморфизма, а именно с перегрузкой методов и некоторых операций, мы уже познакомились.

Инкапсуляцию можно рассматривать как сокрытие особенностей реализации того или иного фрагмента программы от внешнего пользователя. Фрагмент должен быть доступен для обращений к нему только через внешний интерфейс фрагмента. Описания внешнего интерфейса должно быть достаточно для использования фрагмента. Если таким фрагментом является процедура (или функция), то нужно знать, как следует обратиться к процедуре, как передать ей необходимые входные данные и как получить результаты выполнения процедуры. Подробности внутренней реализации процедуры не должны интересовать того программиста, который использует процедуру. Именно принцип инкапсуляции лежит в основе запрета на использование в процедурах и функциях глобальных переменных. Ведь глобальная переменная определена вне процедуры и доступна внешним изменениям, не зависящим от обработки данных в ее теле.

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

  • 1) возможности повторного использования объектов класса, например, в других программах (в этих других программах понадобится только знание внешнего интерфейса объектов класса);
  • 2) возможности модифицировать внутреннюю реализацию класса без изменения тех программ, где применяются объекты этого класса;
  • 3) обеспечению защиты объекта от нежелательных и непредсказуемых взаимодействий с ним других фрагментов программ, в которых он используется.

Для реализации в классах принципа инкапсуляции используется разграничение доступа к его членам. Основной принцип состоит в следующем. Доступ к данным (к полям) объектов должен быть возможен только через средства внешнего интерфейса, предоставляемые классом. Если не рассматривать применений классов в цепочках наследования и в сборках (всему свое время, см. гл. 13), то реализацию класса определяют его закрытые члены (со спецификатором private), а внешний интерфейс — открытые (со спецификатором public). Обычная практика — закрывать все поля класса и открывать только те средства (например, методы), которых достаточно для работы с объектами класса.

Итак, поля классов рекомендуется определять как закрытые, а для обеспечения достаточно полного интерфейса вводить нужное количество открытых методов. Полнота внешнего интерфейса определяется требованиями тех программ, которые должны работать с классом и его объектами.

Объектно-ориентированный подход к программированию рекомендует для расширения внешнего интерфейса класса и его объектов вводить в класс специальные методы, позволяющие получать значения закрытых полей и позволяющие нужным способом задавать их значения. По-английски эти методы называют, соответственно, get method Оaccessor) — метод доступа и set method (mutator) — метод изменения. В зависимости от целей решаемых задач для каждого поля могут быть заданы или оба метода, или один из них.

Кроме традиционного для объектно-ориентированных языков применения специальных методов, обеспечивающих обращение к закрытым полям, язык C# позволяет получить к ним доступ с помощью механизма свойств. Однако свойство это не просто средство доступа к полям класса или его объекта. У свойств более широкие возможности. Дело в том, что в ряде случаев объекты класса могут иметь признаки, вторичные по отношению к значениям их полей. Например, для рассмотренного ранее класса чисел в научной нотации вторичными характеристиками каждого объекта можно сделать его значение в естественной форме вещественного числа или значение Юр, где р — порядок числа в научной нотации, представленный полем объекта. Если в классе треугольников полями объектов сделать длины трех сторон треугольника, то такие характеристики как периметр или площадь можно объявить свойствами объектов класса.

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

Для обращения к свойствам применяются их имена. Эти имена, как и имена полей, можно использовать в выражениях. Однако прежде чем объяснять особенности применения свойств, рассмотрим правила их объявления в классе.

Декларация свойства состоит из двух частей. Первая часть подобна объявлению поля и подобна заголовку метода без параметров и окружающих их круглых скобок. Вторая часть представляет собой конструкцию особого вида, включающую заключенную в фигурные скобки пару особых «методов» с фиксированными именами: get и set. Эти специфические методы называют аксессорами. Общую форму объявления свойства можно представить так:

модификаторы_свойстваор±

тип_свойства имя_свойства

{

декларация get-aKceccopaopt декларация set-aKceccopaopt

У

В качестве модификаторов свойства используются: new, public, protected, internal, private, static, virtual, sealed, override, abstract, extern

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

Тип_свойства — это тип той характеристики (того значения), которую представляет свойство.

Имя_свойства — идентификатор, выбираемый программистом для именования свойства.

Вторая часть объявления свойства (можно назвать ее телом объявления свойства) — это заключенная в фигурные скобки пара объявлений особых методов-аксессоров со специальными именами get и set.

Формат декларации аксессора доступа (get-аксессора):

модификаторы_аксессора0 pt get тело_аксессора

Формат декларации аксессора изменения (setаксессора):

модификаторы_аксессораорХ set тело_аксессора

Модификаторы аксессоров: protected, internal, private, protected internal, internal protected

Тело аксессора — это либо блок, либо пустой оператор, обозначаемый символом точка с запятой. Пустой оператор в качестве тела применяется для аксессоров тех свойств, которые объявлены с модификаторами abstract и extern. Сейчас такие свойства мы не рассматриваем.

Аксессор доступа (get-аксессор) подобен методу без параметров, возвращающему значение, тип которого определяется типом свойства. Достаточно часто аксессор доступа возвращает значение конкретного поля класса или его объекта. Для возврата значения из аксессора в его теле должен выполниться оператор

return выражение;

Аксессор изменения (set-аксессор) подобен методу с возвращаемым значением типа void и единственным неявно заданным параметром, значение которого определяет новое значение свойства. Тип параметра определяется типом свойства. Имя параметра, которое используется в теле аксессора изменений, всегда value.

В теле аксессоров свойства могут содержаться сложные алгоритмы обработки. Например, при изменении свойства можно контролировать диапазон допустимых значений. В теле аксессора доступа возвращаемое значение может вычисляться с учетом значений не одного, а разных полей, и т. д. Заметим, что свойство не вводит новых полей, а только управляет доступом к уже существующим в классе полям. Существует соглашение (не обязательное) начинать имена свойств с заглавных букв. Если свойство представляет «во внешнем мире» конкретное поле класса, то имя свойства повторяет имя поля, но отличается от него первой заглавной буквой. Например, если в классе объявлено поле tempor, то представляющее его свойство рекомендуется назвать Tempor.

Для примера еще раз обратимся к представлению чисел в научной нотации и изменим класс Real, введя в его декларацию объявление свойств (1201.cs):

// Класс чисел в научной нотации class Real {.

// Закрытые поля:

double m = 8.0; // мантисса — явно инициализирована int р; // инициализация по умолчанию II Свойство для получения значения мантиссы: public double Mantissa {.

get { return m; }.

}

// Свойство для показателя: public int Exponent {.

get { return p; } set { p = value; }.

>

// Свойство для значения числа: public double RealValue {.

get { return m * Math. Pow (10, p); } set { m = value; p = 0; reduceQ; }.

}

// Приведение числа к каноническому виду: void reduce ().

{// " Внутренний" для класса метод

double sign = 1; if (m = 10; m /= 10, p += 1); for (; m < 1; m *= 10, p -= 1); m *= sign;

}

>

В измененном классе Real уже рассмотренные закрытые члены: вспомогательный метод reduce (); поля: double m — мантисса, int р — показатель. Кроме того, объявлены три открытых свойства:

public double Mantissa — для получения значения мантиссы; public int Exponent — для получения и изменения показателя; public double RealValue — для получения числа в виде значения вещественного типа и для задания значений полей объекта по значению типа double.

В определении свойства Mantissa только один аксессор get, он позволяет получить значение поля double ш.

Свойство Exponent включает два аксессора: set {р = value;} — изменяет значение поля int р; get {return р;} — возвращает значение того же поля.

Свойство RealValue позволяет обратиться к объекту класса Real как к числовому значению типа double. Аксессоры свойства:

get {return m * Math. Pow (10, p);} set {m = value; p = 0; reduce ();}.

Аксессор get возвращает числовое значение, вычисленное на основе значений полей объекта.

Аксессор set, получив из внешнего обращения значение value, присваивает его переменной поля double m. При этом переменная int р получает нулевое значение. Затем для приведения числа к научной нотации в теле аксессора выполняется обращение к вспомогательному закрытому методу reduce (). Его мы уже рассмотрели в связи с обсуждением конструкторов.

Следующий фрагмент кода иллюстрирует применение свойств класса (программа 1201.cs):

static void Main ().

{

Real number = new Real (); // конструктор умолчания string form = «= {0,8:F5} * 10Л{1, -3:D2}» ;

Console.WriteLine («number» + form, number. Mantissa, number. Exponent); number. Exponent = 2;

Console.WriteLine («number» + form, number. Mantissa, number. Exponent);

Console.WriteLine («number RealValue = «.

+ number. RealValue);

number.RealValue = -314.159;

Console.WriteLine («number» + form, number. Mantissa, number. Exponent);

Console.WriteLine («number RealValue = «.

+ number. RealValue);

}

В программе с помощью конструктора умолчания Real () определен один объект класса чисел в научной нотации и объявлена ссылка number, ассоциированная с этим объектом. Дальнейшие манипуляции с объектом выполнены с помощью свойств Mantissa, Exponent, RealValue. Для обращения к ним используются уточненные имена вида «ссылка_на_объект.имя_свойства».

Результат выполнения программы:

number = 8,0 * 10Л00 number = 8,0 * 10л02 number RealValue = 800 number = -3,14 159 * 10л02 number RealValue = -314,159.

В первой строке результатов приведено изображение числа из объекта, созданного конструктором умолчания. Значения полей при выводе получены с помощью уточненных имен свойств number. Mantissa, number.Exponent.

Оператор number.Exponent = 2; через свойство Exponent изменяет значение поля показателя int р. Этим определяется вторая строка результатов выполнения программы.

В третьей строке — числовое значение объекта number, полученное с помощью свойства RealValue.

Оператор number.RealValue = -314.159; через свойство RealValue изменяет оба поля объекта number.

Результат изменения полей иллюстрирует предпоследняя строка результатов. В последней строке — значение свойства RealValue.

Аксессор get выполняется, когда из кода, внешнего по отношению к классу или его объекту, выполняется «чтение» значения свойства. При этом в точку вызова возвращается некоторое значение или ссылка на какой-то объект. Тип значения или ссылки соответствует типу в объявлении свойства. При этом возможны неявные приведения типов. Например, если get-аксессор возвращает значение типа int, а тип свойства double, то будет автоматически выполнено приведение типов. Аксессор get подобен методу без параметров, возвращающему значение или ссылку с типом свойства.

Если внешний по отношению к классу или его объекту код присваивает некоторое значение свойству, то вызывается set-аксессор этого свойства. В теле этого аксессора присвоенное свойству значение представлено специальной переменной с фиксированным именем value.

Тип этой переменной совпадает с типом свойства. У set-аксессора возвращаемое значение отсутствует. Можно считать, что set-аксессор функционально подобен методу с одним параметром. У этого параметра фиксированное имя value и тот же тип, что и тип свойства.

Можно использовать в объявлении свойства только один из аксессоров. Это позволяет вводить свойства только для записи (изменения) и свойства только для чтения. Возникает вопрос, чем открытое свойство, обеспечивающее только чтение, отличается от открытого поля, объявленного с модификатором readonly. Основное отличие в том, что поле хранит некоторое значение, которое не может изменить процесс чтения из этого поля. При чтении значения свойства есть возможность выполнить заранее запланированные действия (вычисления), причем никаких ограничений на характер этих действий (вычислений) не накладывается. Результат вычислений свойства может зависеть, например, от состояния среды, в которой выполняется программа, или от влияния процессов, выполняемых параллельно. Пример поля с модификатором readonly: «дата рождения». Свойство «точный возраст» должно вычисляться с учетом и поля «дата рождения» и конкретного момента обращения к этому свойству.

Отметим, что свойства, доступные для записи, можно использовать в инициализаторах объектов наряду с открытыми полями.

Показать весь текст
Заполнить форму текущей работой