Un método en programación orientada a objetos (POO) es un procedimiento asociado a un objeto , y generalmente también a un mensaje . Un objeto consta de datos de estado y comportamiento ; estos componen una interfaz , que especifica cómo se puede utilizar el objeto. Un método es un comportamiento de un objeto parametrizado por un usuario.
Los datos se representan como propiedades del objeto y los comportamientos se representan como métodos. Por ejemplo, un Window
objeto podría tener métodos como open
y close
, mientras que su estado (si está abierto o cerrado en un momento dado) sería una propiedad.
En la programación basada en clases , los métodos se definen dentro de una clase y los objetos son instancias de una clase determinada. Una de las capacidades más importantes que proporciona un método es la anulación de métodos : el mismo nombre (por ejemplo, area
) se puede utilizar para varios tipos diferentes de clases. Esto permite que los objetos emisores invoquen comportamientos y deleguen la implementación de esos comportamientos al objeto receptor. Un método en programación Java establece el comportamiento de un objeto de clase. Por ejemplo, un objeto puede enviar un area
mensaje a otro objeto y se invoca la fórmula adecuada ya sea que el objeto receptor sea rectangle
, circle
, triangle
, etc.
Los métodos también proporcionan la interfaz que otras clases utilizan para acceder y modificar las propiedades de un objeto; esto se conoce como encapsulación . La encapsulación y la anulación son las dos características distintivas principales entre métodos y llamadas a procedimientos. [1]
La anulación y la sobrecarga de métodos son dos de las formas más importantes en las que un método se diferencia de un procedimiento convencional o una llamada a función. Anular se refiere a una subclase que redefine la implementación de un método de su superclase. Por ejemplo, findArea
puede haber un método definido en una clase de forma, [2] triangle
, etc., cada uno definiría la fórmula apropiada para calcular su área. La idea es ver los objetos como "cajas negras" para que se puedan realizar cambios en el interior del objeto con un impacto mínimo en los demás objetos que lo utilizan. Esto se conoce como encapsulación y tiene como objetivo hacer que el código sea más fácil de mantener y reutilizar.
La sobrecarga de métodos, por otro lado, se refiere a diferenciar el código utilizado para manejar un mensaje en función de los parámetros del método. Si uno ve el objeto receptor como el primer parámetro en cualquier método, entonces la anulación es solo un caso especial de sobrecarga donde la selección se basa únicamente en el primer argumento. El siguiente ejemplo sencillo de Java ilustra la diferencia:
Los métodos de acceso se utilizan para leer los valores de datos de un objeto. Los métodos mutadores se utilizan para modificar los datos de un objeto. Los métodos de administrador se utilizan para inicializar y destruir objetos de una clase, por ejemplo, constructores y destructores.
Estos métodos proporcionan una capa de abstracción que facilita la encapsulación y la modularidad . Por ejemplo, si una clase de cuenta bancaria proporciona un método de acceso para recuperar el saldogetBalance()
actual (en lugar de acceder directamente a los campos de datos del saldo), entonces revisiones posteriores del mismo código pueden implementar un mecanismo más complejo para la recuperación del saldo (por ejemplo, una base de datos) . buscar), sin que sea necesario cambiar el código dependiente. Los conceptos de encapsulación y modularidad no son exclusivos de la programación orientada a objetos. De hecho, en muchos sentidos, el enfoque orientado a objetos es simplemente la extensión lógica de paradigmas anteriores, como los tipos de datos abstractos y la programación estructurada . [3]
Un constructor es un método que se llama al comienzo de la vida útil de un objeto para crear e inicializar el objeto, un proceso llamado construcción (o creación de instancias ). La inicialización puede incluir una adquisición de recursos. Los constructores pueden tener parámetros pero normalmente no devuelven valores en la mayoría de los idiomas. Vea el siguiente ejemplo en Java:
clase pública Principal { String_name ; int_rollo ; Main ( nombre de cadena , int roll ) { // método constructor this . _nombre = nombre ; este . _roll = rodar ; } }
Un Destructor es un método que se llama automáticamente al final de la vida útil de un objeto, un proceso llamado Destrucción . La destrucción en la mayoría de los idiomas no permite argumentos del método destructor ni valores de retorno. Los destructores se pueden implementar para realizar tareas de limpieza y otras tareas en la destrucción de objetos.
En lenguajes de recolección de basura , como Java , [4] : 26, 29 C# , [5] : 208–209 y Python , los destructores se conocen como finalizadores . Tienen un propósito y función similar a los destructores, pero debido a las diferencias entre los lenguajes que utilizan recolección de basura y los lenguajes con administración manual de memoria, la secuencia en la que se llaman es diferente.
Un método abstracto es aquel que sólo tiene una firma y ningún cuerpo de implementación . A menudo se utiliza para especificar que una subclase debe proporcionar una implementación del método, como en una clase abstracta . Los métodos abstractos se utilizan para especificar interfaces en algunos lenguajes de programación. [6]
El siguiente código Java muestra una clase abstracta que debe ampliarse:
clase abstracta Forma { área int abstracta ( int h , int w ); // firma del método abstracto }
La siguiente subclase extiende la clase principal:
clase pública Rectángulo extiende Forma { @Override int area ( int h , int w ) { return h * w ; } }
Si una subclase proporciona una implementación para un método abstracto, otra subclase puede hacerlo abstracto nuevamente. Esto se llama reabstracción .
En la práctica, esto rara vez se utiliza.
En C#, un método virtual se puede anular con un método abstracto. (Esto también se aplica a Java, donde todos los métodos no privados son virtuales).
clase IA { public virtual void M () { } } clase abstracta IB : IA { anulación pública abstract void M (); // permitido }
Los métodos predeterminados de las interfaces también se pueden reabstraer, requiriendo subclases para implementarlos. (Esto también se aplica a Java).
interfaz IA { void M () { } } interfaz IB : IA { abstracto void IA . M (); } clase C : IB { } // error: la clase 'C' no implementa 'IA.M'.
Los métodos de clase son métodos que se llaman en una clase en lugar de en una instancia. Normalmente se utilizan como parte de un metamodelo de objetos . Es decir, para cada clase definida se crea una instancia del objeto de clase en el metamodelo. Los protocolos de metamodelo permiten crear y eliminar clases. En este sentido, proporcionan la misma funcionalidad que los constructores y destructores descritos anteriormente. Pero en algunos lenguajes como el Common Lisp Object System (CLOS), el metamodelo permite al desarrollador alterar dinámicamente el modelo de objetos en tiempo de ejecución: por ejemplo, crear nuevas clases, redefinir la jerarquía de clases, modificar propiedades, etc.
Los métodos especiales son muy específicos del idioma y un idioma puede admitir ninguno, algunos o todos los métodos especiales definidos aquí. El compilador de un lenguaje puede generar automáticamente métodos especiales predeterminados o se le puede permitir a un programador definir opcionalmente métodos especiales. La mayoría de los métodos especiales no se pueden llamar directamente, sino que el compilador genera código para llamarlos en el momento adecuado.
Los métodos estáticos deben ser relevantes para todas las instancias de una clase y no para una instancia específica. Son similares a las variables estáticas en ese sentido. Un ejemplo sería un método estático para sumar los valores de todas las variables de cada instancia de una clase. Por ejemplo, si hubiera una Product
clase, podría tener un método estático para calcular el precio promedio de todos los productos.
Se puede invocar un método estático incluso si aún no existen instancias de la clase. Los métodos estáticos se denominan "estáticos" porque se resuelven en tiempo de compilación según la clase a la que se llaman y no dinámicamente como en el caso de los métodos de instancia, que se resuelven polimórficamente según el tipo de tiempo de ejecución del objeto.
En Java, un método estático comúnmente utilizado es:
Math.max(doble a, doble b)
Este método estático no tiene objeto propietario y no se ejecuta en una instancia. Recibe toda la información de sus argumentos. [2]
Los operadores de asignación de copia definen las acciones que realizará el compilador cuando un objeto de clase se asigna a un objeto de clase del mismo tipo.
Los métodos de operador definen o redefinen símbolos de operador y definen las operaciones que se realizarán con el símbolo y los parámetros de método asociados. Ejemplo de C++:
#incluir <cadena> clase Datos { público : bool operador < ( const Datos y datos ) const { return roll_ < datos . rollo_ ; } operador bool == ( const Datos y datos ) const { return name_ == datos . nombre_ && roll_ == datos . rollo_ ; } privado : std :: cadena nombre_ ; int rollo_ ; };
Algunos lenguajes de procedimientos se ampliaron con capacidades orientadas a objetos para aprovechar las grandes habilidades y el código heredado de esos lenguajes, pero aún así proporcionar los beneficios del desarrollo orientado a objetos. Quizás el ejemplo más conocido sea C++ , una extensión orientada a objetos del lenguaje de programación C. Debido a los requisitos de diseño para agregar el paradigma orientado a objetos a un lenguaje de procedimientos existente, el paso de mensajes en C++ tiene algunas capacidades y terminologías únicas. Por ejemplo, en C++ un método se conoce como función miembro . C++ también tiene el concepto de funciones virtuales , que son funciones miembro que se pueden anular en clases derivadas y permiten el envío dinámico .
Las funciones virtuales son el medio por el cual una clase C++ puede lograr un comportamiento polimórfico. Las funciones miembro no virtuales , o métodos regulares , son aquellas que no participan en el polimorfismo .
Ejemplo de C++:
#incluir <iostream> #incluir <memoria> clase Super { público : virtual ~ Super () = predeterminado ; virtual void IAm () { std :: cout << "¡Soy la superclase! \n " ; } }; class Sub : public Super { public : void IAm () override { std :: cout << "¡Soy la subclase! \n " ; } }; int main () { std :: Unique_ptr < Super > inst1 = std :: make_unique < Super > (); std :: Unique_ptr < Super > inst2 = std :: make_unique < Sub > (); inst1 -> Soy (); // Llamadas |Super::YoSoy|. inst2 -> Soy (); // Llamadas |Sub::YoSoy|. }