Метод мутатора

Из Википедии, бесплатной энциклопедии

В информатике метод мутатора это метод , используемый для управления изменениями переменной. Они также широко известны как установки методы . Часто установщик сопровождается геттером , который возвращает значение частной переменной-члена. Они также известны под общим названием аксессоры .

Метод мутатора чаще всего используется в объектно-ориентированном программировании с соблюдением принципа инкапсуляции . В соответствии с этим принципом переменные -члены класса проверяет становятся частными, чтобы скрыть и защитить их от другого кода, и могут быть изменены только с помощью общедоступной функции-члена (метода мутатора), которая принимает желаемое новое значение в качестве параметра и при необходимости его и изменяет закрытую переменную-член . Методы-мутаторы можно сравнить с присваивания перегрузкой оператора , но они обычно появляются на разных уровнях иерархии объектов.

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

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

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

Последствия [ править ]

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

Блок , в котором определен мутатор, предоставляет возможность проверки или предварительной обработки входящих данных. Если весь внешний доступ гарантированно осуществляется через мутатор, то эти шаги невозможно обойти. Например, если дата представлена ​​отдельным приватным year, month и day переменные, то входящие даты можно разделить по setDate мутатор, в то время как для обеспечения согласованности доступ к одним и тем же частным переменным экземпляра осуществляется setYear и setMonth. Во всех случаях значения месяца за пределами 1–12 могут быть отклонены одним и тем же кодом.

Аксессоры, наоборот, позволяют синтезировать полезные представления данных из внутренних переменных, сохраняя при этом их структуру инкапсулированной и скрытой от внешних модулей. Денежный getAmount аксессор может построить строку из числовой переменной с количеством десятичных знаков, определенным скрытым currency параметр.

Современные языки программирования часто предлагают возможность генерировать шаблон для мутаторов и средств доступа в одной строке, как, например, в C#. public string Name { get; set; } и Руби attr_accessor :name. В этих случаях блоки кода для проверки, предварительной обработки или синтеза не создаются. Эти упрощенные средства доступа по-прежнему сохраняют преимущество инкапсуляции перед простыми общедоступными переменными экземпляра, но обычно по мере развития системы программное обеспечение поддерживается , а требования изменяются, а требования к данным становятся более сложными. Многие автоматические мутаторы и средства доступа со временем заменяются отдельными блоками кода. Преимущество автоматического создания их на первых этапах реализации заключается в том, что общедоступный интерфейс класса остается идентичным независимо от того, добавляется ли он большей сложности, и не требует обширного рефакторинга, если таковой имеется. [1]

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

Функции доступа могут быть менее эффективными, чем прямая выборка или сохранение полей данных, из-за дополнительных шагов, [2] однако такие функции часто являются встроенными , что устраняет накладные расходы на вызов функции.

Примеры [ править ]

Сборка [ править ]

 студента                    структура 
     , возраст           дд          ? 
  студент                     заканчивает 
                     .code 
 Student_get_age         объект        процедуры  :  DWORD 
                       mov         ebx  ,   object 
                       mov         eax  ,   Student.age  [  ebx  ] 
                       ret 
 Student_get_age         endp 

 Student_set_age         объект        процедуры  :  DWORD  ,   age  :  DWORD 
                       mov         ebx  ,   object 
                       mov         eax  ,   age 
                       mov         Student.age  [  ebx  ],   eax 
                       ret 
 Student_set_age         конечная точка 

С [ править ]

В файле Student.h:

#ifndef _STUDENT_H 
 #define _STUDENT_H 

 struct   Student  ;    /* непрозрачная структура */ 
 typedef   struct   Student   Student  ; 

  студент   *  Student_new  (  int   age  ,   char   *  name  ); 
  void   Student_delete  (  студент   *  s  ); 

  void   Student_set_age  (  студент   *  s  ,   int   age  ); 
  int   Student_get_age  (  студент   *  s  ); 
  char   *  Student_get_name  (  студент   *  s  ); 

  #endif 

В файле Student.c:

#include   <stdlib.h> 
 #include   <string.h> 
 #include   "student.h" 

 struct   Student   { 
   int   age  ; 
   символа    название  ; 
  }; 

  студент   *  Student_new  (  int   age  ,   char   *  name  )   { 
   Student   *  s   =   Malloc  (  sizeof  (  студент  )); 
    s  ->  name   =   strdup  (  имя  ); 
    с  ->  возраст   =   возраст  ; 
    вернуть   с  ; 
  } 

 void   Student_delete  (  студент   *  s  )   { 
   свободно  (  s  ->  имя  ); 
    бесплатно  (  ы  ); 
  } 

 void   Student_set_age  (  student   *  s  ,   int   age  )   { 
   s  ->  age   =   age  ; 
  } 

 int   Student_get_age  (  студент   *  s  )   { 
   return   s  ->  age  ; 
  } 

 char   *  Student_get_name  (  student   *  s  )   { 
   return   s  ->  name  ; 
  } 

В файле main.c:

#include   <stdio.h> 
 #include   "student.h" 

 int   main  (  void  )   { 
   Student   *  s   =   Student_new  (  19  ,   "Maurice"  ); 
    char   *  name   =   Student_get_name  (  s  ); 
    int   old_age   =   Student_get_age  (  s  ); 
    printf  (  "Старость %s = %i  \n  "  ,   name  ,   old_age  ); 
    Student_set_age  (  s  ,   21  ); 
    int   new_age   =   Student_get_age  (  s  ); 
    printf  (  "Новый возраст %s = %i  \n  "  ,   name  ,   new_age  ); 
    студент_удалить  (  ы  ); 
    вернуть   0  ; 
  } 

В файле Makefile:

все  вон   .   текст  ;   кот  $< 
  out.txt  :   основной  ;   ./$< > $@ 
  главное  :   главное  .   о   студент  .   o 
 main.o Student.o  :   студент  .   ч 
 чистый  :   ;   $(  РМ  )  *.   о   вон  .   текстовый   основной 

С++ [ править ]

В файле Student.h:

#ifndef STUDENT_H 
 #define STUDENT_H 

 #include   <string> 

 class   Student   { 
 public  : 
     Student  (  const   std  ::  string  &   name  ); 

      const   std  ::  строка  и   имя  ()   const  ; 
      void   name  (  const   std  ::  string  &   name  ); 

  частный  : 
     std  ::  строка   name_  ; 
  }; 

  #endif 

В файле Student.cpp:

#include   "Student.h" 

 Student  ::  Student  (  const   std  ::  string  &   name  )   :   name_  (  name  )   { 
 } 

 const   std  ::  string  &   Student  ::  name  ()   const   { 
     return   name_  ; 
  } 

 void   Student  ::  name  (  const   std  ::  string  &   name  )   { 
     name_   =   name  ; 
  } 

С# [ править ]

Этот пример иллюстрирует идею C# о свойствах , которые представляют собой особый тип члена класса . В отличие от Java, явные методы не определены; общедоступное «свойство» содержит логику для обработки действий. Обратите внимание на использование встроенной (необъявленной) переменной. value.

публичный   класс   Student 
 { 
     частной   строки   имя  ; 

      /// <summary> 
     /// Получает или задает имя студента 
     /// </summary> 
     public   string   Name 
     { 
         get   {   return   name  ;    } 
         Установить   {   имя   =   значение  ;    } 
     } 
 } 

В более поздних версиях C# (.NET Framework 3.5 и выше) этот пример можно сократить следующим образом, без объявления частной переменной name.

публичный   класс   Student 
 { 
     public   string   Name   {   get  ;    набор  ;    } 
 } 

Использование сокращенного синтаксиса означает, что базовая переменная больше не доступна внутри класса. В результате setчасть имущества должна быть передана в распоряжение. Доступ можно ограничить с помощью set-специфичный модификатор доступа.

публичный   класс   Student 
 { 
     public   string   Name   {   get  ;    частный   набор  ;    } 
 } 

Общий Лисп [ править ]

В Common Lisp Object System спецификации слотов в определениях классов могут указывать любой из :reader, :writer и :accessor варианты (даже несколько раз) для определения методов чтения, методов установки и методов доступа (метод чтения и соответствующий setf метод). [3] Слоты всегда доступны напрямую через их имена с использованием with-slots и slot-value, а параметры доступа к слоту определяют специализированные методы, использующие slot-value. [4]

Сам CLOS не имеет понятия свойств, хотя расширение протокола MetaObject определяет средства доступа к именам функций чтения и записи слота, включая те, которые генерируются с помощью :accessor вариант. [5]

В следующем примере показано определение класса учащихся с использованием этих параметров слотов и прямого доступа к слотам:

(  defclass   Student   () 
   ((  name        :initarg   :name        :initform   ""   :accessor   имя-ученика  )   ; имя-ученика можно установить 
    (  дата рождения   :initarg   :дата рождения   :initform   0    :reader   дата-рождения студента  ) 
    (  номер      :initarg   : число      :initform   0    :читатель   -номер-студента   :писатель   set-номер-студента  ))) 

 ;;   Пример метода получения вычисляемого свойства (это просто метод) 
 (  defmethod   Student-age   ((  self   Student  )) 
   (  -   (  get-universal-time  )   (  Student-birthdate   self  ))) 

 ;;   Пример прямого доступа к слотам в вычисляемом установщике свойств 
 (  defmethod   (  setf   Student-age  )   (  new-age   (  self   Student  )) 
   (  with-slots   (  birthdate  )   self 
     (  setfbirthdate   get   (  -   (  -universal-time  )   new-age  )) 
     нью-эйдж  )) 

 ;;   Параметры доступа к слотам генерируют методы, что позволяет определять дальнейшие методы 
 (  defmethod   set-student-number   :before   (  new-number   (  self   Student  )) 
   ;; Вы также можете проверить, существует ли уже студент с новым номером. 
   (  check- введите   новое число   (  целое число   1   *  ))) 

Д [ править ]

D поддерживает синтаксис функций получения и установки. В версии 2 языка методы получения и установки класса/структуры должны иметь @property атрибут. [6] [7]

класс   Student   { 
     private   char  []   name_  ; 
      // Получатель 
     @property   char  []   name  ()   { 
         return   this  .   имя_  ; 
      } 
     // Setter 
     @property   char  []   name  (  char  []   name_in  )   { 
         return   this  .   имя_   =   имя_в  ; 
      } 
 } 

А Student экземпляр можно использовать следующим образом:

автоматический   студент   =   новый   студент  ; 
  студент  .   имя   =   «Дэвид»  ;              // тот же эффект, что и Student.name("David") 
 auto   Student_name   =   Student  .   имя  ;    // тот же эффект, что и Student.name() 

Делфи [ править ]

Это простой класс на языке Delphi, который иллюстрирует концепцию открытого свойства для доступа к частному полю.

 интерфейса 

тип 
   TStudent   =   класс 
   strict   Private 
     FName  :   строка  ; 
      процедура   SetName  (  const   Value  :   string  )  ; 
    public 
     /// <summary> 
     /// Получаем или устанавливаем имя студента. 
      /// </summary> 
     свойства   имя  :   строки   чтение   FName   запись   SetName  ; 
    конец  ; 

  // ... 

 реализации 

 процедура   TStudent  .   SetName  (  константное   значение  :   строка  )  ; 
  начать 
   FName   :=   Значение  ; 
  конец  ; 

  конец  . 

Ява [ править ]

В этом примере простого класса , представляющего студента, в котором сохранено только имя, можно видеть, что переменной имя является частным, то есть видимым только из класса Student, а «установщик» и «получатель» являются общедоступными, а именно « getName()" и " setName(name)"методы.

публичный   класс   Student   { 
     частное   строки   имя  ; 

      public   String   getName  ()   { 
         возвращаемое   имя  ; 
      } 
    
     Public   void   setName  (  String   newName  )   { 
         name   =   newName  ; 
      } 
 } 

JavaScript [ править ]

В этом примере функция-конструктор Student используется для создания объектов, представляющих учащегося, сохраняя только имя.

функция   Студент  (  имя  )   { 
   var   _name   =   имя  ; 

    этот  .   getName   =   функция  ()   { 
     return   _name  ; 
    }; 

    этот  .   setName   =   функция  (  значение  )   { 
     _name   =   значение  ; 
    }; 
  } 

Или (используя устаревший способ определения средств доступа в веб-браузерах): [8]

функция   Студент  (  имя  ) { 
     var   _name   =   имя  ; 
   
      этот  .   __defineGetter__  (  'name'  ,   function  ()   { 
         return   _name  ; 
     }); 
   
      этот  .   __defineSetter__  (  'имя'  ,   функция  (  значение  )   { 
         _name   =   значение  ; 
     }); 
  } 

Или (используя прототипы для наследования и синтаксис средств доступа ES6 ):

функция   Студент  (  имя  ) { 
     это  .   _имя   =   имя  ; 
  } 

 Студент  .   прототип   =   { 
     получить   имя  ()   { 
         вернуть   это  .   _имя  ; 
      }, 
     установите   имя  (  значение  )   { 
         this  .   _имя   =   значение  ; 
      } 
 }; 

Или (без использования прототипов):

var   Student   =   { 
     получить   имя  ()   { 
         вернуть   это  .   _имя  ; 
      }, 
     установите   имя  (  значение  )   { 
         this  .   _имя   =   значение  ; 
      } 
 }; 

Или (используя defineProperty):

функция   Студент  (  имя  ) { 
     это  .   _имя   =   имя  ; 
  } 
 Объект  .   defineProperty  (  Student.prototype  .  ,  set   'name'  ,   { 
     get  :   function  ()   { 
         return   this  _name  ;  ; 
     }, 
     :  function   (  value  )  {   this 
         .  _name  =   value   ;  } 
     } 
 ) 

ActionScript 3.0 [ править ]

пакет 
 { 
     общественный   класс   Student 
     { 
         частное   var   _name   :   String  ; 
		
          публичная   функция   get   name  ()   :   String 
         {  
             return   _name  ; 
          } 

         общедоступных   функций   набора   Имя  (  значение   :   String  )   :   void 
         { 
             _name   =   value  ; 
          } 
     } 
 } 

Objective-C [ править ]

Использование традиционного синтаксиса Objective-C 1.0 с ручным подсчетом ссылок, как в GNUstep в Ubuntu 12.04 :

@interface   Student  :  NSObject 
 { 
     NSString   *  _name  ; 
  } 

 -   (  NSString   *  )  имя  ; 
  -   (  void  )  setName:  (  NSString   *  )  name  ; 

  @end 

 @implementation   Student 

 -   (  NSString   *  )  name 
 { 
     return   _name  ; 
  } 

 -   (  void  )  setName:  (  NSString   *  )  name 
 { 
     [  _name   Release  ]; 
      _name   =   [  имя   сохраняется  ]; 
  } 

 @конец 

Используя новый синтаксис Objective-C 2.0, используемый в Mac OS X 10.6 , iOS 4 и Xcode 3.2, генерируем тот же код, что описано выше:

@interface   Student  :  NSObject 

 @property   (  неатомарный  ,   сохранить  )   NSString   *  name  ; 

  @end 

 @implementation   Студент 

 @synthesize   name   =   _name  ; 

  @конец 

А начиная с OS X 10.8 и iOS 6 , при использовании Xcode 4.4 и выше синтаксис можно даже упростить:

@interface   Student  :  NSObject 

 @property   (  неатомарный  ,   сильный  )   NSString   *  name  ; 

  @end 

 @implementation   Студент 

 //Здесь ничего не происходит, и все в порядке. 

  @конец 

Перл [ править ]

пакет   «Студент»  ; 

  суб   новый   { 
     благослови   {},   сдвиг  ; 
  } 

 Sub   set_name   { 
     мой   $self   =   сдвиг  ; 
      $self  ->  {  имя  }   =   $_  [  0  ]; 
  } 

 Sub   get_name   { 
     my   $self   =   сдвиг  ; 
      вернуть   $self  ->  {  имя  }; 
  } 

 1  ; 

Или, используя Class::Accessor

пакет   «Студент»  ; 
  используйте   базу   qw(Class::Accessor)  ; 
  __PACKAGE__  ->  Follow_best_practice  ; 

  Студент  ->  mk_accessors  (  qw(имя)  ); 

  1  ; 

Или, используя объектную систему Moose :

пакет   «Студент»  ; 
  используйте   Муса  ; 

  # Moose использует имя атрибута в качестве установщика и получателя, свойства чтения и записи 
 # позволяют нам переопределить это и предоставить наши собственные имена, в этом случае get_name и set_name 
 имеют   'name'   =>   (  is   =>   'rw'  ,   isa   =>   'Str'  ,   читатель   =>   'get_name'  ,   писатель   =>   'set_name'  ); 

  1  ; 

PHP [ править ]

PHP определяет «волшебные методы» __getи __set для свойств объектов. [9]

В этом примере простого класса , представляющего студента, в котором сохранено только имя, можно видеть, что переменной имя является частным, то есть видимым только из класса Student, а «установщик» и «получатель» являются общедоступными, а именно getName() и setName('name') методы.

класс   Student 
 { 
     частная   строка   $name  ; 

      /** 
 * @return string Имя. 
  */ 
     public   function   getName  ()  :   string 
     { 
         return   $this  ->  name  ; 
      } 

     /** 
 * @param string $newName Имя, которое нужно установить. 
  */ 
     публичная   функция   setName  (  строка   $newName  )  :   void 
     { 
         $this  ->  name   =   $newName  ; 
      } 
 } 

Питон [ править ]

В этом примере используется класс Python с одной переменной, геттером и сеттером.

class   Student  : 
     # Инициализатор 
     def   __init__  (  self  ,   name  :   str  )   ->   None  : 
         # Переменная экземпляра для хранения имени ученика 
         self  .   _name   =   name 

     # Метод получения 
     @property 
     def   name  (  self  ): 
         return   self  .   _name 

     # Метод установки 
     @name  .  сеттера 
     определения    имя  (  self  ,   new_name  ): 
         self  .   _имя   =   новое_имя 
>>>  боб   =   Студент  (  «Боб»  ) 
 >>>  боб  .   имя  
 Боб 
 >>>  Боб  .   name   =   "Алиса" 
 >>>  Боб  .   имя  
 Алиса 
 >>>  Боб  .   _name   =   "Чарли"   # обойти установщик 
 >>>  bob  .   _name   # обойти геттер 
 Чарли 

Ракетка [ править ]

В Racket объектная система — это способ организации кода, который поставляется в дополнение к модулям и модулям. Как и в остальной части языка, объектная система имеет первоклассные значения, а лексическая область видимости используется для управления доступом к объектам и методам.

#lang  Racket 
 (  define   Student% 
   (  class   object% 
     (  init-поля   имя  ) 
     (  define/public   (  get-name  )   name  ) 
     (  define/public   (  set-name!   new-name  )   (  set!   name   new-name  )) 
     (  супер-новый  ))) 

 (  define   s   (  new   Student%   [  имя   "Алиса"  ])) 
 (  отправить   s   get-name  )                         ;   => "Алиса" 
 (  отправить   set   -name!   "Bob"  ) 
 (  отправить   get   -name  )                         ;   => "Боб" 

Определения структур — это альтернативный способ определения новых типов значений, при этом мутаторы присутствуют, когда это явно требуется:

#lang  Racket 
 (  struct   Student   (  name  )   #:mutable  ) 
 (  define   s   (  Student   "Alice"  )) 
 (  set-student-name!   s   "Bob"  ) 
 (  student-name   s  )                          ;   => "Боб" 

Руби [ править ]

В Ruby могут быть определены отдельные методы доступа и мутаторы или конструкции метапрограммирования. attr_reader или attr_accessor может использоваться как для объявления частной переменной в классе, так и для предоставления к ней публичного доступа только для чтения или для чтения и записи соответственно.

Определение отдельных методов доступа и мутаторов создает пространство для предварительной обработки или проверки данных.

класс   Student 
   def   name 
     @name 
   end 

   def   name=  (  значение  ) 
     @name  =  value 
   end 
 end 

Простой публичный доступ только для чтения к подразумеваемым @name переменная

класс   Student 
   attr_reader   : 
 конец имени 

Простой публичный доступ для чтения и записи к подразумеваемым @name переменная

класс   Student 
   attr_accessor   : 
 конец имени 

Ржавчина [ править ]

struct   Student   { 
     name  :  String  , 
 } 

 impl   Student   { 
     fn   name  (  &  self  )   ->  &  String   { 
         &  self  .   name 
     } 

     fn   name_mut  (  &  mut   self  )   ->  &  mut   String   { 
         &  mut   self  .   имя 
     } 
 } 

Смолток [ править ]

  age:   aNumber 
      "Установить возраст получателя как aNumber, если он больше 0 и меньше 150 " 
      (  Число   между:   0   и:   150  ) 
         ifTrue:  [  возраст   :=   число  ] 
 

Свифт [ править ]

class   Student   { 
     частное   var   _name  :   String   =   "" 

     var   name  :   String   { 
         get   { 
             return   self  .   _name 
         } 
         set   { 
             self  .   _name   =   новоезначение 
         } 
     } 
 } 

Visual Basic .NET [ править ]

Этот пример иллюстрирует идею VB.NET о свойствах, которые используются в классах. Как и в C#, здесь явно используется Get и Set методы.

Открытый   класс   Student 

     Частное   _name   As   String 

     открытого   свойства   Имя  () 
         Get 
             Return   _name 
         End   Get 
         Set  (  ByVal   значение  ) 
             _name   =   значение 
         End   Set 
     End   Property 

 End   Class 

В VB.NET 2010 автоматически реализуемые свойства можно использовать для создания свойства без использования синтаксиса Get и Set. Обратите внимание, что компилятор создает скрытую переменную, называемую _name, чтобы соответствовать собственности name. Использование другой переменной внутри класса с именем _nameприведет к ошибке. Привилегированный доступ к базовой переменной доступен изнутри класса.

Публичный   класс   Student 
     публичного   свойства   Имя   как   строки 
 конца   класс 

См. также [ править ]

Ссылки [ править ]

  1. ^ Стивен Фукуа (2009). «Автоматические свойства в C# 3.0» . Архивировано из оригинала 13 мая 2011 г. Проверено 19 октября 2009 г.
  2. ^ Тим Ли (13 июля 1998 г.). «Эффективность выполнения функций доступа» .
  3. ^ «CLHS: Макрос ДЕФКЛАСС» . Проверено 29 марта 2011 г.
  4. ^ «CLHS: 7.5.2 Доступ к слотам» . Проверено 29 марта 2011 г.
  5. ^ «MOP: Определения слотов» . Проверено 29 марта 2011 г.
  6. ^ «Функции — язык программирования D» . Проверено 13 января 2013 г.
  7. ^ «Стиль Д» . Проверено 1 февраля 2013 г.
  8. ^ «Object.prototype.__defineGetter__() — JavaScript | MDN» . http://developer.mozilla.org . Проверено 6 июля 2021 г.
  9. ^ «PHP: Перегрузка — Руководство» . www.php.net . Проверено 6 июля 2021 г.