Метод мутатора - 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. Обратите внимание, что скрытая переменная создается компилятором и называется _имя, чтобы соответствовать Собственности имя. Использование другой переменной в классе с именем _имя приведет к ошибке. Привилегированный доступ к базовой переменной доступен из класса.

Общественные Учебный класс Ученик    Общественные Свойство имя В качестве НитьКонец Учебный класс

Смотрите также

Рекомендации

  1. ^ Стивен Фукуа (2009). «Автоматические свойства в C # 3.0». Архивировано из оригинал на 2011-05-13. Получено 2009-10-19.
  2. ^ Тим Ли (13.07.1998). «Эффективность выполнения функций доступа».
  3. ^ "CLHS: Macro DEFCLASS". Получено 2011-03-29.
  4. ^ «CLHS: 7.5.2 Доступ к слотам». Получено 2011-03-29.
  5. ^ «MOP: определения слотов». Получено 2011-03-29.
  6. ^ «Функции - язык программирования D». Получено 2013-01-13.
  7. ^ "Стиль D". Получено 2013-02-01.