stringtranslate.com

Método mutador

En informática , un método mutador es un método utilizado para controlar los cambios en una variable. También se conocen ampliamente como métodos setter . A menudo, un setter va acompañado de un getter , que devuelve el valor de la variable miembro privada. También se conocen colectivamente como métodos de acceso .

El método mutador se utiliza con mayor frecuencia en la programación orientada a objetos , de acuerdo con el principio de encapsulación . Según este principio, las variables miembro de una clase se hacen privadas para ocultarlas y protegerlas de otro código, y solo pueden ser modificadas por una función miembro pública (el método mutador), que toma el nuevo valor deseado como parámetro, lo valida opcionalmente y modifica la variable miembro privada . Los métodos mutadores se pueden comparar con la sobrecarga del operador de asignación , pero normalmente aparecen en diferentes niveles de la jerarquía de objetos.

Los métodos mutadores también se pueden utilizar en entornos no orientados a objetos. En este caso, se pasa al mutador una referencia a la variable que se va a modificar, junto con el nuevo valor. En este escenario, el compilador no puede impedir que el código omita el método mutador y cambie la variable directamente. Los desarrolladores son responsables de garantizar que la variable solo se modifique a través del método mutador y no directamente.

En los lenguajes de programación que los admiten, las propiedades ofrecen una alternativa conveniente sin renunciar a la utilidad de la encapsulación.

En los ejemplos siguientes, un método mutador completamente implementado también puede validar los datos de entrada o realizar otras acciones, como activar un evento .

Trascendencia

La alternativa a definir métodos de acceso y mutadores, o bloques de propiedades , es dar a la variable de instancia alguna visibilidad que no sea privada y acceder a ella directamente desde fuera de los objetos. Se puede definir un control mucho más preciso de los derechos de acceso utilizando mutadores y descriptores de acceso. Por ejemplo, un parámetro puede convertirse en de solo lectura simplemente definiendo un descriptor de acceso pero no un mutador. La visibilidad de los dos métodos puede ser diferente; a menudo es útil que el descriptor de acceso sea público mientras que el mutador permanece protegido, privado del paquete o interno.

El bloque donde se define el mutador brinda una oportunidad para la validación o el preprocesamiento de los datos entrantes. Si se garantiza que todo el acceso externo se realizará a través del mutador, estos pasos no se pueden omitir. Por ejemplo, si una fecha está representada por variables privadas y separadas year, monthentonces dayel mutador puede dividir las fechas entrantes mientras que, para mantener la coherencia, y setDateacceden a las mismas variables de instancia privadas . En todos los casos, los valores de mes que no estén entre 1 y 12 pueden ser rechazados por el mismo código.setYearsetMonth

Los descriptores de acceso, por el contrario, permiten la síntesis de representaciones de datos útiles a partir de variables internas, manteniendo su estructura encapsulada y oculta a los módulos externos. Un getAmountdescriptor de acceso monetario puede construir una cadena a partir de una variable numérica con la cantidad de decimales definida por un currencyparámetro oculto.

Los lenguajes de programación modernos suelen ofrecer la posibilidad de generar el código fuente de los mutadores y los descriptores de acceso en una sola línea, como por ejemplo C# public string Name { get; set; }y Ruby attr_accessor :name. En estos casos, no se crean bloques de código para la validación, el preprocesamiento o la síntesis. Estos descriptores de acceso simplificados aún conservan la ventaja de la encapsulación sobre las variables de instancia públicas simples, pero es común que, a medida que avanzan los diseños de sistemas , se mantiene el software y cambian los requisitos, las demandas sobre los datos se vuelvan más sofisticadas. Muchos mutadores y descriptores de acceso automáticos eventualmente son reemplazados por bloques de código separados. El beneficio de crearlos automáticamente en los primeros días de la implementación es que la interfaz pública de la clase permanece idéntica independientemente de si se agrega o no mayor sofisticación, sin requerir una refactorización extensa si se agrega. [1]

La manipulación de parámetros que tienen mutadores y descriptores de acceso desde dentro de la clase donde están definidos a menudo requiere un poco de reflexión adicional. En las primeras etapas de una implementación, cuando hay poco o ningún código adicional en estos bloques, no importa si se accede directamente a la variable de instancia privada o no. A medida que se agregan validaciones, validaciones cruzadas , verificaciones de integridad de datos , preprocesamiento u otra sofisticación, pueden aparecer errores sutiles en los que algún acceso interno hace uso del código más nuevo mientras que en otros lugares se lo omite.

Las funciones de acceso pueden ser menos eficientes que obtener o almacenar directamente los campos de datos debido a los pasos adicionales involucrados, [2] sin embargo, dichas funciones a menudo están en línea, lo que elimina la sobrecarga de una llamada de función.

Ejemplos

Asamblea

¿La estructura del estudiante tiene edad dd ? El estudiante termina     
 .código estudiante_obtener_edad proc objeto : DWORD mov ebx , objeto mov eax , estudiante.edad [ ebx ] ret estudiante_obtener_edad endp          estudiante_establecer_edad proc objeto : DWORD , edad : DWORD mov ebx , objeto mov eax , edad mov estudiante.edad [ ebx ], eax ret estudiante_establecer_edad endp              

do

En el archivo student.h:

#ifndef _ESTUDIANTE_H #define _ESTUDIANTE_Hstruct student ; /* estructura opaca */ typedef struct student student ;     estudiante * estudiante_nuevo ( int edad , char * nombre ); void estudiante_eliminar ( estudiante * s );      void estudiante_establecer_edad ( estudiante * s , int edad ); int estudiante_obtener_edad ( estudiante * s ); char * estudiante_obtener_nombre ( estudiante * s );        #finsi

En el archivo student.c:

#include <stdlib.h> #include <string.h> #include "estudiante.h"   struct estudiante { int edad ; char * nombre ; };      estudiante * estudiante_nuevo ( int edad , char * nombre ) { estudiante * s = malloc ( sizeof ( estudiante )); s -> nombre = strdup ( nombre ); s -> edad = edad ; return s ; }                 void student_delete ( estudiante * s ) { free ( s -> nombre ); free ( s ); }     void estudiante_conjunto_edad ( estudiante * s , int edad ) { s -> edad = edad ; }        int student_get_age ( student * s ) { return s -> edad ; }     char * estudiante_obtener_nombre ( estudiante * s ) { return s -> nombre ; }     

En el archivo main.c:

#include <stdio.h> #include "estudiante.h"  int main ( void ) { estudiante * s = estudiante_nuevo ( 19 , "Mauricio" ); char * nombre = estudiante_obtener_nombre ( s ); int edad_vieja = estudiante_obtener_edad ( s ); printf ( "edad vieja de %s = %i \n " , nombre , edad_vieja ); estudiante_establecer_edad ( s , 21 ); int edad_nueva = estudiante_obtener_edad ( s ); printf ( "edad nueva de %s = %i \n " , nombre , edad_nueva ); estudiante_eliminar ( s ); return 0 ; }                              

En el archivo Makefile:

all : out . txt ; cat $< out.txt : principal ; ./$< > $@ principal : principal . o estudiante . o principal.o estudiante.o : estudiante . h clean : ; $( RM ) *. o out . txt principal        

C++

En el archivo Student.h:

#ifndef ESTUDIANTE_H #define ESTUDIANTE_H#include <cadena> clase Estudiante { público : Estudiante ( const std :: string & nombre );      const std :: string & nombre () const ; void nombre ( const std :: string & nombre );       privado : std :: cadena nombre_ ; };  #finsi

En el archivo Student.cpp:

#include "Estudiante.h" Estudiante :: Estudiante ( const std :: string & nombre ) : nombre_ ( nombre ) { }     const std :: string & Estudiante :: nombre () const { return nombre_ ; }      void Estudiante :: nombre ( const std :: string & nombre ) { nombre_ = nombre ; }       

DO#

Este ejemplo ilustra la idea de C# de las propiedades , que son un tipo especial de miembro de clase . A diferencia de Java, no se definen métodos explícitos; una "propiedad" pública contiene la lógica para manejar las acciones. Observe el uso de la variable incorporada (no declarada) value.

clase pública Estudiante { cadena privada nombre ;      /// <summary> /// Obtiene o establece el nombre del estudiante /// </summary> public string Name { get { return name ; } set { name = value ; } } }                  

En versiones posteriores de C# (.NET Framework 3.5 y superiores), este ejemplo se puede abreviar de la siguiente manera, sin declarar la variable privada name.

clase pública Estudiante { cadena pública Nombre { obtener ; establecer ; } }         

El uso de la sintaxis abreviada significa que la variable subyacente ya no está disponible desde dentro de la clase. Como resultado, la setparte de la propiedad debe estar presente para la asignación. El acceso se puede restringir con un setmodificador de acceso específico.

clase pública Estudiante { cadena pública Nombre { obtener ; conjunto privado ; } }          

Ceceo común

En Common Lisp Object System , las especificaciones de ranuras dentro de las definiciones de clase pueden especificar cualquiera de las :readeropciones :writery :accessor(incluso varias veces) para definir métodos de lectura, métodos de establecimiento y métodos de acceso (un método de lectura y el setfmétodo respectivo). [3] Las ranuras siempre son directamente accesibles a través de sus nombres con el uso de with-slotsy slot-value, y las opciones de acceso de ranura definen métodos especializados que usan slot-value. [4]

CLOS en sí no tiene noción de propiedades, aunque la extensión del Protocolo MetaObject especifica medios para acceder a los nombres de funciones de lectura y escritura de una ranura, incluidos los generados con la :accessoropción. [5]

El siguiente ejemplo muestra una definición de una clase de estudiante utilizando estas opciones de espacio y acceso directo al espacio:

( defclass student () (( nombre :initarg :name :initform "" :accessor nombre-estudiante ) ; nombre-estudiante se puede configurar ( fecha-nacimiento :initarg :birthdate :initform 0 :reader fecha-nacimiento-estudiante ) ( número :initarg :number :initform 0 :reader número-estudiante :writer número-estudiante establecido )))                          ;; Ejemplo de un captador de propiedad calculado (este es simplemente un método) ( defmethod student-age (( self student )) ( - ( get-universal-time ) ( student-birthdate self )))       ;; Ejemplo de acceso directo a una ranura dentro de un establecedor de propiedades calculado ( defmethod ( setf student-age ) ( new-age ( self student )) ( with-slots ( birthdate ) self ( setf birthdate ( - ( get-universal-time ) new-age )) new-age ))              ;; Las opciones de acceso a la ranura generan métodos, lo que permite más definiciones de métodos ( defmethod set-student-number :before ( new-number ( self student )) ;; También puede verificar si ya existe un estudiante con el nuevo número. ( check-type new-number ( entire 1 * )))           

D

D admite una sintaxis de función de obtención y definición. En la versión 2 del lenguaje, los métodos de clase/estructura de obtención y definición deben tener el @propertyatributo . [6] [7]

clase Estudiante { char privado [] nombre_ ; // Getter @property char [] nombre () { devuelve este . nombre_ ; } // Setter @property char [] nombre ( char [] nombre_in ) { devuelve este . nombre_ = nombre_in ; } }                        

Una Studentinstancia se puede utilizar de la siguiente manera:

auto estudiante = new Estudiante ; estudiante . nombre = "David" ; // mismo efecto que estudiante. nombre("David") auto estudiante_nombre = estudiante . nombre ; // mismo efecto que estudiante. nombre()           

Delfos

Esta es una clase simple en lenguaje Delphi que ilustra el concepto de propiedad pública para acceder a un campo privado.

interfaztipo TStudent = clase estricta privada FName : cadena ; procedimiento SetName ( const Valor : cadena ) ; público /// <summary> /// Obtener o establecer el nombre del estudiante. /// </summary> propiedad Nombre : cadena leer FName escribir SetName ; fin ;                       // ...implementaciónprocedimiento TStudent .SetName ( const Value : string ) ; inicio FName : = Value ; fin ;      fin .

Java

En este ejemplo de una clase simple que representa a un estudiante con solo el nombre almacenado, se puede ver que la variable nombre es privada, es decir, solo visible desde la clase Estudiante, y el "setter" y el "getter" son públicos, es decir, los métodos " getName()" y " setName(name)".

clase pública Estudiante { cadena privada nombre ;       public String getName () { return nombre ; } public void setName ( String nuevoNombre ) { nombre = nuevoNombre ; } }                

JavaScript

En este ejemplo, se utiliza la función constructora Studentpara crear objetos que representan a un estudiante con solo el nombre almacenado.

función Estudiante ( nombre ) { var _nombre = nombre ;       esto .getName = función ( ) { return _name ; };       este .setName = función ( valor ) { _name = valor ; } ; }       

O (utilizando una forma obsoleta de definir accesores en navegadores web): [8]

función Estudiante ( nombre ){ var _nombre = nombre ; this .__ defineGetter__ ( 'nombre' , función () { return _nombre ; }); this .__ defineSetter__ ( 'nombre' , función ( valor ) { _nombre = valor ; }); }                    

O (usando prototipos para herencia y sintaxis de acceso ES6 ):

función Estudiante ( nombre ){ this . _nombre = nombre ; }    Estudiante . prototipo = { obtener nombre () { devolver este . _nombre ; }, establecer nombre ( valor ) { este . _nombre = valor ; } };               

O (sin utilizar prototipos):

var Estudiante = { obtener nombre () { devolver este . _nombre ; }, establecer nombre ( valor ) { este . _nombre = valor ; } };                

O (usando defineProperty):

función Estudiante ( nombre ){ this . _nombre = nombre ; } Objeto . defineProperty ( Estudiante . prototipo , 'nombre' , { obtener : función () { devolver this . _nombre ; }, establecer : función ( valor ) { this . _nombre = valor ; } });                   

ActionScript 3.0

paquete { clase pública Estudiante { var privada _nombre : String ; función pública obtener nombre () : String { return _nombre ; }                     función pública conjunto nombre ( valor : String ) : void { _name = valor ; } } }             

Objetivo-C

Utilizando la sintaxis tradicional de Objective-C 1.0, con referencia manual contando como la que funciona en GNUstep en Ubuntu 12.04 :

@interface  Estudiante  : NSObject { NSString * _name ; }  -  ( NSString * ) nombre ; - ( void ) setName: ( NSString * ) nombre ;   @fin @Estudiante de implementación-  ( NSString * ) nombre { return _nombre ; }   -  ( void ) setName: ( NSString * ) nombre { [ _nombre liberación ]; _nombre = [ nombre retención ]; }       @fin

Utilizando la sintaxis más reciente de Objective-C 2.0 utilizada en Mac OS X 10.6 , iOS 4 y Xcode 3.2, generando el mismo código que se describe arriba:

@interface  Estudiante  : NSObject@property ( no atómico , retener ) NSString * nombre ;    @fin @Estudiante de implementación@synthesize nombre = _nombre ;   @fin

Y a partir de OS X 10.8 y iOS 6 , al utilizar Xcode 4.4 y versiones posteriores, la sintaxis se puede simplificar aún más:

@interface  Estudiante  : NSObject@property ( no atómico , fuerte ) NSString * nombre ;    @fin @Estudiante de implementación//Aquí no pasa nada y está bien.@fin

Perl

paquete Estudiante ; sub nuevo { bendecir {}, shift ; }     sub set_name { mi $self = shift ; $self -> { nombre } = $_ [ 0 ]; }         sub get_name { my $self = shift ; return $self -> { nombre }; }        1 ;

O bien, utilizando Class::Accessor

paquete Estudiante ; usar base qw(Class::Accessor) ; __PAQUETE__ -> seguir_las_mejores_prácticas ;   Estudiante -> mk_accessors ( qw(nombre) );1 ;

O bien, utilizando el sistema de objetos Moose :

paquete Estudiante ; utilizar Moose ;  # Moose usa el nombre del atributo como el definidor y el captador, las propiedades del lector y del escritor # nos permiten anular eso y proporcionar nuestros propios nombres, en este caso get_name y set_name tienen 'name' => ( is => 'rw' , isa => 'Str' , reader => 'get_name' , writer => 'set_name' );              1 ;

PHP

PHP define los "métodos mágicos" __gety __setlas propiedades de los objetos. [9]

En este ejemplo de una clase simple que representa a un estudiante con solo el nombre almacenado, se puede ver que la variable nombre es privada, es decir, solo visible desde la clase Estudiante, y el "setter" y "getter" son públicos, es decir, los métodos getName()y setName('name').

clase  Estudiante {  cadena privada  $nombre ;  /**  * @return string El nombre.  */  public  function  getName () :  string  {  return  $this -> nombre ;  } /**  * @param string $newName El nombre a establecer.  */  public  function  setName ( string  $newName ) :  void  {  $this -> name  =  $newName ;  } }

Pitón

Este ejemplo utiliza una clase Python con una variable, un captador y un definidor.

clase  Estudiante :  # Inicializador  def  __init__ ( self ,  name :  str )  ->  None : # Una variable  de instancia para almacenar el nombre del  estudiante self._name = name   # Método getter  @property  def  name ( self ):  return  self . _name # Método Setter  @name . setter  def  name ( self ,  new_name ):  self . _name  =  new_name
>>> bob  =  Student ( "Bob" ) >>> bob.name Bob >>> bob.name = " Alice " >>> bob.name  Alice >>> bob._name = " Charlie " # omite el setter >>> bob._name # omite el getter Charlie       

Raqueta

En Racket , el sistema de objetos es una forma de organizar el código que viene además de los módulos y las unidades. Como en el resto del lenguaje, el sistema de objetos tiene valores de primera clase y el alcance léxico se utiliza para controlar el acceso a los objetos y métodos.

#lang racket ( define student% ( class object% ( init-field name ) ( define/public ( get-name ) name ) ( define/public ( set-name! new-name ) ( set! name new-name )) ( super-new )))               ( define s ( nuevo estudiante% [ nombre "Alice" ])) ( envía s obtener-nombre ) ; => "Alice" ( envía s establecer-nombre! "Bob" ) ( envía s obtener-nombre ) ; => "Bob"              

Las definiciones de estructuras son una forma alternativa de definir nuevos tipos de valores, con mutadores presentes cuando se requiere explícitamente:

#lang racket ( struct student ( nombre ) #:mutable ) ( define s ( student "Alice" )) ( set-student-name! s "Bob" ) ( student-name s ) ; => "Bob"          

Rubí

En Ruby , se pueden definir métodos de acceso y mutación individuales, o las construcciones de metaprogramación attr_readerse attr_accessorpueden usar para declarar una variable privada en una clase y para proporcionar acceso público de solo lectura o de lectura y escritura a la misma respectivamente.

La definición de métodos de acceso y mutación individuales crea espacio para el preprocesamiento o la validación de los datos.

clase Estudiante def nombre @nombre fin      def nombre= ( valor ) @nombre = valor fin fin   

Acceso público simple de solo lectura a @namevariable implícita

clase Estudiante attr_reader :nombre fin   

Acceso público simple de lectura y escritura a @namevariable implícita

clase Estudiante attr_accessor :nombre fin   

Óxido

struct  Estudiante { nombre : String , }  impl Estudiante { fn nombre ( & self ) -> & String { & self . nombre }         función  nombre_mut ( & mut self ) -> & mut String { & mut self . nombre } }       

Charla informal

 edad:  aNumber  " Establece la edad del receptor como aNumber si es mayor que 0 y menor que 150 " ( aNumber  entre:  0  y:  150 ) ifTrue: [ edad  :=  aNumber ]

Rápido

clase  Estudiante  {  var privado  _name : String = ""     var  nombre :  String  {  obtener  {  devolver  self._name } establecer { self._name = newValue } } }        

Visual Basic .NET

Este ejemplo ilustra la idea de VB.NET sobre las propiedades, que se utilizan en las clases. De manera similar a C#, existe un uso explícito de los métodos Gety Set.

Estudiante de clase pública   Nombre privado como cadena    Nombre de propiedad pública () Obtener Retorno _name Fin Obtener Establecer ( ByVal valor ) _name = valor Fin Establecer Fin Propiedad                Fin de clase 

En VB.NET 2010, las propiedades implementadas automáticamente se pueden utilizar para crear una propiedad sin tener que usar la sintaxis Get y Set. Tenga en cuenta que el compilador crea una variable oculta, llamada _name, para que se corresponda con la propiedad name. El uso de otra variable dentro de la clase nombrada _namegeneraría un error. El acceso privilegiado a la variable subyacente está disponible desde dentro de la clase.

Clase pública Estudiante Nombre de la propiedad pública Como cadena Fin de clase        

Véase también

Referencias

  1. ^ Stephen Fuqua (2009). "Propiedades automáticas en C# 3.0". Archivado desde el original el 13 de mayo de 2011. Consultado el 19 de octubre de 2009 .
  2. ^ Tim Lee (13 de julio de 1998). "Eficiencia en el tiempo de ejecución de las funciones de acceso".
  3. ^ "CLHS: Macro DEFCLASS" . Consultado el 29 de marzo de 2011 .
  4. ^ "CLHS: 7.5.2 Acceso a ranuras" . Consultado el 29 de marzo de 2011 .
  5. ^ "MOP: Definiciones de ranuras" . Consultado el 29 de marzo de 2011 .
  6. ^ "Funciones - Lenguaje de programación D" . Consultado el 13 de enero de 2013 .
  7. ^ "El estilo D" . Consultado el 1 de febrero de 2013 .
  8. ^ "Object.prototype.__defineGetter__() - JavaScript | MDN". developer.mozilla.org . Consultado el 6 de julio de 2021 .
  9. ^ "PHP: Sobrecarga - Manual" www.php.net . Consultado el 6 de julio de 2021 .