Перфолента.NET. ООП. Конструируем класс. Свойства. Часть 1. Упрощенное описание

Материал из ТХАБ.РФ
Перейти к: навигация, поиск

Конструируем класс. Свойства. Часть 1.

Упрощено, на основе оригинального Перфолента.NET. ООП. Конструируем класс. Свойства

Введение

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

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

Рассматривая конструирование собственных классов, мы уже ознакомились с полями и конструкторами и узнали, что:

  • все данные объекта хранятся в полях
  • конструкторы помогают заполнить начальные значения полей удобным и не противоречивым образом.

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

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

Отлично, это работает и решает все проблемы, кроме одной, то что логически выглядит как Свойство (характеристики) объекта больше не доступно для изменения и даже скрыто от внешнего наблюдателя. Вместо Свойство объект получает множество методов в лучшем случае начинающихся со слов Получить и Установить. Например:

    Получить_ИмяСобаки(), Установить Имя_Собаки()

Не красиво, не удобно, громоздко.

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

Конечно, такое решение потребовало доработки компилятора, который теперь обязан сам определять, где идет обращение к полю, а где к свойству, и для свойства компилятор должен вызывать соответствующие методы.

Свойства

Свойство можно представить, как своеобразную «обёртку» над полем. Свойство имеет оба или только один из методов Получить/Установить, а также может иметь одно или несколько полей для хранения связанных с ним данных. Свойство может не иметь «своих» полей, а оказывать влияние на поля других свойств или на поля, логически не связанные со свойствами, но такое поведение встречается довольно редко.

В языке Перфолента для создания свойства существуют два разных синтаксиса – полный и краткий (авто).

  • Полный позволяет контролировать все аспекты работы свойства, но содержит много кода по сравнению с полем.
  • Краткий способ (авто) позволяет компилятору автоматически добавить скрытое поле для хранения значения и дописать код методов

Получить/Установить, делая синтаксис определения свойства почти не отличимым от определения поля.

Что бы понять конструкцию свойства сначала рассмотрим полный синтаксис:

Класс Собака 
       &ВидноВсем
       Свойство Полное ИмяСобаки тип Строка
               // скрытое поле “_ИмяСобаки” для хранения значения свойства “ИмяСобаки”
              // скрытое поле должно начинаться со знака подчёркивания + ИмяСвойства
               Поле _ИмяСобаки тип Строка = "Без имени"
               // метод Получить для получения значения свойства ИмяСобаки
               Получить
                           Возврат _ИмяСобаки
               КонецПолучить
               //метод Установить для установки значения свойства ИмяСобаки
               Установить(НовоеИмя тип Строка)
                             // Какие-то проверки корректности присваиваемого значения
                           _ИмяСобаки = НовоеИмя
               КонецУстановить
       КонецСвойства
КонецКласса

Пояснения к коду:

  • ключевое слово Полное в этом примере является обязательным
  • названия методов Получить и Установить являются зарезервированными
  • Скрытое Поле обычно начинаться со знака подчёркивания + ИмяСвойства
  • при операции присваивания ИмяСобаки = “Жучка” автоматически (и скрыто от программиста т.е. не явно) будет вызван метод Установить

(“Жучка”)

  • Если в методе обратится напрямую _ИмяСвойства = “Какое-то значения” то присваивание нового значения будет без использования проверок

из метода Установить. Это верно только для методов находящихся внутри данного, т.к. для методов снаружи класса поле не видно, если у него нет атрибута &ВидноВсем…

Как видите, по сравнению с полем кода стало значительно больше. Однако, у нас появилось два метода Получить и Установить, в которых мы можем делать любые проверки, например, корректно ли новое значение, или можем выполнить какие-то действия необходимые при изменении значения свойства.

ПРИМЕР ИСПОЛЬЗОВАНИЯ: Как работает метод Установить

СобакаМаши = Новый Собака // создаём объект СобакаМаши по образцу класса Собака
СобакаМаши.ИмяСобаки = "Шарик" // Присваиваем свойству ИмяСобаки значение “Шарик”

Что при этом происходит? Мы присваиваем свойству ИмяСобаки значение также, как если бы это было Поле. Но при присваивании, скрытно (у программистов для этого есть специальный термин - “неявно”) вызывается метод Установить (имя метода “Установить” – специально зарезервировано в языке программирования для присваивания значений свойствам)

               Установить(НовоеИмя тип Строка)
                             // Какие-то проверки корректности присваиваемого значения
                            // например что длина имени от 2 до 15 символов 
                           _ИмяСобаки = НовоеИмя
               КонецУстановить

При неявном (скрытом) вызове метода Установить значение “Шарик” передаётся в качестве параметра НовоеИмя метода Установить т.е.

  Установить(“Шарик”)

Метод Установить приводит присвоение значения переменной НовоеИмя = ”Шарик”, скрытому Полю _ИмяСобаки. Коряво…

Для удобства программистов (чтобы всегда было просто определит какому свойству соответствует какое имя скрытого Поля) Имя поля выбирается добавлением “_” (знака подчёркивания) к имени Свойства.

“_” + ИмяСвойства = _ИмяСкрытогоПоля

При этом перед присвоением в Методе Установить можно сделать различные проверки на корректность присваиваемого значения. Поле _ИмяСобаки – имеет тип Строка – соответственно если мы ему присвоим значение “8ВА$” или “Собака соседки из соседнего подъезда” – то ошибки не будет, но очевидно, что эти значения именами собаки является не могут. Необходимы дополнительные проверки. Самое просто в данном случае – проверить длину имени (оно должна состоять от 2 до максимум 15 символов). Ещё можно проверить на то, что в имени присутствуют только буквы и нет символов “$ ? !” и т.п.

Если замечены ошибки, то необходимо сгенерировать сообщение, чтобы программист видел в каком месте программы и ошибка какого типа произошла. Это гораздо проще чем потом выяснять почему в базе данных при запросе не появляется имя собаки клиента с именем “8ВА$”, или происходит ошибка при записи в базу данных имени “ Собака соседки из соседнего подъезда” т.к. там стоит ограничение на длину имени в 15 символов.

Затем можно нормализовать имя если пользователь присвоил его не точно. Например, “шАрИк” или “шарик” можно преобразовать к “Шарик”.

При необходимости можно напрямую присвоить значение скрытому Полю, минуя проверки метода Установить. В основном это требуется для отладки объектов.

СобакаМаши._ИмяСобаки = "Шарик" 
// Присваиваем Скрытому Полю ИмяСобаки значение “Шарик” минуя проверки метода Установить 

Важно: Методы Установить (и Получить) неявные – т.е. они автоматически вызываются когда присваивается значение свойству (или читается значение свойства).

СобакаМаши.ИмяСобаки = "Шарик" // в момент выполнения  операции = “Шарик” автоматически вызывается  метод Установить которому передаётся  
значение “Шарик” и который присваивает его (после проверок) значению поля _ИмяСобаки

Нельзя в явном виде вызвать методы Установить (и Получить), например:

СобакаМаши.ИмяСобаки.Установить = "Шарик" // Ошибка

или

СобакаМаши.ИмяСобаки.Установить ("Шарик") // Ошибка

ПРИМЕР ИСПОЛЬЗОВАНИЯ: Как работает метод Получить

Вернёмся к нашему классу Собака

Класс Собака 
       &ВидноВсем
       Свойство Полное ИмяСобаки тип Строка
               // скрытое поле “_ИмяСобаки” для хранения значения свойства “ИмяСобаки”
               // скрытое поле должно начинаться со знака подчёркивания + ИмяСвойства
               Поле _ИмяСобаки тип Строка = "Без имени"
               // метод Получить для получения значения свойства ИмяСобаки
               Получить
                           Возврат _ИмяСобаки
               КонецПолучить
               //метод Установить для установки значения свойства ИмяСобаки
               Установить(НовоеИмя тип Строка)
                             // Какие-то проверки корректности присваиваемого значения
                           _ИмяСобаки = НовоеИмя
               КонецУстановить
       КонецСвойства
КонецКласса

Чтобы получить значение Свойства ИмяСобаки

СобакаМаши = Новый Собака // создаём объект СобакаМаши по образцу класса Собака
СобакаМаши.ИмяСобаки = "Шарик" // Присваиваем свойству ИмяСобаки значение “Шарик”
ВыводСтроки СобакаМаши.ИмяСобаки // Тут будет вызван метод Получить, который вернёт значение ”Шарик”

При вызове оператора ВыводСтроки происходит обращение к объекту СобакаМаши и её Свойству ИмяСобаки. При попытке прочитать значение Свойства ИмяСобаки у объекта СобакаМаши происходит скрыто (неявно) в вызов метода Получить

              // метод Получить для получения значения свойства ИмяСобаки
              Получить
                           Возврат _ИмяСобаки
               КонецПолучить

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

Перед выдачей значения Поля _ИмяСобаки оператором Возврат с этим значением можно провести некоторые операции например перевести Имя Собаки в верхний регистр “Шарик” ->”ШАРИК” или добавить описание:

Возврат “Имя Собаки : ” + _ИмяСобаки

Т.о. на экране появится не “Шарик”, а “ШАРИК” или “Имя Собаки : Шарик”

Можно напрямую прочитать значение поля _ИмяСобаки например так:

ВыводСтроки СобакаМаши._ИмяСобаки это не верно, если используется снаружи класса…

При этом мы получим значение Поля _ИмяСобаки минуя всякие обработки метода Получить.

Запрет на чтение и запись свойств

Если при объявлении Свойства не указать метод Установить - то присваивание значения этому Свойству ПОСЛЕ ИНИЦИАЛИЗАЦИИ будет невозможно. Это аналогично создания Свойства “только для чтения” – обычно это применяется для свойств значение которых не должно манятся после создания например: Артикул Товара, уникальный номер или код который присваивается при создании объекта по которому один объект можно легко отличить от другого, Фамилия, Имя и Отчество, дата рождения, номера документов и т.п.

Если при объявлении Свойства не указать метод Получить то получение значения этого Свойства будет невозможно т.к. отсутствует соответствующий метод. Т.о. Свойство получается “только для Записи”. Зачем это необходимо? Например, если в поле записан Пароль учётной записи пользователя – имеет смысл запретить читать его кому попало.

Все эти запреты сделаны для удобства и исключения ошибок самими программистами, а не для защиты от хакеров. Мы всегда сможем напрямую прочитать или записать значение Поля, связанного со Свойством. Это верно только для методов находящихся внутри класса, т.к. для методов снаружи класса поле не видно, если у него нет атрибута &ВидноВсем…

Например так:

СобакаМаши._ИмяСобаки = "Шарик" 
ВыводСтроки СобакаМаши._ИмяСобаки

Ссылки