La programación orientada a objetos ( POO ) es un paradigma de programación basado en el concepto de objetos , [1] que pueden contener datos y código : datos en forma de campos (a menudo conocidos como atributos o propiedades ), y código en forma de procedimientos (a menudo conocidos como métodos ). En la POO, los programas informáticos se diseñan a partir de objetos que interactúan entre sí. [2] [3]
Muchos de los lenguajes de programación más utilizados (como C++ , Java , [4] y Python ) son multiparadigma y admiten la programación orientada a objetos en mayor o menor grado, normalmente en combinación con programación imperativa , programación procedimental y programación funcional .
Los lenguajes orientados a objetos más importantes incluyen Ada , ActionScript , C++ , Common Lisp , C# , Dart , Eiffel , Fortran 2003 , Haxe , Java , [4] JavaScript , Kotlin , Logo , MATLAB , Objective-C , Object Pascal , Perl , PHP , Python , R , Raku , Ruby , Scala , SIMSCRIPT , Simula , Smalltalk , Swift , Vala y Visual Basic.NET .
La terminología que invoca "objetos" en el sentido moderno de la programación orientada a objetos hizo su primera aparición en el grupo de inteligencia artificial del MIT a finales de los años 1950 y principios de los 1960. "Objeto" se refería a átomos de LISP con propiedades identificadas (atributos). [5] [6] Otro ejemplo temprano del MIT fue Sketchpad creado por Ivan Sutherland en 1960-1961; en el glosario del informe técnico de 1963 basado en su disertación sobre Sketchpad, Sutherland definió las nociones de "objeto" e "instancia" (con el concepto de clase cubierto por "maestro" o "definición"), aunque especializado en la interacción gráfica. [7] Además, en 1968, una versión de ALGOL del MIT , AED-0, estableció un vínculo directo entre las estructuras de datos ("plexes", en ese dialecto) y los procedimientos, prefigurando lo que más tarde se denominaría "mensajes", "métodos" y "funciones miembro". [8] [9] Temas como la abstracción de datos y la programación modular fueron puntos de discusión comunes en esta época.
Independientemente del trabajo posterior del MIT, como AED, Simula se desarrolló durante los años 1961-1967. [8] Simula introdujo conceptos importantes que hoy son una parte esencial de la programación orientada a objetos, como clase y objeto , herencia y enlace dinámico . [10] El lenguaje de programación orientado a objetos Simula fue utilizado principalmente por investigadores involucrados con el modelado físico , como modelos para estudiar y mejorar el movimiento de barcos y su contenido a través de puertos de carga. [10]
Pensé que los objetos eran como células biológicas y/o computadoras individuales en una red, capaces de comunicarse solo con mensajes (por eso la mensajería apareció desde el principio; llevó un tiempo ver cómo enviar mensajes en un lenguaje de programación lo suficientemente eficiente como para que fuera útil).
Alan Kay, [1]
Influenciado por el trabajo del MIT y el lenguaje Simula, en noviembre de 1966 Alan Kay comenzó a trabajar en ideas que eventualmente serían incorporadas al lenguaje de programación Smalltalk . Kay utilizó el término "programación orientada a objetos" en conversaciones ya en 1967. [1] Aunque a veces se le llama "el padre de la programación orientada a objetos", [11] Alan Kay ha diferenciado su noción de OO de la noción más convencional de tipo de datos abstractos de objeto, y ha dado a entender que el establishment de la ciencia informática no adoptó su noción. [1] Un memorándum del MIT de 1976 coescrito por Barbara Liskov enumera Simula 67 , CLU y Alphard como lenguajes orientados a objetos, pero no menciona a Smalltalk. [12]
En la década de 1970, Alan Kay , Dan Ingalls y Adele Goldberg desarrollaron la primera versión del lenguaje de programación Smalltalk en Xerox PARC . Smalltalk-72 incluía un entorno de programación y estaba tipado dinámicamente , y al principio era interpretado , no compilado . Smalltalk se hizo conocido por su aplicación de la orientación a objetos a nivel de lenguaje y su entorno de desarrollo gráfico. Smalltalk pasó por varias versiones y el interés en el lenguaje creció. [13] Si bien Smalltalk fue influenciado por las ideas introducidas en Simula 67, fue diseñado para ser un sistema completamente dinámico en el que las clases se podían crear y modificar dinámicamente. [14]
A finales de los años 1970 y 1980, la programación orientada a objetos cobró importancia. El Lisp orientado a objetos Flavors se desarrolló a partir de 1979, introduciendo la herencia múltiple y los mixins . [15] En 1981, Goldberg editó la edición de agosto de Byte Magazine , presentando Smalltalk y la programación orientada a objetos a una amplia audiencia. [16] LOOPS, el sistema de objetos para Interlisp -D, fue influenciado por Smalltalk y Flavors, y se publicó un artículo al respecto en 1982. [17] En 1986, la Association for Computing Machinery organizó la primera Conferencia sobre Programación, Sistemas, Lenguajes y Aplicaciones Orientadas a Objetos (OOPSLA), a la que asistieron 1000 personas. Entre otros desarrollos estuvo el Common Lisp Object System , que integra la programación funcional y la programación orientada a objetos y permite la extensión a través de un protocolo Meta-objeto . En la década de 1980, hubo algunos intentos de diseñar arquitecturas de procesador que incluyeran soporte de hardware para objetos en memoria, pero no tuvieron éxito. Algunos ejemplos incluyen el Intel iAPX 432 y el Linn Smart Rekursiv .
A mediados de la década de 1980, Brad Cox , que había utilizado Smalltalk en ITT Inc. , desarrolló Objective-C . Bjarne Stroustrup , que había utilizado Simula para su tesis doctoral, creó el lenguaje orientado a objetos C++ . [13] En 1985, Bertrand Meyer también produjo el primer diseño del lenguaje Eiffel . Centrado en la calidad del software, Eiffel es un lenguaje de programación puramente orientado a objetos y una notación que soporta todo el ciclo de vida del software. Meyer describió el método de desarrollo de software Eiffel, basado en un pequeño número de ideas clave de la ingeniería de software y la informática, en Object-Oriented Software Construction . [18] Esencial para el enfoque de calidad de Eiffel es el mecanismo de confiabilidad de Meyer, el diseño por contrato , que es una parte integral tanto del método como del lenguaje.
A principios y mediados de la década de 1990, la programación orientada a objetos se desarrolló como el paradigma de programación dominante cuando los lenguajes de programación que soportaban las técnicas se hicieron ampliamente disponibles. Estos incluyeron Visual FoxPro 3.0, [19] [20] C++ , [21] y Delphi [ cita requerida ] . Su dominio se vio reforzado aún más por la creciente popularidad de las interfaces gráficas de usuario , que dependen en gran medida de las técnicas de programación orientada a objetos. Un ejemplo de una biblioteca de GUI dinámica y un lenguaje OOP estrechamente relacionados se puede encontrar en los marcos Cocoa en Mac OS X , escritos en Objective-C , una extensión de mensajería dinámica orientada a objetos para C basada en Smalltalk. Los kits de herramientas OOP también aumentaron la popularidad de la programación basada en eventos (aunque este concepto no se limita a la OOP).
En la ETH de Zúrich , Niklaus Wirth y sus colegas investigaron el concepto de verificación de tipos a través de los límites de los módulos. Modula-2 (1978) incluyó este concepto, y su diseño posterior, Oberon (1987), incluyó un enfoque distintivo para la orientación a objetos, clases y demás. La herencia no es obvia en el diseño de Wirth, ya que su nomenclatura mira en la dirección opuesta: se llama extensión de tipo y el punto de vista va desde el padre hasta el heredero.
Se han añadido características orientadas a objetos a muchos lenguajes que ya existían, como Ada , BASIC , Fortran , Pascal y COBOL . Añadir estas características a lenguajes que no estaban diseñados inicialmente para ellas solía generar problemas de compatibilidad y mantenimiento del código.
Más recientemente, han surgido algunos lenguajes que son principalmente orientados a objetos, pero que también son compatibles con la metodología procedimental. Dos de estos lenguajes son Python y Ruby . Probablemente los lenguajes orientados a objetos recientes más importantes comercialmente sean Java , desarrollado por Sun Microsystems , así como C# y Visual Basic.NET (VB.NET), ambos diseñados para la plataforma .NET de Microsoft . Cada uno de estos dos marcos muestra, a su manera, el beneficio de usar OOP al crear una abstracción a partir de la implementación. VB.NET y C# admiten la herencia entre lenguajes, lo que permite que las clases definidas en un lenguaje creen subclases de las clases definidas en el otro lenguaje.
La programación orientada a objetos utiliza objetos, pero no todas las técnicas y estructuras asociadas se admiten directamente en lenguajes que afirman admitir la programación orientada a objetos. Las características que se enumeran a continuación son comunes entre los lenguajes considerados como fuertemente orientados a clases y objetos (o multiparadigma con soporte para programación orientada a objetos), con notables excepciones mencionadas. [22] [23] [24] [25] Christopher J. Date afirmó que la comparación crítica de la programación orientada a objetos con otras tecnologías, en particular la relacional, es difícil debido a la falta de una definición acordada y rigurosa de la programación orientada a objetos. [26]
La compatibilidad con la programación modular permite agrupar procedimientos en archivos y módulos con fines organizativos. Los módulos tienen espacios de nombres para que los identificadores de un módulo no entren en conflicto con un procedimiento o una variable que compartan el mismo nombre en otro archivo o módulo.
Un objeto es una estructura de datos o un tipo de datos abstracto que contiene campos ( variables de estado que contienen datos) y métodos ( subrutinas o procedimientos que definen el comportamiento del objeto en el código). Los campos también pueden conocerse como miembros, atributos o propiedades. Los objetos se almacenan normalmente como regiones contiguas de memoria . Se accede a los objetos de forma similar a las variables con estructuras internas complejas y, en muchos lenguajes, son efectivamente punteros , que sirven como referencias reales a una única instancia de dicho objeto en la memoria dentro de un montón o pila.
Los objetos a veces corresponden a cosas que se encuentran en el mundo real. [27] Por ejemplo, un programa de gráficos puede tener objetos como "círculo", "cuadrado" y "menú". Un sistema de compras en línea puede tener objetos como "carrito de compras", "cliente" y "producto". A veces, los objetos representan entidades más abstractas, como un objeto que representa un archivo abierto o un objeto que proporciona el servicio de traducir medidas del sistema métrico decimal al sistema métrico de EE. UU.
Los objetos pueden contener otros objetos en sus variables de instancia; esto se conoce como composición de objetos . Por ejemplo, un objeto en la clase Employee puede contener (ya sea directamente o a través de un puntero) un objeto en la clase Address, además de sus propias variables de instancia como "first_name" y "position". La composición de objetos se utiliza para representar relaciones "tiene un": cada empleado tiene una dirección, por lo que cada objeto Employee tiene acceso a un lugar para almacenar un objeto Address (ya sea directamente incrustado dentro de sí mismo o en una ubicación separada a la que se accede a través de un puntero). Date y Darwen han propuesto una base teórica que utiliza OOP como una especie de sistema de tipos personalizable para soportar RDBMS , pero prohíbe los punteros a objetos. [28]
El paradigma OOP ha sido criticado por enfatizar demasiado el uso de objetos para el diseño y modelado de software a expensas de otros aspectos importantes (computación/algoritmos). [29] [30] Por ejemplo, Rob Pike ha dicho que los lenguajes OOP frecuentemente cambian el enfoque de las estructuras de datos y algoritmos a los tipos . [31] Steve Yegge señaló que, a diferencia de la programación funcional : [32]
La programación orientada a objetos pone a los sustantivos en primer lugar. ¿Por qué tomarse tantas molestias para poner una parte del discurso en un pedestal? ¿Por qué un tipo de concepto debería tener prioridad sobre otro? No es que la programación orientada a objetos haya hecho que los verbos pierdan importancia de repente en nuestra forma de pensar. Es una perspectiva extrañamente sesgada.
Rich Hickey , creador de Clojure , describió los sistemas de objetos como modelos demasiado simplistas del mundo real. Hizo hincapié en la incapacidad de la programación orientada a objetos para modelar el tiempo de forma adecuada, lo que se está volviendo cada vez más problemático a medida que los sistemas de software se vuelven más concurrentes. [30]
Alexander Stepanov compara desfavorablemente la orientación a objetos con la programación genérica : [29]
Considero que la programación orientada a objetos es técnicamente errónea. Intenta descomponer el mundo en términos de interfaces que varían en función de un único tipo. Para abordar los problemas reales se necesitan álgebras multiclasificadas, es decir, familias de interfaces que abarcan múltiples tipos. Considero que la programación orientada a objetos es filosóficamente errónea. Afirma que todo es un objeto. Incluso si fuera cierto, no es muy interesante: decir que todo es un objeto es no decir nada en absoluto.
Los lenguajes OOP son diversos, pero por lo general permiten la herencia para la reutilización y extensibilidad del código en forma de clases o prototipos . Estas formas de herencia son significativamente diferentes, pero se utiliza una terminología análoga para definir los conceptos de objeto e instancia .
En la programación basada en clases , el estilo más popular, se requiere que cada objeto sea una instancia de una clase particular . La clase define el formato o tipo de datos (incluidas las variables miembro y sus tipos) y los procedimientos disponibles (métodos de clase o funciones miembro) para un tipo o clase de objeto determinado. Los objetos se crean llamando a un tipo especial de método en la clase conocido como constructor . Las clases pueden heredar de otras clases, por lo que se organizan en una jerarquía que representa relaciones de "es-un-tipo-de". Por ejemplo, la clase Empleado puede heredar de la clase Persona. Todos los datos y métodos disponibles para la clase principal también aparecen en la clase secundaria con los mismos nombres. Por ejemplo, la clase Persona puede definir las variables "nombre" y "apellido" con el método "make_full_name()". Estas también estarán disponibles en la clase Empleado, que puede agregar las variables "posición" y "salario". Se garantiza que todas las instancias de la clase Empleado tendrán las mismas variables, como el nombre, la posición y el salario. Los procedimientos y las variables pueden ser específicos de la clase o de la instancia; Esto nos lleva a los siguientes términos:
Dependiendo de la definición del lenguaje, las subclases pueden o no ser capaces de anular los métodos definidos por las superclases. La herencia múltiple está permitida en algunos lenguajes, aunque esto puede hacer que la resolución de anulaciones sea complicada. Algunos lenguajes tienen soporte especial para otros conceptos como rasgos y mixins , aunque, en cualquier lenguaje con herencia múltiple, un mixin es simplemente una clase que no representa una relación de tipo "es-un-tipo-de". Los mixins se usan típicamente para agregar los mismos métodos a múltiples clases. Por ejemplo, la clase UnicodeConversionMixin podría proporcionar un método unicode_to_ascii() cuando se incluye en la clase FileReader y la clase WebPageScraper, que no comparten un padre común.
Las clases abstractas no pueden instanciarse en objetos; existen sólo para la herencia en otras clases "concretas" que sí pueden instanciarse. En Java, la final
palabra clave puede utilizarse para evitar que una clase se subclasifique. [33]
En cambio, en la programación basada en prototipos , los objetos son las entidades primarias. Generalmente, el concepto de una "clase" ni siquiera existe. Más bien, el prototipo o padre de un objeto es simplemente otro objeto al que el objeto está vinculado. En Self, un objeto puede tener varios padres o ninguno, [34] pero en el lenguaje basado en prototipos más popular, Javascript, cada objeto tiene un vínculo de prototipo (y solo uno). Se pueden crear nuevos objetos basados en objetos ya existentes elegidos como su prototipo. Puede llamar a dos objetos diferentes manzana y naranja una fruta si el objeto fruta existe, y tanto manzana como naranja tienen fruta como su prototipo. La idea de la clase fruta no existe explícitamente, pero se puede modelar como la clase de equivalencia de los objetos que comparten el mismo prototipo, o como el conjunto de objetos que satisfacen una cierta interfaz ( tipado de pato ). A diferencia de la programación basada en clases, normalmente es posible en los lenguajes basados en prototipos definir atributos y métodos que no se comparten con otros objetos; por ejemplo, el atributo sugar_content se puede definir en manzana pero no en naranja .
Algunos lenguajes como Go no admiten la herencia en absoluto. Go afirma que está orientado a objetos [35] y Bjarne Stroustrup, autor de C++, ha afirmado que es posible hacer programación orientada a objetos sin herencia [36] . La doctrina de la composición sobre la herencia aboga por implementar relaciones de tipo tiene un usando la composición en lugar de la herencia. Por ejemplo, en lugar de heredar de la clase Persona, la clase Empleado podría dar a cada objeto Empleado un objeto Persona interno, que luego tendría la oportunidad de ocultar del código externo incluso si la clase Persona tiene muchos atributos o métodos públicos. La delegación es otra característica del lenguaje que se puede usar como alternativa a la herencia.
Rob Pike ha criticado la mentalidad OO por preferir una jerarquía de tipos multinivel con abstracciones en capas a una tabla de búsqueda de tres líneas . [37] Ha llamado a la programación orientada a objetos "los números romanos de la informática". [38]
Bob Martin afirma que, debido a que son software, las clases relacionadas no necesariamente comparten las relaciones de las cosas que representan. [39]
Es responsabilidad del objeto, no de ningún código externo, seleccionar el código procedimental que se ejecutará en respuesta a una llamada de método, normalmente buscando el método en tiempo de ejecución en una tabla asociada con el objeto. Esta característica se conoce como despacho dinámico . Si la variabilidad de la llamada depende de más que el tipo único del objeto en el que se llama (es decir, al menos otro objeto de parámetro está involucrado en la elección del método), se habla de despacho múltiple . Una llamada de método también se conoce como paso de mensajes . Se conceptualiza como un mensaje (el nombre del método y sus parámetros de entrada) que se pasa al objeto para su envío.
El envío interactúa con la herencia; si un método no está presente en un objeto o clase determinados, el envío se delega a su objeto o clase padre, y así sucesivamente, subiendo por la cadena de herencia.
La abstracción de datos es un patrón de diseño en el que los datos son visibles solo para funciones relacionadas semánticamente, para evitar un uso indebido. El éxito de la abstracción de datos conduce a la incorporación frecuente de la ocultación de datos como un principio de diseño en la programación funcional pura y orientada a objetos. De manera similar, la encapsulación evita que el código externo se ocupe del funcionamiento interno de un objeto. Esto facilita la refactorización del código , por ejemplo, permitiendo al autor de la clase cambiar la forma en que los objetos de esa clase representan sus datos internamente sin cambiar ningún código externo (siempre que las llamadas a métodos "públicos" funcionen de la misma manera). También alienta a los programadores a poner todo el código que se relaciona con un determinado conjunto de datos en la misma clase, lo que lo organiza para que otros programadores lo comprendan fácilmente. La encapsulación es una técnica que fomenta el desacoplamiento .
En la programación orientada a objetos, los objetos proporcionan una capa que se puede utilizar para separar el código interno del externo e implementar la abstracción y la encapsulación. El código externo solo puede utilizar un objeto llamando a un método de instancia específico con un determinado conjunto de parámetros de entrada, leyendo una variable de instancia o escribiendo en una variable de instancia. Un programa puede crear muchas instancias de objetos a medida que se ejecuta, que operan de forma independiente. Se afirma que esta técnica permite una fácil reutilización de los mismos procedimientos y definiciones de datos para diferentes conjuntos de datos, además de reflejar potencialmente las relaciones del mundo real de forma intuitiva. En lugar de utilizar tablas de bases de datos y subrutinas de programación, el desarrollador utiliza objetos con los que el usuario puede estar más familiarizado: objetos de su dominio de aplicación. [40] Estas afirmaciones de que el paradigma OOP mejora la reutilización y la modularidad han sido criticadas. [41] [42]
Se recomienda que el diseño inicial utilice la visibilidad más restrictiva posible, en orden de variables locales (o de método), variables privadas (en programación orientada a objetos) y variables globales (o públicas), y que solo se amplíe cuando sea necesario. Esto evita que los cambios en la visibilidad invaliden el código existente. [43]
Si una clase no permite llamar a código para acceder a los datos internos de un objeto y permite el acceso solo a través de métodos, también se trata de una forma de ocultar información. Algunos lenguajes (Java, por ejemplo) permiten que las clases impongan restricciones de acceso explícitamente, por ejemplo, denotando datos internos con la private
palabra clave y designando métodos destinados a ser utilizados por código fuera de la clase con la public
palabra clave. [44] Los métodos también pueden diseñarse como públicos, privados o de nivel intermedio como protected
(que permite el acceso desde la misma clase y sus subclases, pero no a objetos de una clase diferente). [44] En otros lenguajes (como Python) esto se aplica solo por convención (por ejemplo, private
los métodos pueden tener nombres que comiencen con un guión bajo ). En los lenguajes C#, Swift y Kotlin, internal
la palabra clave permite el acceso solo a archivos presentes en el mismo ensamblaje, paquete o módulo que el de la clase. [45]
En los lenguajes de programación, en particular los orientados a objetos, el énfasis en la abstracción es vital. Los lenguajes orientados a objetos amplían la noción de tipo para incorporar la abstracción de datos, destacando la importancia de restringir el acceso a los datos internos a través de métodos. [46] Eric S. Raymond ha escrito que los lenguajes de programación orientados a objetos tienden a fomentar programas con capas densas que destruyen la transparencia. [ 47] Raymond compara esto desfavorablemente con el enfoque adoptado con Unix y el lenguaje de programación C. [47]
El " principio abierto/cerrado " defiende que las clases y funciones "deberían estar abiertas a la extensión, pero cerradas a la modificación". Luca Cardelli ha afirmado que los lenguajes OOP tienen "propiedades de modularidad extremadamente pobres con respecto a la extensión y modificación de clases", y tienden a ser extremadamente complejos. [41] Este último punto es reiterado por Joe Armstrong , el principal inventor de Erlang , quien es citado diciendo: [42]
El problema con los lenguajes orientados a objetos es que tienen todo este entorno implícito que llevan consigo. Querías un plátano, pero lo que conseguiste fue un gorila sosteniendo el plátano y toda la jungla.
Leo Brodie ha sugerido una conexión entre la naturaleza independiente de los objetos y una tendencia a duplicar el código [48] en violación del principio de no repetirse [49] del desarrollo de software.
La subtipificación , una forma de polimorfismo , se produce cuando el código de llamada puede ser independiente de la clase en la jerarquía admitida en la que opera: la clase principal o una de sus descendientes. Mientras tanto, el mismo nombre de operación entre objetos en una jerarquía de herencia puede comportarse de manera diferente.
Por ejemplo, los objetos del tipo Circle y Square se derivan de una clase común llamada Shape. La función Draw para cada tipo de Shape implementa lo necesario para dibujarse a sí misma, mientras que el código de llamada puede permanecer indiferente al tipo particular de Shape que se está dibujando.
Este es otro tipo de abstracción que simplifica el código externo a la jerarquía de clases y permite una fuerte separación de preocupaciones .
Una característica común de los objetos es que los métodos están asociados a ellos y pueden acceder y modificar los campos de datos del objeto. En este tipo de programación orientada a objetos, normalmente hay un nombre especial como thiso self
que se utiliza para hacer referencia al objeto actual. En los lenguajes que admiten la recursión abierta , los métodos de objeto pueden llamar a otros métodos en el mismo objeto (incluidos ellos mismos) utilizando este nombre. Esta variable está enlazada en tiempo real ; permite que un método definido en una clase invoque otro método que se define más tarde, en alguna subclase de la misma.
Simula (1967) es generalmente aceptado como el primer lenguaje con las características primarias de un lenguaje orientado a objetos. Fue creado para realizar programas de simulación , en los que lo que se dio en llamar objetos eran la representación de información más importante. Smalltalk (1972 a 1980) es otro ejemplo temprano y con el que se desarrolló gran parte de la teoría de la POO. En cuanto al grado de orientación a objetos, se pueden hacer las siguientes distinciones:
Muchos lenguajes ampliamente utilizados, como C++, Java y Python, proporcionan características orientadas a objetos. Aunque en el pasado la programación orientada a objetos era ampliamente aceptada, [51] más recientemente los ensayos que critican la programación orientada a objetos y recomiendan evitar estas características (generalmente a favor de la programación funcional ) han sido muy populares en la comunidad de desarrolladores. [52] Paul Graham ha sugerido que la popularidad de la programación orientada a objetos dentro de las grandes empresas se debe a "grupos grandes (y frecuentemente cambiantes) de programadores mediocres". Según Graham, la disciplina impuesta por la programación orientada a objetos evita que cualquier programador "haga demasiado daño". [53] Eric S. Raymond , un programador de Unix y defensor del software de código abierto , ha criticado las afirmaciones que presentan la programación orientada a objetos como la "única solución verdadera". [47]
Richard Feldman sostiene que estos lenguajes pueden haber mejorado su modularidad al añadir características OO, pero se hicieron populares por razones distintas a la de estar orientados a objetos. [54] En un artículo, Lawrence Krubner afirmó que, en comparación con otros lenguajes (dialectos LISP, lenguajes funcionales, etc.), los lenguajes OOP no tienen puntos fuertes únicos e imponen una gran carga de complejidad innecesaria. [55] Un estudio de Potok et al. no ha demostrado ninguna diferencia significativa en productividad entre los enfoques OOP y procedimentales. [56] Luca Cardelli ha afirmado que el código OOP es "intrínsecamente menos eficiente" que el código procedimental y que el OOP puede tardar más en compilarse. [41]
En los últimos años, la programación orientada a objetos se ha vuelto especialmente popular en los lenguajes de programación dinámicos . Python , PowerShell , Ruby y Groovy son lenguajes dinámicos construidos sobre principios de programación orientada a objetos, mientras que Perl y PHP han ido añadiendo características orientadas a objetos desde Perl 5 y PHP 4, y ColdFusion desde la versión 6.
El modelo de objetos de documento de los documentos HTML , XHTML y XML en Internet tiene enlaces al popular lenguaje JavaScript / ECMAScript . JavaScript es quizás el lenguaje de programación basado en prototipos más conocido , que emplea la clonación a partir de prototipos en lugar de heredar de una clase (a diferencia de la programación basada en clases ). Otro lenguaje de programación que adopta este enfoque es Lua .
Los mensajes que fluyen entre computadoras para solicitar servicios en un entorno cliente-servidor pueden diseñarse como linealizaciones de objetos definidos por objetos de clase conocidos tanto por el cliente como por el servidor. Por ejemplo, un objeto linealizado simple constaría de un campo de longitud, un punto de código que identifica la clase y un valor de datos. Un ejemplo más complejo sería un comando que constaría de la longitud y el punto de código del comando y valores que constarían de objetos linealizados que representan los parámetros del comando. Cada uno de estos comandos debe ser dirigido por el servidor a un objeto cuya clase (o superclase) reconozca el comando y pueda proporcionar el servicio solicitado. Los clientes y servidores se modelan mejor como estructuras complejas orientadas a objetos. La Arquitectura de Gestión de Datos Distribuidos (DDM) adoptó este enfoque y utilizó objetos de clase para definir objetos en cuatro niveles de una jerarquía formal:
La versión inicial de DDM definía los servicios de archivos distribuidos. Posteriormente se amplió para convertirse en la base de la arquitectura de bases de datos relacionales distribuidas (DRDA).
Una forma de abordar los desafíos del diseño orientado a objetos es mediante patrones de diseño , que son patrones de solución para problemas comunes en el diseño de software. Algunos de estos problemas comunes tienen implicaciones y soluciones específicas para el desarrollo orientado a objetos.
Los siguientes son patrones de diseño de software notables para objetos OOP. [57]
operator()
), actúa de manera muy similar a una función.Como ejemplo de un antipatrón de objeto , el objeto Dios sabe o hace demasiado.
Es intuitivo asumir que la herencia crea una relación semántica " es un ", y por lo tanto inferir que los objetos instanciados de subclases siempre se pueden usar de manera segura en lugar de los instanciados de la superclase. Esta intuición es, lamentablemente, falsa en la mayoría de los lenguajes OOP, en particular en todos aquellos que permiten objetos mutables . El polimorfismo de subtipos tal como lo aplica el verificador de tipos en lenguajes OOP (con objetos mutables) no puede garantizar la subtipificación conductual en ningún contexto. La subtipificación conductual es indecidible en general, por lo que no puede implementarse mediante un programa (compilador). Las jerarquías de clases u objetos deben diseñarse cuidadosamente, considerando posibles usos incorrectos que no se pueden detectar sintácticamente. Este problema se conoce como el principio de sustitución de Liskov .
Design Patterns: Elements of Reutilizable Object-Oriented Software es un influyente libro publicado en 1994 por Erich Gamma , Richard Helm , Ralph Johnson y John Vlissides , a los que a menudo se hace referencia humorísticamente como la "Banda de los Cuatro". Además de explorar las capacidades y los problemas de la programación orientada a objetos, describe 23 problemas de programación comunes y patrones para resolverlos.
El libro describe los siguientes patrones:
Tanto la programación orientada a objetos como los sistemas de gestión de bases de datos relacionales (RDBMS) son extremadamente comunes en el software actual [update]. Dado que las bases de datos relacionales no almacenan objetos directamente (aunque algunos RDBMS tienen características orientadas a objetos para aproximarse a esto), existe una necesidad general de unir los dos mundos. El problema de unir los accesos de la programación orientada a objetos y los patrones de datos con las bases de datos relacionales se conoce como desajuste de impedancia objeto-relacional . Hay algunos enfoques para hacer frente a este problema, pero no hay una solución general sin desventajas. [58] Uno de los enfoques más comunes es el mapeo objeto-relacional , como se encuentra en lenguajes IDE como Visual FoxPro y bibliotecas como Java Data Objects y Ruby on Rails ' ActiveRecord.
También existen bases de datos de objetos que pueden utilizarse para reemplazar a los RDBMS, pero no han tenido tanto éxito técnico y comercial como los RDBMS.
La programación orientada a objetos se puede utilizar para asociar objetos y procesos del mundo real con sus contrapartes digitales. Sin embargo, no todo el mundo está de acuerdo en que la programación orientada a objetos facilite el mapeo directo del mundo real o en que el mapeo del mundo real sea siquiera un objetivo digno; Bertrand Meyer sostiene en Object-Oriented Software Construction que un programa no es un modelo del mundo sino un modelo de alguna parte del mundo; "La realidad es un primo dos veces alejado". [59] Al mismo tiempo, se han señalado algunas limitaciones principales de la programación orientada a objetos. [60] Por ejemplo, el problema círculo-elipse es difícil de manejar utilizando el concepto de herencia de la programación orientada a objetos .
Sin embargo, Niklaus Wirth (quien popularizó el adagio ahora conocido como la ley de Wirth : "El software se vuelve más lento más rápidamente de lo que el hardware se vuelve más rápido") dijo de la POO en su artículo, "Buenas ideas a través del espejo", "Este paradigma refleja de cerca la estructura de los sistemas en el mundo real y, por lo tanto, es muy adecuado para modelar sistemas complejos con comportamiento complejo" [61] (contraste con el principio KISS ).
Steve Yegge y otros observaron que los lenguajes naturales carecen del enfoque OOP de priorizar estrictamente las cosas (objetos/ sustantivos ) antes que las acciones (métodos/ verbos ). [62] Este problema puede hacer que la OOP sufra soluciones más complicadas que la programación procedimental. [63]
La programación orientada a objetos se desarrolló para aumentar la reutilización y la capacidad de mantenimiento del código fuente. [64] La representación transparente del flujo de control no tenía prioridad y estaba destinada a ser manejada por un compilador. Con la creciente relevancia del hardware paralelo y la codificación multiproceso , el desarrollo de un flujo de control transparente se vuelve más importante, algo difícil de lograr con la programación orientada a objetos. [65] [66] [67] [68]
El diseño basado en la responsabilidad define las clases en términos de un contrato, es decir, una clase debe definirse en torno a una responsabilidad y la información que comparte. Wirfs-Brock y Wilkerson contrastan esto con el diseño basado en datos , en el que las clases se definen en torno a las estructuras de datos que deben contenerse. Los autores sostienen que el diseño basado en la responsabilidad es preferible.
SOLID es un mnemotécnico inventado por Michael Feathers que detalla cinco principios de diseño de ingeniería de software:
GRASP (Patrones de software de asignación de responsabilidad general) es otro conjunto de pautas defendidas por Craig Larman .
Los objetos son las entidades de tiempo de ejecución en un sistema orientado a objetos. Pueden representar una persona, un lugar, una cuenta bancaria, una tabla de datos o cualquier elemento que el programa tenga que manejar.
Se han hecho varios intentos de formalizar los conceptos utilizados en la programación orientada a objetos. Los siguientes conceptos y construcciones se han utilizado como interpretaciones de los conceptos de programación orientada a objetos:
Los intentos de encontrar una definición o teoría de consenso detrás de los objetos no han tenido mucho éxito (sin embargo, véase Abadi & Cardelli, A Theory of Objects [70] para definiciones formales de muchos conceptos y construcciones de OOP), y a menudo divergen ampliamente. Por ejemplo, algunas definiciones se centran en las actividades mentales y otras en la estructuración de programas. Una de las definiciones más simples es que OOP es el acto de usar estructuras de datos o matrices de "mapas" que pueden contener funciones y punteros a otros mapas, todo con algo de azúcar sintáctica y de alcance por encima. La herencia se puede realizar clonando los mapas (a veces llamado "creación de prototipos").
En la jerga local del MIT, las listas de asociación [de símbolos atómicos] también se denominan "listas de propiedades", y los símbolos atómicos a veces se denominan "objetos".
: sinónimo de símbolo atómico
la mayor fortaleza de un enfoque de desarrollo orientado a objetos es que ofrece un mecanismo que captura un modelo del mundo real.
Aunque Go tiene tipos y métodos y permite un estilo de programación orientado a objetos, no existe una jerarquía de tipos.
{{cite book}}
: CS1 maint: date and year (link)La programación orientada a objetos es un paradigma de programación ampliamente aceptado.