Что такое геттеры и сеттеры и для чего они нужны
Что такое геттеры и сеттеры: терминология и сравнение методов
Геттеры и сеттеры встречаются во многих популярных языках программирования:
Где бы н и использовались геттеры и сеттеры, у них одна цель — защитить содержимое ваших скриптов, когда ими пользуется кто-нибудь другой.
Геттеры и сеттеры
Геттеры и сеттеры — это методы доступа, которые помогают вам управлять доступом к различным переменным в коде. В скриптах они пишутся так:
Чтобы лучше понять, как работают геттеры и сеттеры, нужно показать это на примере.
Геттеры и сеттеры для кваса
Итак, представим, что у нас есть собственная квас-машина наподобие кофе-машины, только с пивом:
//Наша квас-машина столько литров кваса не в местит!
//никого не тревожит, что наша квас-машина в мещает всего 50 литров кваса, все просто подходят и пьют
«Почему такой бардак с квасом происходит?» — спросите вы. А все потому, что объем нашей квас-машины доступен снаружи и абсолютно всем. Абсолютно любой может к ней обратиться и добавить или взять кваса столько, сколько за хочет. Для того чтобы такого не происходило, необходимо задать ограничение на использование нашей квас-машины со стороны остальных «любителей кваса».
Обычно контролировать в таких ситуациях можно при помощи приватного свойства, а записывать нужное значение при помощи сеттера. В нашем варианте это будет «setKvassAmount». Например:
var kvassAmount = 0;
var KVASS_COOL_VOLUME = 50;
return Amount * KVASS_HEAT_VOLUME * 40 / power;
// останавливаем квас-машину «с умом»
throw new Error(«Не может быть отрицательного значения»);
throw new Error(«Невозможно наливать большее количество кваса, чем » + volume);
alert( ‘Охлажденный квас!’ );
var kvassMachine = new KvassMachine(100, 50);
kvassMachine.setkvassAmount(500); // вот вам и ошибка!
function KvassMachine(power, volume) <
throw new Error(«Не может быть отрицательного значения»);
throw new Error(«Невозможно наливать большее количество кваса, чем » + volume);
var kvassMachine = new KvassMachine(100, 50);
alert( kvassMachine.getKvassAmount() ); // 500
Заключение
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Есть два типа свойств объекта.
Первый тип это свойства-данные (data properties). Мы уже знаем, как работать с ними. Все свойства, которые мы использовали до текущего момента, были свойствами-данными.
Второй тип свойств мы ещё не рассматривали. Это свойства-аксессоры (accessor properties). По своей сути это функции, которые используются для присвоения и получения значения, но во внешнем коде они выглядят как обычные свойства объекта.
Геттеры и сеттеры
Свойства-аксессоры представлены методами: «геттер» – для чтения и «сеттер» – для записи. При литеральном объявлении объекта они обозначаются get и set :
Геттер срабатывает, когда obj.propName читается, сеттер – когда значение присваивается.
Например, у нас есть объект user со свойствами name и surname :
Снаружи свойство-аксессор выглядит как обычное свойство. В этом и заключается смысл свойств-аксессоров. Мы не вызываем user.fullName как функцию, а читаем как обычное свойство: геттер выполнит всю работу за кулисами.
Давайте исправим это, добавив сеттер для user.fullName :
Дескрипторы свойств доступа
Дескрипторы свойств-аксессоров отличаются от «обычных» свойств-данных.
То есть, дескриптор аксессора может иметь:
Например, для создания аксессора fullName при помощи defineProperty мы можем передать дескриптор с использованием get и set :
Ещё раз заметим, что свойство объекта может быть либо свойством-аксессором (с методами get/set ), либо свойством-данным (со значением value ).
Умные геттеры/сеттеры
Геттеры/сеттеры можно использовать как обёртки над «реальными» значениями свойств, чтобы получить больше контроля над операциями с ними.
Использование для совместимости
У аксессоров есть интересная область применения – они позволяют в любой момент взять «обычное» свойство и изменить его поведение, поменяв на геттер и сеттер.
Давайте его сохраним.
Добавление геттера для age решит проблему:
Теперь старый код тоже работает, и у нас есть отличное дополнительное свойство!
Урок №115. Инкапсуляция, Геттеры и Сеттеры
Обновл. 13 Сен 2021 |
На предыдущем уроке мы узнали, что переменные-члены класса по умолчанию являются закрытыми. Новички, которые изучают объектно-ориентированное программирование, очень часто не понимают, почему всё обстоит именно так.
Зачем делать переменные-члены класса закрытыми?
В качестве ответа, воспользуемся аналогией. В современной жизни мы имеем доступ ко многим электронным устройствам. К телевизору есть пульт дистанционного управления, с помощью которого можно включать/выключать телевизор. Управление автомобилем позволяет в разы быстрее передвигаться между двумя точками. С помощью фотоаппарата можно делать снимки.
Все эти 3 вещи используют общий шаблон: они предоставляют вам простой интерфейс (кнопка, руль и т.д.) для выполнения определенного действия. Однако, то, как эти устройства фактически работают, скрыто от вас (как от пользователей). Для нажатия кнопки на пульте дистанционного управления вам не нужно знать, что выполняется «под капотом» пульта для взаимодействия с телевизором. Когда вы нажимаете на педаль газа в своем автомобиле, вам не нужно знать о том, как двигатель внутреннего сгорания приводит в движение колеса. Когда вы делаете снимок, вам не нужно знать, как датчики собирают свет в пиксельное изображение.
Такое разделение интерфейса и реализации чрезвычайно полезно, поскольку оно позволяет использовать объекты, без необходимости понимания их реализации. Это значительно снижает сложность использования этих устройств и значительно увеличивает их количество (устройства с которыми можно взаимодействовать).
По аналогичным причинам разделение реализации и интерфейса полезно и в программировании.
Инкапсуляция
В объектно-ориентированном программировании инкапсуляция (или «сокрытие информации») — это процесс скрытого хранения деталей реализации объекта. Пользователи обращаются к объекту через открытый интерфейс.
В языке C++ инкапсуляция реализована через спецификаторы доступа. Как правило, все переменные-члены класса являются закрытыми (скрывая детали реализации), а большинство методов являются открытыми (с открытым интерфейсом для пользователя). Хотя требование к пользователям использовать публичный интерфейс может показаться более обременительным, нежели просто открыть доступ к переменным-членам, но на самом деле это предоставляет большое количество полезных преимуществ, которые улучшают возможность повторного использования кода и его поддержку.
Преимущество №1: Инкапсулированные классы проще в использовании и уменьшают сложность ваших программ.
С полностью инкапсулированным классом вам нужно знать только то, какие методы являются доступными для использования, какие аргументы они принимают и какие значения возвращают. Не нужно знать, как класс реализован изнутри. Например, класс, содержащий список имен, может быть реализован с использованием динамического массива, строк C-style, std::array, std::vector, std::map, std::list или любой другой структуры данных. Для использования этого класса, вам не нужно знать детали его реализации. Это значительно снижает сложность ваших программ, а также уменьшает количество возможных ошибок. Это является ключевым преимуществом инкапсуляции.
Все классы Стандартной библиотеки C++ инкапсулированы. Представьте, насколько сложнее был бы процесс изучения языка C++, если бы вам нужно было знать реализацию std::string, std::vector или std::cout (и других объектов) для того, чтобы их использовать!
Преимущество №2: Инкапсулированные классы помогают защитить ваши данные и предотвращают их неправильное использование.
Глобальные переменные опасны, так как нет строгого контроля над тем, кто имеет к ним доступ и как их используют. Классы с открытыми членами имеют ту же проблему, только в меньших масштабах. Например, допустим, что нам нужно написать строковый класс. Мы могли бы начать со следующего:
Публичные свойства, геттеры и сеттеры или магические методы?
Пример использования публичных свойств:
В данном примере bar является публичным свойством класса Foo. При таком подходе мы можем манипулировать данным свойством как угодно и хранить в нём любые данные.
Пример использования геттеров и сеттеров:
Пример использования магических геттеров и сеттеров:
В данном случае свойство bar не является публичным, однако в коде оно используется так, как если бы было публичным. Когда PHP не может найти соответствующего публичного свойства он вызывает соответствующий магический метод ( __get() для получения значения, __set() для установки значения). Данный подход может показаться золотой серединой, но у него есть существенный недостаток (см. недостатки ниже!). Следует также отметить, что __get() и __set() методы НЕ вызываются для публичных свойств, и вызываются в случае, если свойство помечено как protected или private и находится за пределами области видимости, или если свойство не определено.
Другие альтернативы?
До изучения PHP я использовал C#. В C# все свойства имеют методы доступа, но вам не нужно вызывать их как методы, вы можете манипулировать свойсвами напрямую и соответствующие методы будут вызываться магически. Это в некотором роде это похоже на магические методы __get() и __set() в PHP, однако свойства остаются определены и доступны. Это золотая середина и было бы очень хорошо увидеть аналогичную возможность в PHP.
Геттеры и сеттеры в Python – что нужно знать
Геттеры и сеттеры в Python отличаются от методов в других языках ООП. Основное использование методов получения и установки – обеспечение инкапсуляции данных в объектно-ориентированных программах. В отличие от других объектно-ориентированных языков, частные переменные в Python не являются скрытыми полями. Некоторые языки ООП используют методы получения и установки для инкапсуляции данных. Мы хотим скрыть атрибуты класса объекта от других классов, чтобы методы других классов случайно не изменили данные.
В языках ООП геттеры и сеттеры используются для извлечения и обновления данных. Метод получения извлекает текущее значение атрибута объекта, тогда как средство установки изменяет значение атрибута объекта. В этой статье мы собираемся обсудить геттер и сеттер в Python с примерами.
Что такое геттер в Python?
Геттеры (получатели) в Python – это методы, которые используются в объектно-ориентированном программировании (ООП) для доступа к частным атрибутам класса. Функция setattr() в Python согласовывается с функцией getattr() в Python. Она изменяет значения атрибутов объекта.
Что такое сеттер в Python?
Сеттер (установщик) в Python – это метод, который используется для установки значения свойства. В объектно-ориентированном программировании очень полезно устанавливать значение частных атрибутов в классе.
Как правило, геттеры и сеттеры в основном используются для обеспечения инкапсуляции данных в ООП.
Использование обычной функции для выполнения функций геттеров и сеттеров
Не будет специальной реализации, если мы укажем обычные методы get() и set() для достижения свойства getters и setters.
Давайте рассмотрим пример, чтобы понять, как мы можем использовать обычную функцию для получения функций получения и установки.
После выполнения этого кода мы получим вывод, как показано ниже:
Для достижения такой функциональности методы get age() и set age() в приведенном выше коде работают как стандартные функции и не влияют на методы получения и установки. Python имеет уникальное свойство функции().
Использование функции property() в качестве геттеров и сеттеров
В Python property() является встроенной функцией для создания и возврата свойства объекта. Есть три метода: getter(), setter() и delete(). В Python функция property() принимает четыре аргумента: свойства (fget, fset, fdel, doc). Функция fget используется для получения значения атрибута. Функция fset используется для установки значения атрибута. Функция fdel используется для удаления значения атрибута. Атрибуту присваивается строка документации doc.
Давайте рассмотрим пример, чтобы понять, как мы можем использовать функцию property() для достижения поведения геттеров и сеттеров.
Вывод: после выполнения этого кода выше мы получим вывод, как показано ниже:
В приведенной выше программе есть только один оператор печати. Выходные данные состоят из трех строк из-за вызываемого метода установки set age() и getter метода get age(). В результате возраст – это объект свойства, который помогает обеспечить безопасность доступа к частным переменным.
Использование декораторов @property
Мы использовали функцию property() в предыдущем методе для достижения поведения геттеров и сеттеров. Однако, как упоминалось ранее в этой статье, геттеры и сеттеры также используются для проверки получения и установки значений атрибутов.
Другой метод принудительного выполнения функции свойства – использование декоратора. @property – один из встроенных декораторов Python. Основная цель любого декоратора – изменить методы или атрибуты класса, чтобы пользователю класса не нужно было изменять свой код.
Давайте рассмотрим пример, чтобы понять, как мы можем использовать декораторы @property для достижения поведения геттеров и сеттеров.
В приведенном выше коде показано, как использовать декоратор @property для создания методов получения и установки. Приведенный выше пример служит кодом проверки, вызывающим ошибку ValueError, если мы пытаемся инициализировать age со значением меньше 20.
Делаем атрибуты приватными
Теперь мы увидим, как сделать методы закрытыми, чтобы внешние вызывающие функции не могли манипулировать переменными внутри них. Ими можно управлять только с помощью функций, определенных в классе. Они становятся закрытыми, если ставить перед ними два символа подчеркивания.
Давайте рассмотрим пример, чтобы понять, как мы можем сделать атрибуты закрытыми в программе.
Вывод: после выполнения этого кода выше мы получим вывод, как показано ниже:
Чтение значений из частных методов
Чтобы прочитать значение из частных методов, мы должны использовать метод получения. Без использования метода получения мы не можем использовать метод свойств для доступа к значениям частных атрибутов. Давайте рассмотрим пример, чтобы понять этот метод.
Возьмем еще один пример создания класса со свойствами. Из этого класса мы возьмем несколько объектов.
Для этих объектов свойство (Emp) не задано. Мы могли бы установить его напрямую, но это не лучший метод. Вместо этого мы создаем два метода: getEmp() и setEmp().