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 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 la 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 si el objeto receptor es un 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 los métodos y las llamadas a procedimientos. [1]
La anulación y la sobrecarga de métodos son dos de las formas más significativas en que un método difiere de un procedimiento o una llamada a una función convencionales. La anulación se refiere a una subclase que redefine la implementación de un método de su superclase. Por ejemplo, findArea
puede ser un método definido en una clase de forma, [2] triangle
, etc., cada uno definiría la fórmula adecuada para calcular su área. La idea es considerar 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.
Por otro lado, la sobrecarga de métodos se refiere a la diferenciación del código utilizado para manejar un mensaje en función de los parámetros del método. Si se considera el objeto receptor como el primer parámetro de cualquier método, la sobreescritura es simplemente un caso especial de sobrecarga en el que la selección se basa únicamente en el primer argumento. El siguiente ejemplo simple de Java ilustra la diferencia:
Los métodos de acceso se utilizan para leer los valores de datos de un objeto. Los métodos de mutación se utilizan para modificar los datos de un objeto. Los métodos de administración 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 getBalance()
método de acceso para recuperar el saldo actual (en lugar de acceder directamente a los campos de datos del saldo), las revisiones posteriores del mismo código pueden implementar un mecanismo más complejo para la recuperación del saldo (por ejemplo, una búsqueda de base de datos ), 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 instanciación ). La inicialización puede incluir una adquisición de recursos. Los constructores pueden tener parámetros, pero por lo general no devuelven valores en la mayoría de los lenguajes. Vea el siguiente ejemplo en Java:
clase pública Main { String _name ; int _roll ; Main ( String nombre , int roll ) { // método constructor this . _name = nombre ; this . _roll = roll ; } }
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 lenguajes no permite argumentos de 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 que utilizan 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 una función similares a los de 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 los llama es diferente.
Un método abstracto es aquel que solo tiene una firma y no tiene un 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 necesita ser ampliada:
clase abstracta Forma { int abstracto área ( 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 área ( int h , int w ) { devolver h * w ; } }
Si una subclase proporciona una implementación para un método abstracto, otra subclase puede volverlo abstracto. Esto se denomina reabstracción .
En la práctica esto rara vez se utiliza.
En C#, un método virtual se puede reemplazar por un método abstracto. (Esto también se aplica a Java, donde todos los métodos no privados son virtuales).
clase IA { void virtual público M () { } } clase abstracta IB : IA { void virtual público M ( ); // permitido }
Los métodos predeterminados de las interfaces también se pueden reabstraer, lo que requiere que las subclases los implementen. (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 invocan en una clase en lugar de en una instancia. Normalmente se utilizan como parte de un metamodelo de objeto . 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 Common Lisp Object System (CLOS) el metamodelo permite al desarrollador alterar dinámicamente el modelo de objeto en tiempo de ejecución: por ejemplo, para crear nuevas clases, redefinir la jerarquía de clases, modificar propiedades, etc.
Los métodos especiales son muy específicos de cada lenguaje y un lenguaje 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 métodos especiales de manera opcional. La mayoría de los métodos especiales no se pueden llamar directamente, sino que el compilador genera código para llamarlos en los momentos apropiados.
Los métodos estáticos están pensados para ser relevantes para todas las instancias de una clase, en lugar de para una instancia específica. En ese sentido, son similares a las variables estáticas . 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 en función de la clase en la que se invocan y no de forma dinámica, como en el caso de los métodos de instancia, que se resuelven de forma polimórfica en función del tipo de objeto en tiempo de ejecución.
En Java, un método estático comúnmente utilizado es:
Matemática.max(doble a, doble b)
Este método estático no posee ningún objeto y no se ejecuta en una instancia. Recibe toda la información de sus argumentos. [2]
Los operadores de asignación de copia definen acciones que debe 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 los 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++:
#include <cadena> clase Datos { público : bool operador < ( const Datos & datos ) const { devolver roll_ < datos.roll_ ; } bool operador == ( const Datos & datos ) const { devolver nombre_ == datos.nombre_ && roll_ == datos.roll_ ; } privado : std :: string nombre_ ; int roll_ ; };
Algunos lenguajes procedimentales se ampliaron con capacidades orientadas a objetos para aprovechar los grandes conjuntos de 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 procedimental 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 los medios por los cuales una clase de 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++:
#include <iostream> #include <memoria> clase Super { público : virtual ~ Super () = predeterminado ; virtual void IAm () { std :: cout << "¡Soy la superclase! \n " ; } }; clase Sub : público Super { público : void IAm () override { std :: cout << "¡Soy la subclase! \n " ; } }; int principal () { 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|. }