Свойство (программирование)
Информация должна быть проверяема, иначе она может быть поставлена под сомнение и удалена.
Вы можете отредактировать эту статью, добавив ссылки на авторитетные источники.
Эта отметка установлена 14 мая 2011.
Свойство — способ доступа к внутреннему состоянию объекта, имитирующий переменную некоторого типа. Обращение к свойству объекта выглядит так же, как и обращение к структурному полю (в структурном программировании), но, в действительности, реализовано через вызов функции. При попытке задать значение данного свойства вызывается один метод, а при попытке получить значение данного свойства — другой.
При применении свойств
- можно задать значение по умолчанию, которое будет храниться в данном свойстве (или указать, что никакого значения по умолчанию не предполагается);
- можно указать, что это свойство только для чтения.
Как правило, свойство связано с некоторым внутренним полем (переменной) объекта. Но свойству вообще может не быть сопоставлена ни одна переменная объекта, хотя пользователь данного объекта имеет дело с ним так, как если бы это было настоящее поле.
Свойства повышают гибкость и безопасность программирования, поскольку, являясь частью (открытого) интерфейса, позволяют менять внутреннюю реализацию объекта без изменения его свойств. По своей сути, свойства предназначены для того, чтобы свести программирование к операциям над свойствами, скрывая вызовы методов.
Методы свойств
Во многих языках программирования свойства реализуются в виде пары методов: метод, получающий текущее значение свойства, называется акцессор (accessor); метод, задающий новое значение свойства — мутатор (mutator). В языках программирования, не поддерживающих свойства, например C++ и Java, пара из акцессора и мутатора является общепринятым суррогатом для их замены.
Принято называть методы свойств именем свойства с приставками get и set: например, для свойства Xyzzy — get_Xyzzy и set_Xyzzy (традиционный стиль Си) либо GetXyzzy и SetXyzzy (стиль CamelCase). В связи с этой схемой наименования за методами свойств закрепились жаргонные названия getter и setter.
Примеры
Свойства в C#
Свойства в C# — поля с логическим блоком, в котором есть ключевые слова get и set .
Пример класса со свойством:
class MyClass private int p_field; public int Field get return p_field; > private set p_field = value; > > >
Свойства в VB.NET
Пример реализации в VB.NET. Если нужно реализовать свойство только для чтения или только для записи, применяются модификаторы ReadOnly и WriteOnly. Свойство может быть параметризованным. Также может быть свойством по умолчанию, для этого необходимо добавить модификатор Default
Sub Main Dim F As New Foo F.Data = 5 F.Item(0) = 5 F(0) = 5 'Запись в свойство Console.WriteLine(F(0)) 'Чтение свойства End Sub Public Class Foo Private m_Data As Integer Private m_Arr() As Integer = 1, 2, 3, 4, 5> Public Property Data As Integer Set(Value As Integer) 'Сеттер m_Data = Value End Set Get Return m_Data 'Геттер End Get End Property Public Default Property Item(Param As Integer) As Integer 'Параметризованное свойство по умолчанию Set(Value As Integer) m_Arr(Param) = Value End Set Get Return m_Arr(Param) End Get End Property End Class
Свойства в Delphi
Для описания свойства в Delphi служит слово property .
Пример класса со свойством:
TMyClass = class private FMyField: Integer; procedure SetMyField(const Value: Integer); function GetMyField: Integer; public property MyField: Integer read GetMyField write SetMyField; end; function TMyClass.GetMyField: Integer; begin Result := FMyField; end; procedure TMyClass.SetMyField(const Value: Integer); begin FMyField := Value; end;
Свойства в ActionScript
class MyClass private _foo : int; public function get foo () : int return _foo; > public function set foo (foo : int) : void _foo = foo; > >
Свойства в Objective C
@interface Company : NSObject NSString *name; > @property(retain) NSString *name; @end @implementation Company @synthesize name; @end
Свойства в Ruby
Описания свойства в Ruby ничем не отличается от описания метода. Например, для создания свойства duration у класса Song нужно описать методы duration и duration=(value)
class Song def duration @duration end def duration=(value) @duration = value end end
Однако простое обращение к внутренней переменной объекта может быть заменено на вызов метода attr_accessor :duration
class Song attr_accessor :duration end
Более интересным будет пример создания свойства duration_in_minutes, которое будет возвращать или устанавливать время длительности в минутах:
class Song def duration_in_minutes @duration/60.0 end def duration_in_minutes=(value) @duration = (value*60).to_i end end
При этом изменение свойства duration_in_minutes повлияет на свойство duration. Например
song = Song.new song.duration_in_minutes = 1.2 print song.duration # напечатает 72
См. также
- Концепции языков программирования
- Объектно-ориентированное программирование
Wikimedia Foundation . 2010 .
- Сборка мусора
- Компакт-кассета
Полезное
Смотреть что такое «Свойство (программирование)» в других словарях:
- Свойство объекта — в объектно ориентированном программировании характеристика объекта. Обычно свойства изменяются с помощью методов. См. также: Объектно ориентированное программирование Финансовый словарь Финам … Финансовый словарь
- Объектно-ориентированное программирование — Эта статья во многом или полностью опирается на неавторитетные источники. Информация из таких источников не соответствует требованию проверяемости представленной информации, и такие ссылки не показывают значимость темы статьи. Статью можно… … Википедия
- Автоматное программирование — Автоматное программирование это парадигма программирования, при использовании которой программа или её фрагмент осмысливается как модель какого либо формального автомата. В зависимости от конкретной задачи в автоматном программировании… … Википедия
- Инкапсуляция (программирование) — У этого термина существуют и другие значения, см. Инкапсуляция. В языках программирования инкапсуляция имеет одно из следующих значений, либо их комбинацию: языковой механизм ограничения доступа к определённым компонентам объекта; языковая… … Википедия
- Делегирование (программирование) — В объектно ориентированном программировании существуют два смежных понятия делегирования. В современном понимании это означает свойство языка программирования использовать правила поиска метода для диспетчеризации так называемых self calls… … Википедия
- Объектно-ориентированное программирование на Python — Объектно ориентированное программирование на Python программирование на Python с использованием парадигмы ООП: с самого начала Python проектировался как объектно ориентированный язык программирования[1]. Содержание 1 Введение 1.1 … Википедия
- Математическое программирование — математическая дисциплина, посвященная теории и методам решения задач о нахождении экстремумов функций на множествах, определяемых линейными и нелинейными ограничениями (равенствами и неравенствами). М. п. раздел науки об… … Большая советская энциклопедия
- МАТЕМАТИЧЕСКОЕ ПРОГРАММИРОВАНИЕ — математическая дисциплина, посвященная теории и методам решения задач о нахождении экстремумов функций на множествах конечномерного векторного пространства, определяемых линейными и нелинейными ограничениями (равенствами и неравенствами). М. п.… … Математическая энциклопедия
- ЛИНЕЙНОЕ ПРОГРАММИРОВАНИЕ — математическая дисциплина, посвященная теории и методам решения задач об экстремумах линейных функций на множествах n мерного векторного пространства, задаваемых системами линейных неравенств и равенств; Л. п. один из разделов математического… … Математическая энциклопедия
- Объектно-ориентированное программирование на Питоне — С самого начала Питон проектировался как объектно ориентированный язык программирования [1]. Содержание 1 Введение 1.1 Принципы ООП … Википедия
- Обратная связь: Техподдержка, Реклама на сайте
- Путешествия
Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.
- Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
- Искать во всех словарях
- Искать в переводах
- Искать в ИнтернетеИскать в этой же категории
Свойства (Руководство по программированию в C#)
Свойство — это член, предоставляющий гибкий механизм для чтения, записи или вычисления значения частного поля. Свойства можно использовать, как если бы они являются общедоступными элементами данных, но они являются специальными методами, называемыми методами доступа. Эта функция позволяет легко получать доступ к данным и по-прежнему способствовать обеспечению безопасности и гибкости методов.
Общие сведения о свойствах
- Свойства позволяют классу предоставлять общий способ получения и задания значений, скрывая при этом код реализации или проверки.
- Метод доступа get используется для возврата значения свойства, а метод доступа set — для присвоения нового значения. Метод доступа к свойству init используется для назначения нового значения только во время построения объекта. Эти методы доступа могут иметь различные уровни доступа. Дополнительные сведения см. в разделе Доступность методов доступа.
- Ключевое слово value используется для определения значения, присваиваемого методом доступа set или init .
- Свойства могут быть доступны для чтения и записи (они имеют оба метода доступа — get и set ), только для чтения (они имеют метод доступа get , но не имеют метода доступа set ) или только для записи (они имеют метод доступа set , но не имеют метода доступа get ). Свойства только для записи встречаются редко и чаще всего используются для ограничения доступа к конфиденциальным данным.
- Простые свойства, не требующие пользовательского кода метода доступа, можно реализовать как определения текста выражений или как автоматически реализуемые свойства.
Свойства с резервными полями
Одной из базовых схем реализации свойств является использование закрытого резервного поля для установки и извлечения значения свойства. Метод доступа get возвращает значение закрытого поля, а метод доступа set может выполнять определенные проверки данных до присвоения значению закрытого поля. Оба метода доступа также могут выполнять некоторые преобразования или вычисления данных перед его сохранением или возвратом.
Это показано в следующем примере. В этом примере класс TimePeriod представляет интервал времени. На внутреннем уровне класс сохраняет интервал времени в секундах в закрытом поле с именем _seconds . Свойство чтения и записи с именем Hours позволяет клиенту указывать временной интервал в часах. Методы доступа get и set выполняют необходимое преобразование между часами и секундами. Кроме того, метод доступа set проверяет данные и создает ArgumentOutOfRangeException, если указано недопустимое количество часов.
public class TimePeriod < private double _seconds; public double Hours < get < return _seconds / 3600; >set < if (value < 0 || value >24) throw new ArgumentOutOfRangeException(nameof(value), "The valid range is between 0 and 24."); _seconds = value * 3600; > > >
Чтобы получить и задать значение, можно получить и задать свойства, как показано в следующем примере:
TimePeriod t = new TimePeriod(); // The property assignment causes the 'set' accessor to be called. t.Hours = 24; // Retrieving the property causes the 'get' accessor to be called. Console.WriteLine($"Time in hours: "); // The example displays the following output: // Time in hours: 24
Определения текста выражений
Как правило, методы доступа к свойствам состоят из однострочных операторов, которые просто назначают или возвращают результат выражения. Эти свойства можно реализовать как члены, воплощающие выражение. Определения текста выражений состоят из символа => , за которым идет выражение, назначаемое свойству или извлекаемое из него.
Свойства, доступные только для чтения, могут реализовать get метод доступа в качестве элемента, на основе выражения. В этом случае не используется ни ключевое слово метода доступа get , ни ключевое слово return . В следующем примере показана реализация свойства только для чтения Name в виде члена, воплощающего выражение.
public class Person < private string _firstName; private string _lastName; public Person(string first, string last) < _firstName = first; _lastName = last; >public string Name => $" "; >
И get метод set доступа могут быть реализованы как члены с выражением. В этом случае необходимо указывать ключевые слова get и set . В следующем примере показано использование определений текста выражений для обоих методов доступа. Ключевое слово return не используется с методом get доступа.
public class SaleItem < string _name; decimal _cost; public SaleItem(string name, decimal cost) < _name = name; _cost = cost; >public string Name < get =>_name; set => _name = value; > public decimal Price < get =>_cost; set => _cost = value; > >
Автоматически реализуемые свойства
В некоторых случаях свойства get и set методы доступа просто назначают значение или извлекают значение из резервного поля, не включая дополнительную логику. С помощью автоматически реализуемых свойств можно упростить код, в то время как компилятор C# будет прозрачно предоставлять вам резервное поле.
Если у свойства есть методы доступа get и set (или get и init ), они оба должны быть автоматически реализованы. Автоматически реализуемое свойство определяется с помощью ключевых слов get и set без указания какой-либо реализации. Следующий пример аналогичен предыдущему, за исключением того, что Name и Price являются автоматически реализуемыми свойствами. В этом примере также удаляется параметризованный конструктор, что позволяет инициализировать объекты SaleItem , вызывая конструктор без параметров и инициализатор объекта.
public class SaleItem < public string Name < get; set; >public decimal Price < get; set; >>
Автоматически реализованные свойства могут объявлять различные специальные возможности для get методов доступа и set доступа. Обычно вы объявляете общедоступный get метод доступа и частный set метод доступа. Дополнительные сведения см. в статье об ограничении специальных возможностей доступа.
Обязательные свойства
Начиная с C# 11, можно добавить required член, чтобы принудительно инициализировать любое свойство или поле клиентского кода:
public class SaleItem < public required string Name < get; set; >public required decimal Price < get; set; >>
Чтобы создать SaleItem объект, необходимо задать как свойства, так Name и Price свойства с помощью инициализаторов объектов, как показано в следующем коде:
var item = new SaleItem < Name = "Shoes", Price = 19.95m >; Console.WriteLine($": sells for ");
См. также
- Использование свойств
- Свойства интерфейса
- Сравнение свойств и индексаторов
- Ограничение доступности методов доступа
- Автоматически реализуемые свойства
Спецификация языка C#
Дополнительные сведения см. в разделе Свойства в Спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
См. также
- Индексаторы
- Ключевое слово get
- Ключевое слово set
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Свойство (программирование)
Свойство — интерфейс доступа программиста к соответствующей переменной объекта. Свойство может быть просто другим именем переменной (поля) объекта, тогда компилятор подставляет на место свойства переменную. Если это не так — то при обращении программиста к свойству вызывается определённый метод, который выполняет определённые операции с объектом. В некоторых языках при обращении к свойству всегда вызывается метод, который, в простейшем случае, просто выполняет запись или чтение определённой переменной объекта.
Свойства повышают гибкость и безопасность программирования и являются важным инструментом, применяемым при разработке ПО.
Методы свойств
Во многих языках программирования свойства реализуются в виде пары методов: метод, получающий текущее значение свойства, называется акцессор (accessor); метод, задающий новое значение свойства — мутатор (mutator). В языках программирования, не поддерживающих свойства, например C++ и Java, пара из акцессора и мутатора является общепринятым суррогатом для их замены.
Принято называть методы свойств именем свойства с приставками get и set: например, для свойства Xyzzy — get_Xyzzy и set_Xyzzy (традиционный стиль Си) либо GetXyzzy и SetXyzzy (стиль CamelCase). В связи с этой схемой наименования за методами свойств закрепились жаргонные названия getter и setter.
Свойства в C#
Свойства в C# — поля с логическим блоком, в котором есть ключевые слова get и set .
Пример класса со свойством:
class MyClass { private int field; public int Field { get { return field; } set { field = value; } } }
Свойства в Delphi
Для описания свойства в Delphi служит слово property .
Пример класса со свойством:
TMyClass = class private FMyField: Integer; procedure SetMyField(const Value: Integer); function GetMyField: Integer; protected public property MyField: Integer read GetMyField write SetMyField; end;
Свойства в ActionScript
class MyClass { private _foo : int; public function get foo () : int { return _foo; } public function set foo (foo : int) : void { _foo = foo; } }
Свойства в Objective C
@interface Company : NSObject { NSString *name; } @property(retain) NSString *name; @end @implementation Company @synthesize name; @end
Свойства в Ruby
Описания свойства в Ruby ничем не отличается от описания метода. Например, для создания свойства duration у класса Song нужно описать методы duration и duration=(value)
class Song def duration @duration end def duration=(value) @duration = value end end
Однако простое обращение к внутренней переменной объекта может быть заменено на вызов метода attr_accessor :duration
class Song attr_accessor :duration end
Более интересным будет пример создания свойства duration_in_minutes, которое будет возвращать или устанавливать время длительности в минутах:
class Song def duration_in_minutes @duration/60.0 end def duration_in_minutes=(value) @duration = (value*60).to_i end end
При этом изменение свойства duration_in_minutes повлияет на свойство duration. Например
song = Song.new song.duration_in_minutes = 1.2 print song.duration # напечатает 72
Свойства против методов
На первый взгляд, такой вопрос как выбор свойства или метода кажется простым. Но это до тех пор, пока вы не столкнётесь с непониманием в своей команде. Хотя есть устоявшиеся практики, их формулировки достаточно расплывчаты. В такого рода вопросах есть некоторая степень свободы, которая затрудняет наш выбор, а кажущаяся простота даёт плодородную почву для споров.
Бэкграунд Java-программистов
Язык программирования — это основной инструмент программиста. Наличие или отсутствие каких-либо конструкций формирует определённый стиль кодирования. Вот, например, в Java нет свойств, есть только поля и методы.
Возьмём для примера следующий класс:
public class Point
Мы имеем класс, описывающий точку на плоскости. Что с ним не так? Во-первых, так как это открытые поля, то они доступны для редактирования извне. Во-вторых, мы открываем детали реализации, что храним точку в декартовых координатах.
Поэтому, обычно, так не пишут, а инкапсулируют поля за геттерами и сеттерами:
public class Point < private double x; private double y; public Point(double x, double y) < this.x = x; this.y = y; >public double getX() < return x; >public void setX(double x) < this.x = x; >public double getY() < return y; >public void setY(double y) < this.y = y; >>
Стандартная практика на Java, в IDE даже есть специальные генераторы для этого.
Мы убрали прямой доступ к полям с помощью методов get и set.
Хотя они выглядят как функции, в сущности, являются геттерами и сеттерами.
Сахар в Котлине
В Котлине у нас есть свойства и мы можем не писать простыню из методов get и set:
class Point(var x: Double, var y: Double)
Выглядит лаконично, не так ли? Обращение к свойству тоже удобно: x вместо getX() .
При необходимости мы можем переопределить геттер или сеттер:
var x: Double = 0 set(value) < if (value >= 0) field = value >
В Котлине мы всегда имеем дело со свойствами, поля скрыты за сеттерами и геттерами. То есть мы имеем все преимущества методов, но при этом можем обращаться как с полями.
Нам подвезли сахар, но старые привычки остались. Я часто замечаю, что программисты на Java продолжают писать методы get и set в классах на Котлине, когда это уже необязательно. Название самих методов говорит о том, что их можно сконвертировать в свойства. Но всегда ли нужно предпочесть свойство методу? Если у нас есть функция без параметров, то выбор не всегда очевиден.
Общепринятые соглашения
Официальная документация говорит нам, что функции без параметров могут быть взаимозаменяемы read-only свойствами.
Ниже дан алгоритм, по которому можно определить, когда предпочесть свойство методу:
- если свойство не бросает исключение (exception)
- дёшево для вычисления (или можно закешировать при первом запуске)
- возвращает одно и то же значение при каждом вызове, если состояние объекта не изменилось
Я ожидал увидеть более развёрнутое руководство. Для первого пункта я бы добавил про любой сайд-эффект, который может происходить при вызове функции. С последним пунктом тоже не всё так просто.
Например, если у нас есть класс User:
class User( val firstName: String, val lastName: String )
Нужно ли полное имя делать свойством или всё же методом?
val fullName get() = "$firstName $lastName"
В данном случае создаётся всегда новый объект String, хотя это деталь реализации. Но значения всегда будут равны при сравнении через equals. На крайний случай можно закешировать fullName, пожертвовав памятью.
Но вот пункт про вычислимость вызывает больше всего вопросов.
Сложно или легко вычислимые свойства
Кажется, это довольно расплывчатое требование. Что значит сложно вычислимое? Если подразумеваются тяжёлые вычисления, такие как запрос в сеть или к БД, то мы должны будем вынести вызов в отдельный поток. В этом случае асинхронный вызов будет выглядеть по-другому: метод с коллбэком, реактивный поток или корутина. Но речь, скорее всего, не об этом.
Рассмотрим следующий пример:
class DocumentModel
У нас есть класс модели документа, у которого есть свойство activePageIndex, которое возвращает текущий индекс страницы. Мы не знаем внутренней реализации, но предполагаем, что это свойство и согласно принятому соглашению, мы можем не беспокоиться о производительности и спокойно использовать его в цикле:
images.forEach < image ->document.addImage(image, document.activePageIndex) >
Допустим, чтобы получить текущую страницу, нужно пробежаться по всему документу, то есть сделать некоторые вычисления. В этом случае оптимально сохранить текущую страницу в переменную, прежде чем использовать её в цикле:
val pageIndex = document.activePageIndex images.forEach < image ->document.addImage(image, pageIndex) >
Но чтобы это понять, нужно заглянуть в реализацию. Когда программист видит свойство, то он делает некоторые допущения в использовании, полагая, что автор класса позаботился о принятом соглашении. В этом случае автор допустил небрежность, чем ввёл в заблуждение. По хорошему, нужно сделать метод вместо свойства для получения активной страницы и назвать её как-то по-другому, например, findActivePageIndex.
Интерфейс важнее реализации
С одной стороны, приведённый выше пример показывает, насколько важно думать об интерфейсе, как он будет использоваться на клиентской стороне. С другой стороны, реализация накладывает ограничение на интерфейс. Если сложные вычисления, то нужно использовать функцию вместо свойства. Здесь мы вступаем в некоторое противоречие, что первичнее, реализация или интерфейс? Мы заранее не можем сказать об эффективности и есть соблазн впасть в крайность — всегда делать методы в интерфейсе. Особенно после Java непривычно видеть свойства в интерфейсе. При этом, метод, начинающийся со слова get или set никого не смущает.
При проектировании интерфейса, по-моему, мы должны в первую очередь думать о клиентском коде. Если мы будем ставить реализацию впереди интерфейса, то мы получим плохой API класса. Цена такой ошибки может быть рефакторинг всех вызовов в проекте. Разработчики библиотек хорошо это понимают, когда изменение API ломает сторонний код или меняет поведение класса, на которое клиент не рассчитывал.
Частая ситуация, что интерфейс создают при помощи рефакторинга в IDE, извлекая из существующего класса. Похоже, что это порочная практика. В результате такого рефакторинга на выходе мы получаем кашу из методов, зачастую несвязанных между собой.
Интерфейс — это так же важно, как и подбор подходящего имени для переменной или функции. Это контракт между автором и пользователем интерфейса. Реализаций может быть множество, включая самые неоптимальные. Это уже детали. При реализации свойств мы должны позаботиться, чтобы оно соответствовало принятому соглашению о лёгкой вычислимости.
Фундаментальные отличия
Хорошо, предположим, мы принимаем, что интерфейс первичен по отношению к реализации. Но из каких соображений исходить при его проектировании. В каком случае выбрать свойство, а когда нужен метод?
У свойств и методов есть более глубокие различия. Когда мы проектируем класс, то его можно разделить на две условные части:
- Состояние. Можно рассматривать как данные, которые описывают характеристики или черты объекта. В этом случае больше подходят свойства.
- Поведение. То есть то, что можно сделать с объектом. За это отвечают методы.
Они обычно изменяют состояние.
Это довольно простое правило, которое поможет при выборе свойства или метода.
Методы принято начинать с глагола и если вы не можете подобрать ничего лучше, чем get/set, то это явный признак свойства.
Вместо заключения
Разберём первоначальный пример, только сделаем его интерфейсом:
interface Point
Так что с ним не так?
Во-первых, два отдельных сеттера для координат x и y. Когда мы определяем точку в пространстве, то мы задаём их в паре, то есть атомарно. Меняя их независимо, мы создаём возможность для ошибок.
Добавим метод для задания координат и сделаем координаты x и y только для чтения:
interface Point
Во-вторых, интерфейс недостаточно гибкий. Иногда удобно работать с полярными координатами, но в интерфейсе только прямоугольные. Таким образом, мы неявно раскрываем реализацию.
interface Point
Как мы видим, хороший интерфейс спроектировать не так просто. Хотя можно было бы ограничиться data-классом:
data class Point( var x: Double, var y: Double )