Метод мутатора - Mutator method
В Информатика, а метод мутатора это метод используется для управления изменениями переменной. Они также широко известны как сеттер методы. Часто сеттера сопровождает добытчик (также известный как аксессуар), который возвращает значение частной переменной-члена.
Метод мутатора чаще всего используется в объектно-ориентированного программирования, в соответствии с принципом инкапсуляция. Согласно этому принципу, член переменные из учебный класс делаются закрытыми, чтобы скрыть и защитить их от другого кода, и могут быть изменены только с помощью общедоступной функции-члена (метода мутатора), которая принимает желаемое новое значение в качестве параметра, при необходимости проверяет его и изменяет частное переменная-член. Методы мутатора можно сравнить с назначение перегрузка оператора но обычно они появляются на разных уровнях иерархии объектов.
Методы мутатора также могут использоваться в не объектно-ориентированных средах. В этом случае ссылка к изменяемой переменной передается в мутатор вместе с новым значением. В этом сценарии компилятор не может запретить коду обойти метод мутатора и напрямую изменить переменную. Ответственность ложится на Разработчики чтобы переменная изменялась только с помощью метода мутатора, а не напрямую.
В языках программирования, которые их поддерживают, характеристики предлагают удобную альтернативу без отказа от инкапсуляции.
В приведенных ниже примерах полностью реализованный метод мутатора также может подтверждать входных данных или предпринять дальнейшие действия, такие как запуск мероприятие.
Подразумеваемое
Альтернатива определению методов мутатора и доступа, или свойство блоков, это дать переменная экземпляра немного видимость кроме частного, и получить к нему доступ непосредственно извне объектов. Более точный контроль прав доступа может быть определен с помощью мутаторов и средств доступа. Например, параметр можно сделать доступным только для чтения, просто определив метод доступа, но не мутатор. Видимость двух методов может быть разной; часто бывает полезно, чтобы метод доступа был общедоступным, в то время как мутатор оставался защищенным, закрытым для пакета или внутренним.
В блокировать где определен мутатор, дает возможность Проверка или предварительная обработка входящих данных. Если гарантировано, что весь внешний доступ осуществляется через мутатор, то эти шаги нельзя обойти. Например, если дата представлена отдельным частным год
, месяц
и день
переменные, то входящие даты могут быть разделены на setDate
мутатор, в то время как для согласованности к тем же переменным частного экземпляра обращается setYear
и setMonth
. Во всех случаях значения месяцев за пределами 1–12 могут быть отклонены одним и тем же кодом.
Аксессоры, наоборот, позволяют синтезировать полезные представления данных из внутренних переменных, сохраняя при этом их структуру инкапсулированной и скрытой от внешних модулей. Денежный getAmount
аксессор может построить строку из числовой переменной с количеством десятичных знаков, определенным скрытым валюта
параметр.
Современные языки программирования часто предлагают возможность генерировать шаблон для мутаторов и средств доступа в одной строке - например, C # общедоступная строка Имя {получить; набор; }
и Руби attr_accessor: имя
. В этих случаях блоки кода не создаются для проверки, предварительной обработки или синтеза. Эти упрощенные средства доступа по-прежнему сохраняют преимущество инкапсуляции над простыми общедоступными переменными экземпляра, но обычно, поскольку система проектирует прогресс, программное обеспечение поддерживается и требования меняются, требования к данным становятся более изощренными. Многие автоматические мутаторы и аксессоры со временем заменяются отдельными блоками кода. Преимущество их автоматического создания на ранних этапах реализации заключается в том, что открытый интерфейс класса остается идентичным вне зависимости от того, добавляется ли большая изощренность, и при этом не требуется обширного рефакторинга.[1]
Манипулирование параметрами, имеющими мутаторы и методы доступа из внутри класс, в котором они определены, часто требует дополнительных размышлений. В первые дни реализации, когда в этих блоках мало или совсем нет дополнительного кода, не имеет значения, осуществляется прямой доступ к частной переменной экземпляра или нет. В качестве подтверждения перекрестная проверка, целостность данных добавлены проверки, предварительная обработка или другая сложность, тонкая ошибки может появиться там, где при некотором внутреннем доступе используется новый код, а в других местах он обойден.
Функции аксессоров могут быть менее эффективными, чем прямая выборка или сохранение полей данных, из-за задействованных дополнительных шагов,[2] однако такие функции часто встроенный что устраняет накладные расходы на вызов функции.
Примеры
сборка
ученик структура возраст дд ?ученик заканчивается
.кодstudent_get_age proc объект:DWORD mov ebx, объект mov eax, student.age[ebx] Retstudent_get_age конецstudent_set_age proc объект:DWORD, возраст:DWORD mov ebx, объект mov eax, возраст mov student.age[ebx], eax Retstudent_set_age конец
C
В файле student.h:
#ifndef _STUDENT_H#define _STUDENT_Hструктура ученик; / * непрозрачная структура * /typedef структура ученик ученик;ученик *student_new(int возраст, char *имя);пустота student_delete(ученик *s);пустота student_set_age(ученик *s, int возраст);int student_get_age(ученик *s);char *student_get_name(ученик *s);#endif
В файле student.c:
#включают <stdlib.h>#включают <string.h>#включают "student.h"структура ученик { int возраст; char *имя;};ученик *student_new(int возраст, char *имя) { ученик *s = маллок(размер(ученик)); s->имя = strdup(имя); s->возраст = возраст; возвращаться s;}пустота student_delete(ученик *s) { свободный(s->имя); свободный(s);}пустота student_set_age(ученик *s, int возраст) { s->возраст = возраст;}int student_get_age(ученик *s) { возвращаться s->возраст;}char *student_get_name(ученик *s) { возвращаться s->имя;}
В файле main.c:
#включают <stdio.h>#включают "student.h"int главный(пустота) { ученик *s = student_new(19, "Морис"); char *имя = student_get_name(s); int старость = student_get_age(s); printf("Старость% s =% i п", имя, старость); student_set_age(s, 21); int new_age = student_get_age(s); printf("Новый век% s =% i п", имя, new_age); student_delete(s); возвращаться 0;}
В файле Makefile:
все: из.текст; Кот $<out.txt: главный; ./$< > $@главный: главный.о ученик.оmain.o student.o: ученик.часчистый: ;$(RM) *.о из.текст главный
C ++
В файле Student.h:
#ifndef STUDENT_H#define STUDENT_H#включают <string>учебный класс Ученик {общественный: Ученик(const стандартное::нить& имя); const стандартное::нить& имя() const; пустота имя(const стандартное::нить& имя);частный: стандартное::нить имя_;};#endif
В файле Student.cpp:
#включают "Студент.h"Ученик::Ученик(const стандартное::нить& имя) : имя_(имя) {}const стандартное::нить& Ученик::имя() const { возвращаться имя_;}пустота Ученик::имя(const стандартное::нить& имя) { имя_ = имя;}
C #
Этот пример иллюстрирует C # Идея характеристики, которые представляют собой особый тип учебный класс член. В отличие от Java, явные методы не определены; публичное «свойство» содержит логику для обработки действий. Обратите внимание на использование встроенной (необъявленной) переменной ценить
.
общественный учебный класс Ученик { частный нить имя; /// <резюме> /// Получает или задает имя студента /// общественный нить Имя { получать { возвращаться имя; } набор { имя = ценить; } }}
В более поздних версиях C # (.NET Framework 3.5 и выше) этот пример может быть сокращен следующим образом, без объявления частной переменной имя
.
общественный учебный класс Ученик { общественный нить Имя { получать; набор; }}
Использование сокращенного синтаксиса означает, что базовая переменная больше не доступна изнутри класса. В результате набор
часть имущества должна присутствовать при переуступке. Доступ можно ограничить с помощью набор
-специфический модификатор доступа.
общественный учебный класс Ученик { общественный нить Имя { получать; частный набор; }}
Common Lisp
В Общая объектная система Lisp, спецификации слотов в определениях классов могут указывать любой из : reader
, : писатель
и : аксессуар
параметры (даже несколько раз) для определения методов чтения, методов установки и методов доступа (метод чтения и соответствующие setf
метод).[3] Слоты всегда напрямую доступны через их имена с использованием с прорезями
и значение слота
, а параметры доступа к слоту определяют специализированные методы, которые используют значение слота
.[4]
Сам CLOS не имеет понятия свойств, хотя Протокол MetaObject extension определяет средства доступа к именам функций чтения и записи слота, включая те, которые сгенерированы с помощью : аксессуар
вариант.[5]
В следующем примере показано определение класса ученика с использованием этих параметров слота и прямого доступа к слоту:
(defclass ученик () ((имя : initarg :имя : initform "" : аксессуар имя студента) ; имя студента устанавливаетсяf'able (Дата рождения : initarg :Дата рождения : initform 0 : reader дата рождения студента) (номер : initarg :номер : initform 0 : reader Количество учащихся : писатель набор-номер-студента)));; Пример вычисляемого геттера свойства (это просто метод)(defmethod студенческий возраст ((себя ученик)) (- (получить универсальное время) (дата рождения студента себя)));; Пример прямого доступа к слоту внутри вычисляемого установщика свойств(defmethod (setf студенческий возраст) (нью-эйдж (себя ученик)) (с прорезями (Дата рождения) себя (setf Дата рождения (- (получить универсальное время) нью-эйдж)) нью-эйдж));; Опции доступа к слотам генерируют методы, что позволяет определять дальнейшие методы.(defmethod набор-номер-студента :перед (новый номер (себя ученик)) ;; Вы также можете проверить, существует ли уже ученик с новым номером. (чек-тип новый номер (целое число 1 *)))
D
D поддерживает синтаксис функций получения и установки. В версии 2 методов класса / структуры языка getter и setter должны быть @свойство
атрибут.[6][7]
учебный класс Ученик { частный char[] имя_; // Геттер @свойство char[] имя() { возвращаться это.имя_; } // Сеттер @свойство char[] имя(char[] name_in) { возвращаться это.имя_ = name_in; }}
А Ученик
instance можно использовать так:
авто ученик = новый Ученик;ученик.имя = "Дэйвид"; // тот же эффект, что и student.name ("Дэвид")авто имя студента = ученик.имя; // тот же эффект, что и student.name ()
Delphi
Это простой класс на языке Delphi, который иллюстрирует концепцию общедоступного свойства для доступа к частному полю.
интерфейстип TStudent = учебный класс строгий частный FName: нить; процедура Имя набора(const Ценить: нить); общественный /// <резюме> /// Получить или установить имя студента. /// свойство Имя: нить читать FName записывать Имя набора; конец;// ...выполнениепроцедура TStudent.Имя набора(const Ценить: нить);начинать FName := Ценить;конец;конец.
Ява
В этом примере простого учебный класс представляя студента с сохраненным только именем, можно увидеть Переменная имя является закрытым, т.е. видимым только из класса Student, а "сеттер" и "получатель" являются общедоступными, а именно "getName ()
" и "setName (имя)
"методы.
общественный учебный класс Ученик { частный Нить имя; общественный Нить getName() { возвращаться имя; } общественный пустота Имя набора(Нить новое имя) { имя = новое имя; }}
JavaScript
В этом примере конструктор-функция Ученик
используется для создания объектов, представляющих учащегося, с сохранением только имени.
функция Ученик(имя) { вар _имя = имя; это.getName = функция() { возвращаться _имя; }; это.Имя набора = функция(ценить) { _имя = ценить; };}
Или (нестандартный):
функция Ученик(имя){ вар _имя = имя; это.__defineGetter__('имя', функция() { возвращаться _имя; }); это.__defineSetter__('имя', функция(ценить) { _имя = ценить; });}
Или (если использовать прототипы для наследования; ECMA-6!):
функция Ученик(имя){ это._имя = имя;}Ученик.прототип = { получать имя() { возвращаться это._имя; }, набор имя(ценить) { это._имя = ценить; }};
Или (без использования прототипов; ECMA-6):
вар Ученик = { получать имя() { возвращаться это._имя; }, набор имя(ценить) { это._имя = ценить; }};
Или (при использовании defineProperty):
функция Ученик(имя){ это._имя = имя;}Объект.defineProperty(Ученик.прототип, 'имя', { получать: функция() { возвращаться это._имя; }, набор: функция(ценить) { это._имя = ценить; }});
ActionScript 3.0
упаковка{ общественный учебный класс Ученик { частный вар _имя : Нить; общественный функция получать имя() : Нить { возвращаться _имя; } общественный функция набор имя(ценить : Нить) : пустота { _имя = ценить; } }}
Цель-C
Используя традиционный синтаксис Objective-C 1.0, с ручным подсчетом ссылок как с тем, над которым работает GNUstep на Ubuntu 12.04:
@интерфейс Ученик : NSObject{ NSString *_имя;}- (NSString *)имя;- (пустота)Имя набора:(NSString *)имя;@конец@выполнение Ученик- (NSString *)имя{ возвращаться _имя;}- (пустота)Имя набора:(NSString *)имя{ [_имя релиз]; _имя = [имя удерживать];}@конец
Использование нового синтаксиса Objective-C 2.0, как в Mac OS X 10.6, iOS 4 и Xcode 3.2, генерируя тот же код, что и описанный выше:
@интерфейс Ученик : NSObject@свойство (неатомный, удерживать) NSString *имя;@конец@выполнение Ученик@синтезировать имя = _имя;@конец
И начиная с OS X 10.8 и iOS 6, при использовании Xcode 4.4 и выше синтаксис можно даже упростить:
@интерфейс Ученик : NSObject@свойство (неатомный, сильный) NSString *имя;@конец@выполнение Ученик// Здесь ничего не происходит, и все в порядке.@конец
Perl
упаковка Ученик;суб новый { благословить {}, сдвиг;}суб Имя набора { мой $ self = сдвиг; $ self->{имя} = $_[0];}суб get_name { мой $ self = сдвиг; возвращаться $ self->{имя};}1;
Или, используя Class :: Accessor
упаковка Ученик;использовать основание qw (Класс :: Аксессор);__УПАКОВКА__->follow_best_practice;Ученик->mk_accessors(qw (имя));1;
Или, используя Объектная система лося:
упаковка Ученик;использовать лось;# Moose использует имя атрибута как свойства установки и получения, чтения и записи# позволяет нам переопределить это и указать наши собственные имена, в данном случае get_name и set_nameимеет 'имя' => (является => 'rw', это => 'Str', читатель => 'get_name', писатель => 'Имя набора');1;
PHP
В этом примере простого учебный класс представляя студента с сохраненным только именем, можно увидеть Переменная имя является частным, т.е. видимым только из класса Student, а "установщик" и "получатель" являются общедоступными, а именно getName ()
и setName ('имя')
методы.
учебный класс Ученик{ частный нить $ name; /** * @return string Имя. */ общественный функция getName(): нить { возвращаться $ это->имя; } /** * @param string $ newName Имя, которое нужно установить. */ общественный функция Имя набора(нить $ newName): пустота { $ это->имя = $ newName; }}
Python
В этом примере используется класс Python с одной переменной, геттером и сеттером.
учебный класс Ученик: # Инициализатор def __в этом__(себя, имя: ул) -> Никто: # Переменная экземпляра для хранения имени студента себя._имя = имя # Метод получения @свойство def имя(себя): возвращаться себя._имя # Метод установки @имя.сеттер def имя(себя, новое имя): себя._имя = новое имя
>>> боб = Ученик("Боб")>>> боб.имя Боб>>> боб.имя = "Алиса">>> боб.имя Алиса>>> боб._имя = "Чарли" # обойти установщик>>> боб._имя # обойти геттерЧарли
Ракетка
В Ракетка, объектная система - это способ организации кода, который дополняет модули и единицы. Как и в остальном языке, объектная система имеет первоклассные значения, а лексическая область видимости используется для управления доступом к объектам и методам.
#lang ракетка(определять ученик% (учебный класс объект% (поле инициализации имя) (define / public (имя) имя) (define / public (Имя набора! новое имя) (набор! имя новое имя)) (супер новый)))(определять s (новый ученик% [имя "Алиса"]))(Отправить s имя) ; => «Алиса»(Отправить s Имя набора! "Боб")(Отправить s имя) ; => «Боб»
Определения структур - это альтернативный способ определения новых типов значений с мутаторами, которые присутствуют, когда это явно требуется:
#lang ракетка(структура ученик (имя) #: изменчивый)(определять s (ученик "Алиса"))(набор-имя-студента! s "Боб")(имя студента s) ; => «Боб»
Рубин
В Рубин могут быть определены индивидуальные методы доступа и мутатора, или конструкции метапрограммирования attr_reader
или же attr_accessor
может использоваться как для объявления частной переменной в классе, так и для предоставления публичного доступа только для чтения или чтения и записи соответственно.
Определение индивидуальных методов доступа и мутатора создает пространство для предварительной обработки или проверки данных.
учебный класс Ученик def имя @имя конец def имя=(ценить) @имя=ценить конецконец
Простой публичный доступ только для чтения к подразумеваемым @имя
Переменная
учебный класс Ученик attr_reader :имяконец
Простой открытый доступ для чтения и записи к подразумеваемым @имя
Переменная
учебный класс Ученик attr_accessor :имяконец
Болтовня
возраст: число "Установите возраст получателя как aNumber, если он больше 0 и меньше 150" (число между: 0 и: 150) если правда: [ возраст := число ]
Быстрый
учебный класс Ученик { частный вар _имя: Нить = "" вар имя: Нить { получать { возвращаться себя._имя } набор { себя._имя = newValue } }}
Visual Basic .NET
Этот пример иллюстрирует идею VB.NET о свойствах, которые используются в классах. Как и в C #, здесь явно используется Получать
и Набор
методы.
Общественные Учебный класс Ученик Частный _имя В качестве Нить Общественные Свойство Имя() Получать Возвращаться _имя Конец Получать Набор(ByVal ценить) _имя = ценить Конец Набор Конец СвойствоКонец Учебный класс
В VB.NET 2010 автоматически реализованные свойства можно использовать для создания свойства без использования синтаксиса Get и Set. Обратите внимание, что скрытая переменная создается компилятором и называется _имя
, чтобы соответствовать Собственности имя
. Использование другой переменной в классе с именем _имя
приведет к ошибке. Привилегированный доступ к базовой переменной доступен из класса.
Общественные Учебный класс Ученик Общественные Свойство имя В качестве НитьКонец Учебный класс
Смотрите также
Рекомендации
- ^ Стивен Фукуа (2009). «Автоматические свойства в C # 3.0». Архивировано из оригинал на 2011-05-13. Получено 2009-10-19.
- ^ Тим Ли (13.07.1998). «Эффективность выполнения функций доступа».
- ^ "CLHS: Macro DEFCLASS". Получено 2011-03-29.
- ^ «CLHS: 7.5.2 Доступ к слотам». Получено 2011-03-29.
- ^ «MOP: определения слотов». Получено 2011-03-29.
- ^ «Функции - язык программирования D». Получено 2013-01-13.
- ^ "Стиль D". Получено 2013-02-01.