En informática , un método mutador es un método que se utiliza para controlar los cambios en una variable. También se les conoce comúnmente como métodos setter . A menudo, un método setter va acompañado de un método getter , que devuelve el valor de la variable miembro privada. Estos dos métodos se conocen colectivamente como métodos de acceso .
El método mutador se utiliza con mayor frecuencia en la programación orientada a objetos , en consonancia con el principio de encapsulación . Según este principio, las variables miembro de una clase se declaran privadas para ocultarlas y protegerlas de otro código, y solo pueden modificarse mediante una función miembro pública (el método mutador), que recibe como parámetro el nuevo valor deseado, lo valida opcionalmente y modifica la variable miembro privada . Los métodos mutadores pueden compararse con la sobrecarga del operador de asignación , pero suelen aparecer en diferentes niveles de la jerarquía de objetos.
Los métodos mutadores también pueden utilizarse en entornos no orientados a objetos. En este caso, se pasa al método mutador una referencia a la variable que se va a modificar, junto con su nuevo valor. En este escenario, el compilador no puede impedir que el código omita el método mutador y modifique la variable directamente. Es responsabilidad de los desarrolladores garantizar que la variable solo se modifique mediante el método mutador y no directamente.
En los lenguajes de programación que las admiten, las propiedades ofrecen una alternativa conveniente sin renunciar a la utilidad de la encapsulación.
En los ejemplos que se muestran a continuación, un método mutador completamente implementado también puede validar los datos de entrada o tomar medidas adicionales, como activar un evento .
Trascendencia
La alternativa a definir métodos de acceso y modificación, o bloques de propiedades , consiste en otorgar a la variable de instancia cierta visibilidad distinta a la privada y acceder a ella directamente desde fuera de los objetos. Mediante métodos de acceso y modificación se puede definir un control mucho más preciso de los derechos de acceso. Por ejemplo, un parámetro puede hacerse de solo lectura simplemente definiendo un método de acceso, pero no uno de modificación. La visibilidad de ambos métodos puede ser diferente; a menudo resulta útil que el método de acceso sea público, mientras que el método de modificación permanezca protegido, con acceso restringido al paquete o interno.
El bloque donde se define el mutador ofrece la oportunidad de validar o preprocesar los datos entrantes. Si se garantiza que todo acceso externo se realice a través del mutador, estos pasos no se pueden omitir. Por ejemplo, si una fecha está representada por variables privadas separadas , yearlas fechas entrantes pueden dividirse mediante el mutador, mientras que, para mayor coherencia, se accede a las mismas variables de instancia privadas mediante y . En todos los casos, los valores de mes fuera del rango 1-12 pueden rechazarse con el mismo código.monthdaysetDatesetYearsetMonth
Por el contrario, los accesores permiten sintetizar representaciones de datos útiles a partir de variables internas, manteniendo su estructura encapsulada y oculta para módulos externos. Un getAmountaccesor monetario puede construir una cadena a partir de una variable numérica con el número de decimales definido por un parámetro oculto currency.
Los lenguajes de programación modernos suelen ofrecer la posibilidad de generar el código repetitivo para los métodos de acceso y modificación en una sola línea , como por ejemplo en C# public string Name { get; set; }y Ruby attr_accessor :name. En estos casos, no se crean bloques de código para validación, preprocesamiento o síntesis. Estos métodos de acceso simplificados conservan la ventaja de la encapsulación frente a las variables de instancia públicas simples, pero es común que, a medida que avanzan los diseños de los sistemas , se mantiene el software y cambian los requisitos, las exigencias sobre los datos se vuelvan más sofisticadas. Muchos métodos de acceso y modificación automáticos acaban sustituyéndose por bloques de código independientes. La ventaja de crearlos automáticamente en las primeras etapas de la implementación es que la interfaz pública de la clase permanece idéntica, independientemente de si se añade mayor sofisticación o no, sin necesidad de una refactorización extensa en caso de que se añada. [ 1 ]
La manipulación de parámetros con métodos de acceso y modificación dentro de la clase donde se definen suele requerir una planificació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 a la variable de instancia privada directamente o no. A medida que se añaden validaciones, validación cruzada , comprobaciones de integridad de datos , preprocesamiento u otras mejoras, pueden aparecer errores sutiles donde algún acceso interno utiliza el código más reciente, mientras que en otros lugares se omite.
Las funciones de acceso pueden ser menos eficientes que la obtención o el almacenamiento directo de campos de datos debido a los pasos adicionales involucrados, [ 2 ] sin embargo, dichas funciones a menudo se insertan en línea, lo que elimina la sobrecarga de una llamada a la función.
Ejemplos
![]()
Asamblea
estructura del estudiante edad dd ? estudiante termina.code student_get_age proc object : DWORD mov ebx , object mov eax , student.age [ ebx ] ret student_get_age endpobjeto student_set_age : DWORD , edad : DWORD mov ebx , objeto mov eax , edad mov student.age [ ebx ] , eax ret student_set_age endpdo
En el archivo Student.h :
#pragma una vezstruct Student ; /* estructura opaca */ typedef struct Student Student ;Estudiante * crearEstudiante ( int edad , const char * nombre ); void destruirEstudiante ( const Estudiante * s );void setStudentAge ( Student * s , int age ); int getStudentAge ( const Student * s ); char * getStudentName ( const Student * s );En el archivo Student.c :
#include <stdlib.h> #include <string.h>#incluir "Student.h"struct Estudiante { int edad ; char * nombre ; };Estudiante * createStudent ( int edad , const char * nombre ) { Estudiante * s = ( Estudiante * ) malloc ( sizeof ( Estudiante )); s -> nombre = strdup ( nombre ); s -> edad = edad ; return s ; }void destroyStudent ( const Student * s ) { free ( s -> name ); free ( s ); }void setStudentAge ( Student * s , int age ) { s -> age = age ; }int getStudentAge ( const Student * s ) { return s -> age ; }char * getStudentName ( const Student * s ) { return s -> name ; }En el archivo Main.c :
#include <stdio.h>#incluir "Student.h"int main ( void ) { Student * s = createStudent ( 19 , "Maurice" ); char * name = getStudentName ( s ); int old_age = getStudentAge ( s ); printf ( "%s's old age = %i \n " , name , old_age ); setStudentAge ( s , 21 ); int new_age = getStudentAge ( s ); printf ( "%s's new age = %i\ n " , name , new_age ); destroyStudent ( s ); return 0 ; }En el archivo Makefile:
todo : out.txt ; cat $ < out.txt : main ; ./$ < > $ @ main : Main.o Student.o Main.o Student.o : Student.h clean :; $ ( RM ) * .o out.txt mainC++
En el archivo Student.cppm :
importar std ;usando std :: string ;clase Estudiante { privado : string nombre ; público : Estudiante ( const string & nombre ) : nombre { nombre } {}[[ nodiscard ]] const string & getName () const noexcept { return name ; }void setName ( const string & name ) noexcept { this -> name = name ; } };DO#
Este ejemplo ilustra el concepto de propiedades en C# , 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 gestionar las acciones. Nótese el uso de la variable integrada (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 puede abreviarse 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 implica que la variable subyacente ya no está disponible desde dentro de la clase. Por lo tanto, la setparte de la propiedad debe estar presente para su asignación. El acceso puede restringirse con un setmodificador de acceso específico.
clase pública Estudiante { cadena pública Nombre { obtener ; establecer ; } }Lisp común
En Common Lisp Object System , las especificaciones de ranuras dentro de las definiciones de clase pueden especificar cualquiera de las opciones :reader, :writery (incluso varias veces) para definir métodos de lectura, métodos de asignación y métodos de acceso (un método de lectura y el método respectivo). [ 3 ] Las ranuras siempre son directamente accesibles a través de sus nombres con el uso de y , y las opciones de acceso de ranura definen métodos especializados que usan . [ 4 ]:accessorsetfwith-slotsslot-valueslot-value
CLOS en sí mismo no tiene noción de propiedades, aunque la extensión MetaObject Protocol especifica medios para acceder a los nombres de las funciones de lectura y escritura de una ranura, incluidas las generadas con la :accessoropción. [ 5 ]
El siguiente ejemplo muestra la definición de una clase de estudiante utilizando estas opciones de ranura y acceso directo a la ranura:
( defclass student () (( name :initarg :name :initform "" :accessor student-name ) ; student-name es configurable ( birthdate :initarg :birthdate :initform 0 :reader student-birthdate ) ( number :initarg :number :initform 0 :reader student-number :writer set-student-number )));; Ejemplo de un método para obtener una propiedad calculada (esto es simplemente un método) ( defmethod student-age (( self student )) ( - ( get-universal-time ) ( student-birthdate self )));; Ejemplo de acceso directo a ranuras dentro de un setter de propiedad 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 definiciones de métodos adicionales ( defmethod set-student-number :before ( new-number ( self student )) ;; También podrías comprobar si ya existe un estudiante con el nuevo número. ( check-type new-number ( integer 1 * )))D
D admite una sintaxis de funciones getter y setter. En la versión 2 del lenguaje, los métodos getter y setter de clase/estructura deben tener el @propertyatributo. [ 6 ] [ 7 ]
clase Estudiante { cadena privada nombre_ ;// Getter @property string name () { return this . name_ ; }// Setter @property string name ( string name_in ) { return this . name_ = name_in ; } }Una Studentinstancia se puede utilizar de esta manera:
Estudiante s = nuevo Estudiante ; s.nombre = " David" ; // mismo efecto que estudiante.nombre("David") cadena nombre_estudiante = s.nombre ; // mismo efecto que estudiante.nombre( )Delfos
Esta es una clase sencilla en lenguaje Delphi que ilustra el concepto de propiedad pública para acceder a un campo privado.
interfaztype TStudent = class strict private FName : string ; procedure SetName ( const Value : string ) ; public /// <summary> /// Obtiene o establece el nombre del estudiante. /// </summary> property Name : string read FName write SetName ; end ;// ...implementaciónprocedimiento TStudent . SetName ( const Value : string ) ; begin FName := Value ; end ;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 Student, y los métodos "setter" y "getter" son públicos, a saber, los métodos " getName()" y " setName(name)".
clase pública Estudiante { cadena privada nombre ;public String getName () { return name ; } public void setName ( String name ) { this . name = name ; } }JavaScript
En este ejemplo, se utiliza una función constructora Studentpara crear objetos que representan a un estudiante, almacenando únicamente su nombre.
función Estudiante ( nombre ) { var _nombre = nombre ;this.getName = function ( ) { return _name ; } ;this.setName = function ( value ) { _name = value ; } ; }O (usando una forma obsoleta de definir accesores en navegadores web): [ 8 ]
función Estudiante ( nombre ){ var _nombre = nombre ; this . __defineGetter__ ( 'nombre' , function () { return _nombre ; }); this . __defineSetter__ ( 'nombre' , function ( valor ) { _nombre = valor ; }); }O (usando prototipos para la herencia y la sintaxis de acceso de ES6 ):
función Estudiante ( nombre ){ este . _nombre = nombre ; }Estudiante.prototipo = { obtener nombre ( ) { devolver este . _nombre ; }, establecer nombre ( valor ) { este . _nombre = valor ; } } ;O (sin usar prototipos):
var Estudiante = { obtener nombre () { devolver este . _nombre ; }, establecer nombre ( valor ) { este . _nombre = valor ; } };O (usando defineProperty):
function Student ( name ){ this . _name = name ; } Object . defineProperty ( Student . prototype , 'name' , { get : function () { return this . _name ; }, set : function ( value ) { this . _name = value ; } });ActionScript 3.0
paquete { clase pública Estudiante { variable privada _nombre : String ; función pública obtener nombre () : String { devolver _nombre ; }función pública establecer nombre ( valor : String ) : void { _nombre = valor ; } } }Objetivo-C
Utilizando la sintaxis tradicional de Objective-C 1.0, con conteo manual de referencias como el que funciona en GNUstep en Ubuntu 12.04 :
@interface Student : NSObject { NSString * _name ; }- ( NSString * ) nombre ; - ( void ) establecerNombre: ( NSString * ) nombre ;@fin@implementación Estudiante- ( NSString * ) nombre { return _nombre ; }- ( void ) setName: ( NSString * ) name { [ _name release ]; _name = [ name retain ]; }@finUtilizando la sintaxis más reciente de Objective-C 2.0, como la que se usa en Mac OS X 10.6 , iOS 4 y Xcode 3.2, se genera el mismo código que se describe anteriormente:
@interface Estudiante : NSObject@property ( nonatomic , retain ) NSString * nombre ;@fin@implementación Estudiante@synthesize nombre = _nombre ;@finY a partir de OS X 10.8 e iOS 6 , al usar Xcode 4.4 o superior, la sintaxis se puede simplificar aún más:
@interface Estudiante : NSObject@property ( nonatomic , strong ) NSString * nombre ;@fin@implementación Estudiante//Aquí no se permite nada y está bien.@finPerl
paquete Estudiante ;sub nuevo { bendecir {}, cambiar ; }sub set_name { my $self = shift ; $self -> { name } = $_ [ 0 ]; }sub obtener_nombre { mi $self = shift ; return $self -> { nombre }; }1 ;O bien, utilizando Class::Accessor
paquete Estudiante ; usar base qw(Clase::Accessor) ; __PAQUETE__ -> seguir_mejores_prácticas ;Estudiante -> mk_accessors ( qw(nombre) );1 ;O bien, utilizando el sistema de objetos Moose :
paquete Estudiante ; usar Moose ;# Moose utiliza el atributo name como setter y getter, las propiedades reader y writer # 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 __setpara las 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 Student, y los métodos "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 -> name ; }/** * @param string $newName El nombre a establecer. */ public function setName ( string $newName ) : void { $this -> name = $newName ; } }Pitón
Este ejemplo utiliza una clase de Python con una variable, un método getter y un método setter.
clase Estudiante : _nombre : str# 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 ) -> str : return self . _name# Método setter @name . setter def name ( self , new_name : str ) -> None : self . _name = new_nameestudiante : Estudiante = Estudiante ( "Bob" ) imprimir ( estudiante.nombre ) # imprime : Bobestudiante.nombre = "Alice " print ( estudiante.nombre ) # imprime : Aliceestudiante._nombre = " Charlie " # omitir el setter print ( estudiante._nombre ) # omitir el getter # imprime : CharlieRaqueta
En Racket , el sistema de objetos es una forma de organizar el código que complementa los módulos y las unidades. Al igual que en el resto del lenguaje, el sistema de objetos tiene valores de primera clase y se utiliza el ámbito léxico para controlar el acceso a 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 ( new student% [ name "Alice" ])) ( send s get-name ) ; => "Alice" ( send s set-name! "Bob" ) ( send s get-name ) ; => "Bob"Las definiciones de estructuras son una forma alternativa de definir nuevos tipos de valores, y los modificadores están presentes cuando se requieren explícitamente:
#lang racket ( struct student ( name ) #: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 modificación individuales, o bien se pueden utilizar las construcciones de metaprogramación para declarar una variable privada en una clase y para proporcionar acceso público a ella, ya sea de solo lectura o de lectura y escritura, respectivamente.attr_readerattr_accessor
Definir métodos individuales de acceso y modificación crea espacio para el preprocesamiento o la validación de los datos.
clase Estudiante definición nombre @nombre findef nombre = ( valor ) @nombre = valor fin finAcceso público simple de solo lectura a @namela variable implícita
clase Estudiante attr_reader :nombre finAcceso público simple de lectura y escritura a @namela variable implícita
clase Estudiante attr_accessor :nombre finÓxido
struct Estudiante { nombre : String , }impl Estudiante { fn nombre ( & self ) -> & Cadena { & self . nombre }fn name_mut ( & mut self ) -> & mut String { & mut self . name } }Charla informal
edad: aNúmero "Establece la edad del receptor como aNúmero si es mayor que 0 y menor que 150" ( aNúmero entre: 0 y: 150 ) ifTrue: [ edad := aNúmero ] Rápido
clase Estudiante { variable privada _nombre : Cadena = ""var nombre : String { obtener { devolver self._nombre } establecer { self._nombre = nuevoValor } } }Visual Basic .NET
Este ejemplo ilustra el concepto de propiedades en VB.NET, que se utilizan en las clases. Al igual que en C#, se hace un uso explícito de los métodos Gety .Set
Estudiante de clase públicaPrivado _name como cadenaNombre de la propiedad pública () Obtener Devolver _nombre Fin Obtener Establecer ( Por valor valor ) _nombre = valor Fin Establecer Fin PropiedadFin de claseEn VB.NET 2010, las propiedades implementadas automáticamente permiten crear una propiedad sin necesidad de usar la sintaxis Get y Set. Cabe destacar que el compilador crea una variable oculta, denominada _name, que se corresponde con la propiedad name. Usar otra variable dentro de la clase con el mismo nombre _namegeneraría un error. El acceso privilegiado a la variable subyacente está disponible desde dentro de la clase.
Clase pública Estudiante Propiedad pública nombre Como Cadena Fin de claseVéase también
Referencias
- ↑ Stephen Fuqua (2009). "Propiedades automáticas en C# 3.0" . Consultado el 19 de octubre de 2009 .
{{cite web}}: CS1 maint: servicio de archivado obsoleto ( enlace ) - ↑ Tim Lee (13 de julio de 1998). "Eficiencia en tiempo de ejecución de las funciones de acceso" .
- ↑ "CLHS: Macro DEFCLASS" . Consultado el 29 de marzo de 2011 .
- ↑ "CLHS: 7.5.2 Acceso a ranuras" . Consultado el 29 de marzo de 2011 .
- ↑ "MOP: Definiciones de ranuras" . Consultado el 29 de marzo de 2011 .
- ↑ "Funciones - Lenguaje de programación D" . Consultado el 13 de enero de 2013 .
- ↑ "El estilo D" . Consultado el 1 de febrero de 2013 .
- ↑ "Object.prototype.__defineGetter__() - JavaScript | MDN" . developer.mozilla.org . Consultado el 6 de julio de 2021 .
- ↑ "PHP: Sobrecarga - Manual" . www.php.net . Consultado el 6 de julio de 2021 .
- Método (programación informática)