Red de conocimiento de abogados - Derecho de sociedades - ¿Qué es la programación orientada a objetos?

¿Qué es la programación orientada a objetos?

En este artículo, el quinto de esta serie, Teodor explica qué es la programación orientada a objetos, cuándo usarla y cómo funciona en Perl. La programación orientada a objetos (POO) es una técnica de programación poderosa, pero no es una panacea. Un buen programador debe entender cómo usarlo y debe saber cuándo confiar en técnicas de programación más tradicionales. Usar programación orientada a objetos en Perl es fácil. A diferencia de los lenguajes de programación orientada a objetos más restrictivos, como C++ y Java, la programación orientada a objetos en Perl impone pocas restricciones obligatorias al programador. La programación orientada a objetos es una adición esencial a la caja de herramientas de todo programador y una técnica muy útil para ampliar la gama de problemas que se pueden resolver con Perl. ¿Qué es la programación orientada a objetos (POO)? La programación orientada a objetos es un enfoque de programación o un enfoque general para la resolución de problemas. Por el contrario, los algoritmos son métodos específicos que se utilizan para resolver problemas específicos. La programación orientada a objetos es inherentemente un enfoque poderoso; tiende a hacer que los enfoques de programación procedimental y funcional sean menos relevantes para el problema y, a menos que su combinación con los enfoques de programación procedimental y funcional sea extremadamente beneficioso, no habrá interacción entre ellos. En Perl, este poder está algo disminuido, pero todavía está muy vivo. Este artículo analiza los conceptos básicos de la programación orientada a objetos en Perl versus la programación funcional y de procedimientos, y demuestra cómo usar la programación orientada a objetos en programas y módulos de Perl. Tenga en cuenta que este artículo es una descripción general y no una explicación exhaustiva de todos los aspectos de la programación orientada a objetos en Perl. Se necesitarían varios libros para cubrir una explicación tan detallada y se ha escrito varias veces. Para obtener más información, consulte Recursos más adelante en este artículo. ¿Qué es exactamente la programación orientada a objetos? La programación orientada a objetos es una tecnología que utiliza objetos para resolver problemas. En términos de programación, los objetos son entidades cuyas propiedades y comportamientos son necesarios para resolver el problema en cuestión. Esta definición debería ser más detallada, pero no puede serlo porque la variedad de métodos de programación orientada a objetos en la industria informática actual es casi inimaginable. En el entorno de programación Perl, no se requiere programación orientada a objetos para utilizar el lenguaje. Perl versión 5 y posteriores fomentan el uso de programación orientada a objetos, pero no lo requieren exactamente. Todas las bibliotecas de Perl son módulos, lo que significa que utilizan al menos partes básicas de programación orientada a objetos. Además, la mayoría de las bibliotecas Perl se implementan como objetos, lo que significa que los usuarios deben utilizarlas como entidades OOP con comportamientos y características específicas a través de interfaces bien definidas. Volver arriba Funciones básicas del lenguaje de programación OO Generalmente, se requieren tres funciones de lenguaje para un lenguaje de programación OOP. Son herencia, polimorfismo y encapsulación. Perl admite la herencia. La herencia se utiliza cuando un objeto (objeto hijo) utiliza otro objeto como punto de partida (objeto padre) y luego modifica sus propiedades y comportamiento cuando es necesario. La relación padre-hijo es necesaria para la programación orientada a objetos porque permite construir objetos encima de otros objetos. Esta reutilización es uno de los beneficios que hace de la programación orientada a objetos el favorito de los programadores. Hay dos tipos de herencia: herencia única y herencia múltiple. La herencia única requiere que el objeto hijo tenga solo un padre, mientras que la herencia múltiple es más libre (como en la vida real, tener más de dos padres puede causar confusión durante la programación y dificultar el trabajo con objetos hijos, así que no utilices la herencia múltiple también mucho ). Aunque dos o más objetos principales son realmente raros, Perl admite la herencia múltiple. El polimorfismo (del griego, que significa "muchas formas") es la técnica de hacer que un objeto parezca otro objeto. Esto es un poco complicado, así que déjame darte un ejemplo. Digamos que tienes un rancho de ovejas con cuatro ovejas (Ovis), pero acabas de comprar dos cabras (Capra) y un pastor alemán (Canis). ¿Cuántos animales tienes en tu casa? Hay que sumar todas las ovejas, cabras y perros, lo que da 7. De hecho, acaba de aplicar el polimorfismo, que consiste en tratar tres tipos diferentes de animales como un tipo común ("animal") a efectos de cálculo. Si piensas en las ovejas, las cabras y los perros como mamíferos, es un simple acto de fe. Los biólogos utilizan el polimorfismo de esta manera todos los días, y los programadores son conocidos por "robar" (me refiero a "reutilizar") buenas ideas de otros campos de la ciencia. Perl soporta totalmente el polimorfismo.

Pero no se usa muy a menudo, porque los programadores de Perl parecen preferir usar atributos de objetos en lugar de modificar el comportamiento heredado para modificar el comportamiento general. Esto significa que es más probable que vea código que crea tres objetos IO::Socket::INET: uno para recibir y enviar paquetes UDP en el puerto 234, uno para recibir paquetes TCP en el puerto 80 y otro para enviar paquetes TCP en el puerto. 1024, no verá el uso de IO::Socket::INET::UDPTransceiver para el primer caso, el uso de IO::Socket::INET::TCPReceiver para el segundo caso y el uso de IO::Socket ::INET::TCPReceiver para el tercer caso Código de caso usando IO::Socket::TCPTransmitter. Esto es como decir en términos biológicos que tanto los perros como las cabras son mamíferos, pero las cabras pertenecen al género Capra y los perros al género Canis. Los puristas de la programación orientada a objetos creen que todo debería clasificarse correctamente, pero los programadores de Perl no son puristas en absoluto. Suelen estar menos restringidos por las reglas de la programación orientada a objetos, lo que los hace más felices en las fiestas que los puristas de la programación orientada a objetos. La encapsulación se refiere a contener el comportamiento y las características del objeto de tal manera que los usuarios no puedan acceder al comportamiento y las características del objeto a menos que lo permita el autor del objeto. De esta manera, el usuario en cuestión no puede hacer cosas que no tiene permitido hacer y no puede acceder a datos a los que no tiene permiso y, a menudo, a datos dañinos. Perl suele utilizar un enfoque relajado para la encapsulación. Ver Listado 1. Volver arriba ¿Por qué la programación orientada a objetos es un enfoque poderoso? Volviendo a nuestro tema original sobre cómo la programación orientada a objetos es un enfoque poderoso, ahora podemos ver que la programación orientada a objetos combina varios conceptos clave que dificultan la combinación con el uso de programación funcional y de procedimientos (PP y FP). Primero, ni PP ni FP tienen el concepto de herencia o polimorfismo de clase, porque no hay clases en PP y FP. La encapsulación existe en PP y FP, pero sólo a nivel de procedimiento, nunca como propiedades de clase u objeto. Dado que los programadores se toman la molestia de utilizar estas herramientas básicas de programación orientada a objetos, significa que generalmente es más probable que utilicen programación orientada a objetos para todo el proyecto en lugar de mezclar métodos incompatibles. Se podría argumentar que, en última instancia, todos los programas se reducen a la ejecución procedimental de instrucciones, por lo que no importa cuán puramente implementado esté un programa de programación orientada a objetos, cada programa de programación orientada a objetos comienza con sus funciones (también llamadas métodos) y la creación del primer objeto que realiza el resto de la obra) contiene código procesal. Incluso los lenguajes tan cercanos a la programación orientada a objetos "pura" como Java requieren inevitablemente una función main(). Por tanto, parece que la POO es sólo un subconjunto del PP. Pero esta reducción de la programación orientada a objetos a instrucciones secuenciales no preocupa más a los arquitectos o programadores de sistemas que las instrucciones reales del ensamblador ejecutadas para cada operación. Recuerde, la programación orientada a objetos es un método en sí mismo, no un fin. La programación orientada a objetos no funciona bien con los enfoques de programación procedimental porque se centra en objetos, mientras que la programación procedimental se basa en procedimientos (definimos aproximadamente los procedimientos como funciones que se pueden obtener sin utilizar técnicas de programación orientada a objetos y los métodos como funciones que solo se pueden obtener en objetos). ). función que sólo se puede obtener en ). Al igual que los métodos, los procedimientos son solo funciones llamadas por el usuario, pero existen algunas diferencias entre los dos. El procedimiento no utiliza datos de objetos. Se les deben pasar datos en su lista de argumentos o deben usar datos de su alcance. Un procedimiento puede acceder a cualquier dato que se le pase cuando se le llama, incluso a los datos globales de todo el programa. Los métodos sólo deben acceder a los datos de su objeto. De hecho, el alcance de la función de un método suele ser el objeto que contiene el método. A menudo se encuentra que los procesos utilizan datos globales, aunque esto sólo debe hacerse cuando sea absolutamente necesario. Los métodos que utilizan datos globales deben reescribirse lo antes posible. Los procedimientos suelen llamar a otros procedimientos con varios parámetros. Los métodos deben tener sólo unos pocos parámetros y deben llamar a otros métodos más veces que a otros procedimientos. Hay varias razones por las que la programación funcional (FP) no funciona bien con la programación orientada a objetos. La razón más importante es que FP se basa en métodos funcionales detallados para resolver problemas, mientras que OOP usa objetos para expresar conceptos y, a diferencia de los métodos OOP que solo se pueden usar dentro del objeto que los contiene, los procedimientos FP se usan en todas partes.

En resumen, ahora podemos explicar por qué Perl es uno de los mejores lenguajes para mezclar enfoques de programación orientada a objetos, FP y PP. Volver arriba ¿Cómo combina Perl la programación orientada a objetos con la programación funcional y de procedimientos? Perl es un lenguaje flojo. Se esfuerza por permitir que los programadores hagan lo que quieran y de la forma que consideren conveniente. Esto es muy diferente de lenguajes como Java y C++. Por ejemplo, Perl felizmente permite al programador crear variables automáticamente si el programador no las declaró originalmente (aunque esto no se recomienda y se puede evitar usando el muy recomendado pragma "usar estricto"). Si te dispararas en el pie, Perl te daría diez balas y una mira láser, luego se quedaría quieto y te animaría. Como resultado, Perl es un lenguaje muy abierto al abuso de métodos. No tengas miedo. No importa. Por ejemplo, se permite el acceso a datos de objetos internos, cambios en vivo en clases y redefinición de métodos en vivo. La forma de Perl es permitir a los programadores romper las reglas en aras de la codificación, la depuración y la eficiencia de la ejecución. Si ayuda a hacer el trabajo, entonces está bien. Por lo tanto, el propio Perl puede ser el mejor amigo o el peor enemigo de un programador. Si mezclar POO, FP y PP significa romper las reglas, ¿por qué alguien querría mezclar POO, FP y PP? Volvamos atrás y pensemos en esto. ¿Qué son OOP, FP y PP? Son simplemente métodos de programación, conjuntos de conceptos y reglas existentes que sirven a los equipos de programación. OOP, FP y PP son herramientas y el primer trabajo de todo programador es comprender sus herramientas. Si un programador no pudo usar la transformación Schwartziana de FP al ordenar hashes y en su lugar escribió su propia Sort::Hashtable, o no pudo reutilizar el módulo Sys::Hostname y en su lugar escribió código de procedimiento para obtener el nombre de host del sistema, entonces estos programadores pierden el tiempo. , energía y dinero, y reducen la calidad y confiabilidad del código. Un equipo de programación puede volverse complaciente con las herramientas que mejor conoce y eso puede ser lo peor que les puede pasar. Un equipo que utiliza sólo un subconjunto de las herramientas que se garantiza que estarán disponibles en una industria tan apasionante e innovadora como la programación informática está destinado a volverse inútil después de unos años. Los programadores deberían poder incorporar cualquier cosa que haga que su trabajo sea más eficiente, su código mejor y su equipo más innovador. Perl reconoce y fomenta esta actitud. Volver arriba Beneficios de la programación orientada a objetos Hay demasiados beneficios de la programación orientada a objetos para enumerarlos aquí. Como mencioné anteriormente, hay muchos libros sobre el tema. Algunos de estos beneficios son: facilidad de reutilización del código, mejoras en la calidad del código, interfaces consistentes y adaptabilidad. Debido a que la programación orientada a objetos se basa en clases y objetos, reutilizar el código OO significa simplemente importar clases cuando sea necesario. La reutilización de código es, con diferencia, la principal razón para utilizar la programación orientada a objetos y es la razón por la que la programación orientada a objetos está ganando importancia y popularidad en la industria actual. Hay algunas trampas aquí. Por ejemplo, en la situación actual, la solución al problema anterior puede haber sido subóptima y la biblioteca está tan mal documentada que comprender y utilizar una biblioteca mal documentada puede llevar tanto tiempo como reescribirla. Es trabajo del arquitecto del sistema ver y evitar estos errores. El uso de programación orientada a objetos mejora la calidad del código porque la encapsulación reduce la corrupción de datos ("fuego amigo"), mientras que la herencia y el polimorfismo reducen la cantidad y la complejidad del código nuevo que debe escribirse. Existe un delicado equilibrio entre la calidad del código y la innovación en la programación, que es mejor dejar que el equipo lo descubra, ya que depende completamente de la composición y el propósito del equipo. La herencia y reutilización de POO facilitan la implementación de interfaces consistentes en el código, pero no se puede decir que todo el código OO tenga interfaces consistentes. Los programadores todavía tienen que seguir una arquitectura común. Por ejemplo, el equipo debe acordar el formato y la interfaz para el registro de errores, preferiblemente a través de una interfaz de módulo de demostración que permita futuras extensiones y sea extremadamente fácil de usar. Sólo entonces todos los programadores podrán comprometerse a utilizar esa interfaz en lugar de imprimir declaraciones al azar, porque se darán cuenta de que el esfuerzo de aprender la interfaz no será en vano cuando aparezca la próxima función de registro de errores. La adaptabilidad es un concepto algo vago en programación.

Me gusta definirlo como aceptación y anticipación de cambios en el entorno y el uso. La adaptabilidad es importante para un software bien escrito porque todo software debe evolucionar con el mundo exterior. Un software bien escrito debería ser fácil de evolucionar. La programación orientada a objetos ayuda a que el software evolucione al garantizar que un nuevo sistema operativo o un nuevo formato de informes no requiera cambios fundamentales en el núcleo de la arquitectura a través de un diseño modular, una calidad de código mejorada e interfaces consistentes. Volver arriba Cómo utilizar la programación orientada a objetos en Perl Lo creas o no, la programación orientada a objetos en Perl no es difícil para usuarios principiantes e intermedios, y ni siquiera es tan complicado para usuarios avanzados. Según lo que hemos discutido hasta ahora sobre las complejas formas en que funciona la programación orientada a objetos, es posible que no lo creas así. Sin embargo, Perl se complace en imponer la menor cantidad posible de restricciones a los programadores. Perl OOP es como una barbacoa (perdón por la metáfora). Cada uno trae su propia carne y la asa a su gusto. Incluso el espíritu de equipo de la barbacoa es así, al igual que los datos se pueden compartir fácilmente entre objetos no relacionados. El primer paso que debemos dar es entender los paquetes Perl. Los paquetes son similares a los espacios de nombres en C++ y las bibliotecas en Java: como vallas utilizadas para restringir los datos a un área específica. Sin embargo, los paquetes de Perl sólo ofrecen sugerencias para programadores. Por defecto, Perl no restringe el intercambio de datos entre paquetes (aunque los programadores pueden hacerlo mediante variables léxicas).

Listado 1. Nombres de paquetes, cambio de paquetes, intercambio de datos entre paquetes y variables de paquete #!/usr/bin/perl # nota: el siguiente código generará advertencias con el parámetro -w, # y ni siquiera se compilará con "use estricto". Está destinado a demostrar # el paquete y las variables léxicas. Siempre debes "usar estricto". # ¡presta atención a cada línea! # esta es una variable de paquete global; no deberías tener ninguna con "usar estricto" # it está implícitamente en el paquete llamado "main" $global_sound = " "; paquete Cow; # el paquete Cow comienza aquí # esta es una variable de paquete, accesible desde cualquier otro paquete como $Cow::sound $sound = " moo" #; esta es una variable léxica, accesible desde cualquier lugar de este archivo my $extra_sound = "sampede package Pig" el paquete Pig comienza, Cow termina # esta es una variable de paquete, accesible desde cualquier otro paquete como $Pig: :sound $Pig ::sound = "oink"; $::global_sound = "los cerdos lo hacen mejor"; # otra variable del paquete "principal" # volvemos al paquete predeterminado (principal) print "Las vacas van : ", $ Vaca::sonido; # imprime "muu" print "\nLos cerdos van: ", $Cerdo::sonido; # imprime "oink" print "\nSonido extra: ", $extra_sound; Escucho: ", $sonido; # $main::¡el sonido no está definido! print "\nTodos dicen: ", $global_sound; # imprime "los cerdos lo hacen mejor" Tenga en cuenta que esto se puede usar en los tres Acceda al archivo con alcance variable léxica $extra_sound en paquetes ("main", "Pig" y "Cow") porque en este ejemplo están definidos en el mismo archivo. Normalmente, cada paquete se define dentro de su propio archivo para garantizar que las variables léxicas sean privadas de ese paquete. Esto permite la encapsulación. (Para obtener más detalles, ejecute "perldoc perlmod".) A continuación, queremos asociar el paquete con la clase. En lo que respecta a Perl, una clase es sólo un paquete elegante (por el contrario, los objetos se crean especialmente mediante la función bless()). Del mismo modo, Perl aplica reglas de programación orientada a objetos de manera laxa para que los programadores no estén sujetos a ellas.

El método new() es el nombre idiomático de un constructor de clase (aunque en la forma informal y habitual de Perl, puedes usar cualquier nombre). Se llama cada vez que se crea una instancia de una clase en un objeto. Listado 2. clase barebones #!/usr/bin/perl -w paquete Barebones; use estricto; # esta clase no toma parámetros de constructor sub new { my $classname = shift; # conocemos el nombre de nuestra clase bless {}, $classname; # y bendito sea un hash anónimo } 1; Puedes probar el código en el Listado 2 colocándolo en un archivo llamado Barebones.pm en cualquier directorio y luego ejecutando el siguiente comando en ese directorio (esto significa: "En la biblioteca incluye el actual directorio en la ruta, use el módulo Barebones y cree un nuevo objeto Barebones"): perl -I. -MBarebones -e 'my $b = Barebones->new()' Por ejemplo, puede ingresar una declaración impresa en vea lo que contiene la variable $classname. Si llama a Barebones::new() en lugar de Barebones->new() , el nombre de la clase no se pasará a new() . En otras palabras, new() no actuará como un constructor, sino simplemente como una función normal. Quizás se pregunte: ¿por qué necesita pasar $classname? ¿Por qué no utilizar bless {}, "Barebones"; Debido a la herencia, este constructor puede ser llamado por una clase que hereda de Barebones pero que no se llama Barebones. Es posible que tenga algo incorrecto con el nombre incorrecto y, en programación orientada a objetos, es una mala idea. Además de new(), cada clase requiere datos y métodos de miembros. Definirlos es tan sencillo como escribir algunos procedimientos. Listado 3. Clase con datos y métodos de miembros #!/usr/bin/perl -w package Barebones; use estricto; my $count = 0; # esta clase no toma parámetros de constructor sub new { my $classname = shift # lo sabemos; nuestro nombre de clase $count++; # recuerda cuántos objetos bendice {}, $classname; # y bendice un hash anónimo } sub count { my $self = shift; # este es el objeto en sí return $count } 1; codifique con: perl -I. -MBarebones -e 'my $b = Barebones->new(); Barebones->new(); print $b->count' Debería obtener '2'. El constructor se llama dos veces y modifica la variable léxica ($count), que está restringida al alcance del paquete Barebones, no al alcance de cada objeto Barebones. Los datos dentro del alcance del objeto deben almacenarse en el propio objeto. En el ejemplo de Barebones, lo que se comparte como objeto es un hash anónimo. Observe cómo podemos acceder al objeto cada vez que se llaman sus métodos, ya que una referencia al objeto es el primer argumento que se pasa a esos métodos.

Hay varios métodos especiales, como DESTROY() y AUTOLOAD(), que Perl llama automáticamente bajo ciertas condiciones. AUTOLOAD() es un método general que se utiliza para permitir nombres de métodos dinámicos. DESTROY() es un destructor de objetos, pero no deberías usarlo a menos que realmente lo necesites. El uso de destructores en Perl generalmente indica que todavía estás pensando como un programador de C/C++. Veamos la herencia. Haga esto en Perl cambiando la variable @ISA. Simplemente asigna una lista de nombres de clases a la variable. Eso es todo. Puedes poner cualquier cosa en @ISA. Puedes hacer de tu clase una subclase de Satanás. A Perl no le importa (aunque a su pastor, ministro, imán, erudito judío, etc. probablemente sí le importe). Listado 4. Herencia #!/usr/bin/perl -w paquete Barebones; # agregue estas líneas al comienzo de su módulo, antes de que otro código o # declaraciones de variables requieran Animal; somos hijos de Animal # tenga en cuenta que @ISA se dejó como una variable predeterminada global y "use # estricto" viene después de su declaración. Esa es la forma más fácil de hacerlo. use estricto # haga su nuevo (. ) el método se ve así: sub new { my $proto = shift; my $class = ref($proto) || my $self = $class->SUPER::new(); ) método bless ($self, $class); # pero bendice $self (un animal) como Barebones } 1; Hay mucho más en el lenguaje Perl que deberías explorar. Se han escrito muchos libros sobre este tema. Si desea leerlo, consulte Recursos. Volver arriba h2xs: Su nuevo mejor amigo ¿No preferiría tener una herramienta que pudiera escribir clases de Perl para usted, también escribir marcos de documentación (POD) y, en general, hacerle la vida un poco más fácil al hacer esas cosas correctamente? Perl viene con una herramienta de este tipo: h2xs. No olvide utilizar algunas opciones importantes: "-A -n Module". Usando estos indicadores, h2xs generará un directorio de marco llamado "Módulo" lleno de archivos útiles. Estos archivos son: Module.pm, el módulo en sí, con la documentación del marco ya escrita. Module.xs, utilizado para vincular su módulo con código C. (Para obtener más detalles, ejecute "perldoc perlxs".) MANIFEST, una lista de archivos para empaquetar. test.pl, script de prueba del marco. Cambios, un registro de los cambios realizados en este módulo. Makefile.PL, el generador de archivos MAKE (ejecútelo con " perl Makefile.PL ".) No necesita utilizar todos estos archivos, pero es bueno saber que estarán ahí cuando los necesite.