¿Realmente necesitamos lenguajes OO para gestionar la complejidad del software?

209

Esta será una pregunta muy poco técnica y no técnica, y no estoy seguro de si esta es la plataforma correcta. Pero soy un estudiante principiante de CS, así que espero que lo toleren.

En el primer semestre, nos presentaron conceptos OOP como encapsulación, ocultación de datos, modularidad, herencia, etc. a través de Java y UML. (Java es mi primer lenguaje de programación)

Según tengo entendido, OOP es una forma de gestionar la complejidad del software. Pero sus principios no son nuevos ni únicos, son en cierto sentido universales para todos los campos de ingeniería.

Por ejemplo, un automóvil es una estructura muy compleja cuya complejidad es manejada por una jerarquía de componentes modulares y encapsulados con comportamientos e interfaces bien definidos.

Pero no entiendo la razón detrás de la introducción de un nuevo paradigma de programación. Creo que todos los principios utilizados para gestionar la complejidad pueden realizarse mediante lenguajes de programación de procedimientos. Por ejemplo, para modularidad, podemos dividir el programa en muchos programas pequeños que realizan tareas bien definidas cuyo código está contenido en archivos separados. Estos programas interactuarían entre sí a través de sus entradas y salidas bien definidas. Los archivos pueden estar protegidos (¿cifrados?) Para lograr la encapsulación. Para la reutilización del código, podemos llamar a esos archivos siempre que sean necesarios en nuevos programas. ¿Esto no captura todo lo que es OOP o me estoy perdiendo algo muy obvio?

No estoy pidiendo una prueba de que OOP maneja la complejidad. En mi opinión, ciertamente lo hace. Pero creo que todos los principios utilizados para gestionar la complejidad, como la modularidad, la encapsulación, la ocultación de datos, etc., pueden implementarse muy fácilmente mediante lenguajes de procedimiento. Entonces, ¿por qué realmente OOP si podemos gestionar la complejidad sin ella?

intercambio de steake
fuente
41
Te falta la separación de la interfaz y la implementación. Poder intercambiar una implementación por otra en tiempo de ejecución es una característica muy importante. Básicamente, esto se logra mediante el método dinámico de despacho de lenguajes OO con herencia. Los lenguajes de procedimiento también pueden hacer eso (léase: punteros nulos), pero sin tipo de seguridad.
marstato
81
En gran medida, la idea de los lenguajes y el diseño orientados a objetos es precisamente hacer que esos conceptos universales e intuitivos sean lo más fáciles de representar y recrear en código. Si tuviera un esquema o un conjunto de pautas sobre cómo lograr todas esas cosas sin un lenguaje inherentemente orientado a objetos, entonces sus propuestas sobre cómo hacer las cosas serían efectivamente la metodología orientada a objetos utilizada. Los lenguajes reales de OO son solo una forma de formalizar y simplificar eso.
Standback
14
@RobbieDee, ¿has leído mi pregunta? Se trata de tratar de entender OO en un nivel más fundamental al cuestionar el clima, la complejidad del software se puede gestionar sin OO. No estoy tratando de socavar OO, no estoy tratando de inventar algo nuevo, solo estoy tratando de entenderlo mejor y si la pregunta es tan 'evidente', ¿por qué recibió la excelente respuesta de Jorg?
steakexchange
12
Cifrar un archivo no es encapsulación. Es posible que haya ocultado ver el contenido del código de otro desarrollador, pero no necesariamente ha protegido el funcionamiento interno del código de otro código. El autor original podría hacer esto antes o después del cifrado si puede recordar cómo.
JeffO
8
No necesita nada más que lenguaje de máquina: deje que el programador memorice los códigos de operación y escriba los mismos y los ceros. Pero tener algún tipo de lenguaje "simbólico" es muy útil en términos de reducir errores y aumentar la productividad, y, como observó Dijkstra, un lenguaje que impone cierta "estructura" (o al menos facilita el mantenimiento de la "estructura"). Los idiomas OO pueden no ser la tecnología ideal, dado el nivel actual de sofisticación del idioma, pero son bastante buenos para muchas aplicaciones. La idea es gestionar la complejidad sin interponerse en su camino.
Daniel R Hicks

Respuestas:

177

Déjame probar con una respuesta teórica realmente baja :)

Lo que realmente está preguntando es: ¿Por qué incluir soporte para la Orientación de Objetos (OO) directamente en el lenguaje cuando se pueden usar lenguajes de procedimiento para diseñar y escribir código OO?

Y la respuesta es: tener un estándar sobre cómo se expresa OO en el código fuente para no terminar con 22 implementaciones diferentes para la misma abstracción.

Por ejemplo, supongamos que creo una MagicButtony una MagicSliderque se puede utilizar en un sistema de interfaz de usuario. Necesito una forma de agrupar los métodos que pueden usarse con MagicButton, los métodos que solo pueden usarse con MagicSlider y los métodos que pueden usar ambos. Estos objetos comparten algunos métodos porque ambos son objetos Magic gui.

Puedo agrupar nombrando funciones de una manera especial MagicSlider_DoSomething ..., incluyendo los métodos en archivos específicos nombrados de una manera especial MagicSliderMethods.XXX, o podría encontrar alguna otra forma especial de hacer lo mismo. Si no hay una forma estándar en el idioma para hacerlo, lo haré diferente de usted y de cualquier otra persona. Esto hace que compartir código sea mucho más difícil.

Sí, el envío tardío (métodos virtuales en lenguajes OO) puede implementarse en lenguajes de procedimiento, pero hay muchas formas diferentes de implementarlo. Dependiendo de quién escribió el código, terminará con diferentes implementaciones de OO dentro del mismo programa.

Piensa en el pobre desarrollador de mantenimiento. Esta persona debe administrar diferentes abstracciones de objetos y diferentes formas de llamar a métodos virtuales dependiendo de quién escribió el código original.

Además: tener las abstracciones en el lenguaje permite a los editores de código avanzados como Eclipse realizar muchos análisis estáticos en el código. Por ejemplo, Eclipse puede ofrecer una lista de todos los métodos que se pueden usar en un objeto, así como la implementación automática de "métodos TODO" vacíos. Eclispe sabe exactamente qué métodos debe implementar su clase en función de qué clases extienda y qué interfaces implemente. Esto sería casi imposible si no hubiera un estándar de lenguaje para hacer OO.

MTilsted
fuente
40
Ejemplo clásico: Lua. No es OO de forma nativa, pero se puede hacer, pero esto significa que hay alrededor de 5 bibliotecas OO diferentes igualmente conocidas que no son completamente interoperables.
Kroltan
55
@steakexchange Te enfocas demasiado en los absolutos. Muy poco tiene un "único propósito". Todos los idiomas hacen muchas cosas diferentes con diferentes grados de calidad. Elegir un idioma es elegir el conjunto de compensaciones que lo hacen más adecuado para el propósito para el que lo necesita.
Tim B
42
@nocomprende Estandarizar abstracciones es casi literalmente para lo que son los lenguajes de programación. Incluso el lenguaje ensamblador resume las diferencias entre algo así como diez generaciones de hardware durante una década y media.
David Moles
56
@DavidMoles Las abstracciones estandarizadas son literalmente lo que son los lenguajes de programación. ¡No pierdas la oportunidad perfecta de usar "literalmente" literalmente!
Clement Cherlin
12
Es posible estandarizar esto. Cuando estaba en la universidad a mediados de los 90, trabajé bastante en X-Windows (principalmente basado en Motif, para aquellos que recuerdan tales cosas). De hecho, X-Windows le permitió implementar todas las características de orientación de objetos en C normal . Sin embargo, la gimnasia mental para hacerlo fue bastante sustancial y se basó en gran medida en que las personas no miraran dentro de la caja (en ese momento, el Código de widgets de Schroedinger generalmente terminó muerto). Los lenguajes OO ocultan esto a los codificadores, de la misma manera que lo hace un compilador normal para ensamblador, y la vida es más fácil.
Graham
211

En el primer semestre, nos presentaron conceptos OOP como encapsulación, ocultación de datos, modularidad, herencia, etc. a través de Java y UML. (Java es mi primer lenguaje de programación)

Ninguno de esos son conceptos OOP. Todos existen fuera de OO, independientes de OO y muchos incluso fueron inventados antes de OO.

Entonces, si crees que de eso se trata OO, entonces tu conclusión es correcta: puedes hacer todo eso en lenguajes de procedimiento, porque no tienen nada que ver con OO .

Por ejemplo, uno de los documentos fundamentales sobre Modularidad es Sobre los criterios que se utilizarán en los sistemas de descomposición en módulos . No hay mención de OO allí. (Fue escrito en 1972, para entonces OO todavía era un nicho oscuro, a pesar de tener ya más de una década).

Si bien la abstracción de datos es importante en OO, es más una consecuencia de la característica principal de OO (Mensajería) que una característica definitoria. Además, es muy importante recordar que existen diferentes tipos de abstracción de datos. Los dos tipos más comunes de abstracción de datos que se usan actualmente (si ignoramos "ninguna abstracción", que probablemente todavía se usa más que las otras dos combinadas), son los tipos de datos abstractos y los objetos . Entonces, con solo decir "Ocultación de información", "Encapsulación" y "Abstracción de datos", no ha dicho nada sobre OO, ya que OO es solo una forma de abstracción de datos, y las dos son de hecho fundamentalmente diferentes:

  • Con los tipos de datos abstractos, el mecanismo para la abstracción es el sistema de tipos ; Es el sistema de tipos que oculta la implementación. (El sistema de tipos no tiene por qué ser necesariamente estático). Con los objetos, la implementación se oculta detrás de una interfaz de procedimiento , que no requiere tipos. (Por ejemplo, se puede implementar con cierres, como se hace en ECMAScript).
  • Con los tipos de datos abstractos, las instancias de diferentes ADT se encapsulan entre sí, pero las instancias del mismo ADT pueden inspeccionar y acceder a la representación y la implementación privada de cada uno. Los objetos siempre están encapsulados de todo . Solo el objeto en puede inspeccionar su propia representación y acceder a su propia implementación privada. Ningún otro objeto , ni siquiera otros objetos del mismo tipo, otras instancias de la misma clase, otros objetos que tengan el mismo prototipo, clones del objeto, o lo que sea que pueda hacer eso. Ninguno .

Lo que esto significa, por cierto, es que en Java, las clases no están orientadas a objetos. Dos instancias de la misma clase pueden acceder mutuamente a la representación y la implementación privada. Por lo tanto, las instancias de clases no son objetos, de hecho son instancias ADT. Java interfaces, sin embargo, no proporcionan la abstracción de datos orientada a objetos. En otras palabras: solo las instancias de interfaces son objetos en Java, las instancias de clases no lo son.

Básicamente, para los tipos, solo puede usar interfaces. Esto significa tipos de parámetros de métodos y constructores, tipos de métodos de retorno, tipos de campos de instancia, campos estáticos y campos locales, el argumento para un instanceofoperador o un operador de conversión, y los argumentos de tipo para un constructor de tipo genérico siempre deben ser interfaces. Una clase solo se puede usar directamente después del newoperador, en ningún otro lugar.

Por ejemplo, para modularidad, podemos dividir el programa en muchos programas pequeños que realizan tareas bien definidas cuyo código está contenido en archivos separados. Estos programas interactuarían entre sí a través de sus entradas y salidas bien definidas. Los archivos pueden estar protegidos (¿cifrados?) Para lograr la encapsulación. Para la reutilización del código, podemos llamar a esos archivos siempre que sean necesarios en nuevos programas. ¿Esto no captura todo lo que es OOP o me estoy perdiendo algo muy obvio?

Lo que describe es OO.

De hecho, esa es una buena manera de pensar en OO. De hecho, eso es exactamente lo que los inventores originales de OO tenían en mente. (Alan Kay fue un paso más allá: imaginó muchas pequeñas computadoras que se enviaban mensajes entre sí a través de la red). Lo que llama "programa" generalmente se llama "objeto" y, en lugar de "llamar", generalmente decimos "envíe un mensaje ".

La orientación a objetos se trata de mensajería (también conocido como despacho dinámico ). El término "Orientado a objetos" fue acuñado por el Dr. Alan Kay, el diseñador principal de Smalltalk, y lo define así :

OOP para mí significa solo mensajes, retención y protección local y ocultación del proceso estatal, y un enlace tardío extremo de todas las cosas.

Analicemos eso:

  • mensajería ("envío de método virtual", si no está familiarizado con Smalltalk)
  • proceso de estado debe ser
    • retenido localmente
    • protegido
    • oculto
  • atascamiento extremo de todas las cosas

En lo que respecta a la implementación, la mensajería es una llamada a un procedimiento con retraso, y si las llamadas a un procedimiento tienen un retraso, entonces no puede saber en tiempo de diseño a qué llamará, por lo que no puede hacer ninguna suposición sobre la representación concreta del estado. Entonces, realmente se trata de mensajes, el enlace tardío es una implementación de mensajes y la encapsulación es una consecuencia de ello.

Más tarde aclaró que " La gran idea es 'enviar mensajes' ", y lamenta haberlo llamado "orientado a objetos" en lugar de "orientado a mensajes", porque el término "orientado a objetos" pone el foco en lo que no es importante (objetos ) y distrae de lo que es realmente importante (mensajes):

Solo un suave recordatorio de que me tomé algunas molestias en el último OOPSLA para tratar de recordarles a todos que Smalltalk no solo NO es su sintaxis o la biblioteca de clases, ni siquiera se trata de clases. Lamento haber acuñado hace mucho tiempo el término "objetos" para este tema porque hace que muchas personas se centren en la idea menor.

La gran idea es la "mensajería", de eso se trata el núcleo de Smalltalk / Squeak (y es algo que nunca se completó en nuestra fase Xerox PARC). Los japoneses tienen una pequeña palabra - ma - para "lo que está en el medio" - tal vez el equivalente en inglés más cercano es "intersticial". La clave para crear sistemas excelentes y que se puedan desarrollar es mucho más para diseñar cómo se comunican sus módulos en lugar de cuáles deberían ser sus propiedades y comportamientos internos. Piense en Internet: para vivir, (a) tiene que permitir muchos tipos diferentes de ideas y realizaciones que están más allá de cualquier estándar único y (b) para permitir diversos grados de interoperabilidad segura entre estas ideas.

(Por supuesto, hoy en día, la mayoría de las personas ni siquiera se enfocan en objetos sino en clases, lo cual es aún más incorrecto).

La mensajería es fundamental para OO, tanto como metáfora como mecanismo.

Si le envía un mensaje a alguien, no sabe qué hace con él. Lo único que puedes observar es su respuesta. No sabe si procesaron el mensaje ellos mismos (es decir, si el objeto tiene un método), si enviaron el mensaje a otra persona (delegación / representación), incluso si lo entendieron. De eso se trata la encapsulación, de eso se trata OO. Ni siquiera puede distinguir un proxy del real, siempre que responda como espera que lo haga.

Un término más "moderno" para "mensajería" es "despacho de método dinámico" o "llamada de método virtual", pero eso pierde la metáfora y se enfoca en el mecanismo.

Por lo tanto, hay dos formas de ver la definición de Alan Kay: si la mira por sí sola, puede observar que la mensajería es básicamente una llamada a un procedimiento vinculado de forma tardía y la vinculación tardía implica la encapsulación, por lo que podemos concluir que # 1 y # 2 son en realidad redundantes, y OO tiene que ver con la unión tardía.

Sin embargo, más tarde aclaró que lo importante es la mensajería, por lo que podemos verlo desde un ángulo diferente: la mensajería está retrasada. Ahora, si la mensajería fuera lo único posible, entonces el # 3 sería trivialmente cierto: si solo hay una cosa, y esa cosa está vinculada tarde, entonces todas las cosas están vinculadas tarde. Y una vez más, la encapsulación se deriva de la mensajería.

También se hacen puntos similares en On Understanding Data Abstraction, revisado por William R. Cook y también su Propuesta de definiciones modernas y simplificadas de "objeto" y "orientado a objetos" :

El despacho dinámico de operaciones es la característica esencial de los objetos. Significa que la operación a invocar es una propiedad dinámica del objeto en sí. Las operaciones no pueden identificarse estáticamente, y no hay forma en general de [saber] exactamente qué operación se ejecutará en respuesta a una solicitud dada, excepto ejecutándola. Esto es exactamente lo mismo que con las funciones de primera clase, que siempre se envían dinámicamente.

¡En Smalltalk-72, ni siquiera había ningún objeto! Había sólo flujos de mensajes que quedó analizando, reescrito y redireccionados. Primero llegaron los métodos (formas estándar de analizar y redirigir las secuencias de mensajes), luego vinieron los objetos (agrupaciones de métodos que comparten algún estado privado). La herencia llegó mucho más tarde, y las clases solo se introdujeron como una forma de apoyar la herencia. Si el grupo de investigación de Kay ya hubiera conocido los prototipos, probablemente nunca habrían introducido clases en primer lugar.

Benjamin Pierce en Tipos y lenguajes de programación argumenta que la característica definitoria de la Orientación a objetos es la recursión abierta .

Entonces: según Alan Kay, OO tiene que ver con la mensajería. Según William Cook, OO tiene que ver con el envío de métodos dinámicos (que es realmente lo mismo). Según Benjamin Pierce, OO se trata de Open Recursion, lo que básicamente significa que las autorreferencias se resuelven dinámicamente (o al menos esa es una forma de pensar) o, en otras palabras, mensajes.

Como puede ver, la persona que acuñó el término "OO" tiene una visión bastante metafísica de los objetos, Cook tiene una visión bastante pragmática y Pierce una visión matemática muy rigurosa. Pero lo importante es: ¡el filósofo, el pragmático y el teórico están de acuerdo! La mensajería es el único pilar de OO. Período.

¡Tenga en cuenta que aquí no se menciona la herencia! La herencia no es esencial para OO. En general, la mayoría de los lenguajes OO tienen alguna forma de reutilización de implementación, pero eso no necesariamente tiene que ser herencia. También podría ser alguna forma de delegación, por ejemplo. De hecho, el Tratado de Orlando analiza la delegación como una alternativa a la herencia y cómo las diferentes formas de delegación y herencia conducen a diferentes puntos de diseño dentro del espacio de diseño de los lenguajes orientados a objetos. (Tenga en cuenta que incluso en los lenguajes que admiten la herencia, como Java, a las personas se les enseña a evitarlo, lo que nuevamente indica que no es necesario para OO).

Jörg W Mittag
fuente
16
+100 - Ponemos la culpa inherente a las cosas porque se están usando de manera incorrecta.
JeffO
55
Lo siento, pero esto es increíblemente incorrecto. Alan Kay puede haber ideado el término, pero los principios existían antes de Smalltalk. La programación orientada a objetos deriva de Simula, y su estilo OO no tenía nada que ver con los "mensajes". Casi todos los lenguajes OO que han tenido éxito se han basado en los principios básicos establecidos en Simula, los mismos que vemos en Java, y el estilo OO de Smalltalk ha sido un fracaso en el "mercado de ideas" cada vez que se reintroduce, porque simplemente no funciona muy bien en absoluto. El nombre era lo único realmente significativo que Kay contribuía.
Mason Wheeler
23
@steakexchange No. "La esencia de OO", lo que lo hace verdaderamente distintivo, son los objetos con métodos virtuales. Hay una razón por la que nadie usa Smalltalk: el sistema de transmisión de mensajes funciona muy mal a escala de computadora individual. Cada vez que un diseñador de lenguaje bien intencionado pero ingenuo intenta reimplementar los principios de Smalltalk, termina fallando. (El ejemplo más reciente sería Objective-C, que nadie hubiera usado si Steve Jobs no lo hubiera empujado a toda la comunidad de iOS. Nunca ha encontrado ninguna tracción fuera del ecosistema de Apple, y hay una razón para eso. )
Mason Wheeler
28
@MasonWheeler ¿Podría explicar su comentario en una respuesta ya que tiene una opinión bastante opuesta a lo que dice Jorg?
steakexchange
20
También vale la pena señalar que el concepto de lenguajes orientados a objetos evolucionó mucho. Esos conceptos ancestrales pueden no ser tan ciertos hoy en día con muchos idiomas que abandonan los viejos modelos y adoptan múltiples paradigmas. Mire C #, por ejemplo: ese lenguaje mezcla casi todo bajo el sol a la vez y, aunque se lo conoce principalmente como un lenguaje OO, en realidad es una mezcla de diferentes paradigmas. Eso le permite ser una herramienta realmente expresiva para los desarrolladores de todo. Además, Class-Based OO es uno de los muchos sabores igualmente válidos de la programación OO.
T. Sar
66

Pero creo que todos los principios utilizados para gestionar la complejidad, como la modularidad, la encapsulación, la ocultación de datos, etc., pueden implementarse muy fácilmente mediante lenguajes de procedimiento.

Cuando dices "muy fácilmente" estás haciendo una declaración muy audaz. La forma en que lo leo es: "No veo la dificultad, por lo que no debe ser muy grande". Cuando se formula de esa manera, queda claro que no estás preguntando "¿por qué necesitamos OO?", Estás preguntando "¿por qué las dificultades que otros paradigmas de programación encontraron que conducen a la invención de OO son inmediatamente aparentes para mí? "

Una respuesta a esa pregunta es que muchas de estas dificultades no existen en los tipos de programas en los que está trabajando. No se le pide que actualice el código de espagueti de 40 años. No está intentando escribir un nuevo administrador de pantalla para un sistema operativo. No está depurando aplicaciones distribuidas multiproceso.

Para muchos de los tipos de programas de juguetes que los estudiantes de CS tienen la tarea de escribir, podríamos escribirlos en BASIC o ensamblado como Java o Python. Esto se debe a que la complejidad inherente de las tareas es muy baja, solo hay un desarrollador, no hay problemas de interoperabilidad heredados, el rendimiento no importa y el código probablemente solo se ejecutará algunas veces en una máquina.

Imagínese tomar un conductor de estudiantes y pedirles que se unan en una calle concurrida en hora punta, en una transmisión manual sin sincronismo, en dirección a una colina empinada. Desastre. ¿Por qué? No pueden administrar el nivel de complejidad requerido para seguir simultáneamente todas las reglas que requiere la tarea.

Ahora imagine al mismo estudiante, el mismo vehículo, conduciendo a un ritmo de caminata en un estacionamiento vacío. Están bien, porque su nivel de habilidad es adecuado para la tarea. No hay presión, hay poco riesgo, y pueden tomar las subtareas individuales de arranque, embrague, cambio, aceleración, dirección, una a la vez.

Ese estudiante podría preguntar por qué tenemos transmisiones automáticas, si un conductor experto puede hacer todas estas cosas simultáneamente. La respuesta es que un conductor suficientemente hábil no necesita, en condiciones óptimas, una automática. Pero no todos somos conductores profesionales en óptimas condiciones y, por lo general, queremos la conveniencia de que los diseñadores de automóviles se encarguen de toda esa complejidad por nosotros.

Un programador hábil y disciplinado puede crear un sistema funcional de alta complejidad en C, o ensamblaje. Pero no todos somos Linus Torvalds. Tampoco deberíamos serlo, para crear software útil.

Personalmente, no me interesa tener que reinventar todas las características de un lenguaje moderno antes de que pueda abordar el problema en cuestión. Si puedo aprovechar un lenguaje que incluye soluciones a problemas ya resueltos, ¿por qué no lo haría?

Así que le daré la vuelta a su pregunta y le preguntaré si los idiomas ofrecen características convenientes como la encapsulación y el polimorfismo, ¿por qué no deberíamos usarlos?

Clement Cherlin
fuente
13
Básicamente, es posible hacer OO con un lenguaje de procedimiento, pero eso es hacer las cosas manualmente mientras se usa un lenguaje OO estandarizado que se automatiza y simplifica.
steakexchange
66
@steakexchange Más o menos exactamente eso.
Tim B
3
@steakexchange un buen ejemplo histórico de esto fue el modelo de objetos para X Windows en el pasado. Fue escrito en C pero se basó en un sistema orientado a objetos. Por lo tanto, tenía que seguir ciertas convenciones para interactuar con él para que sus clases fueran agradables con las de los demás.
Ukko
77
@nocomprende Ciertamente. Pero uno puede hacer que la computadora no se pueda arrancar haciendo grabaciones de disco sin procesar en lugar de depender del sistema de archivos, y habrá problemas realmente difíciles de depurar en un sistema de objetos ad-hoc creado por un novato. La encapsulación, cuando se hace correctamente, nos impide entrometernos intencionalmente o no en cosas que no deberíamos.
Clement Cherlin
3
Es interesante para mí que los ejemplos que da de aplicaciones que se beneficiarían de OO a menudo no están escritos en idiomas OO. El espagueti de 40 años probablemente esté escrito en C, COBOL, FORTRAN o REXX. El administrador de pantalla probablemente esté escrito en C (aunque con convenciones OO-ish), y muchos sistemas multiproceso distribuidos con éxito están escritos en Erlang, Go o C.
James_pic
22

Lo que estás describiendo no es OOP, es abstracción. La abstracción está presente en todos los modelos modernos de diseño, incluso en los que no son POO. Y OOP es un tipo muy específico de abstracción.

Primero, vale la pena señalar que no existe una definición única de OOP, por lo que puede haber personas que no estén de acuerdo con lo que yo caracterizo como OOP.

En segundo lugar, es importante recordar que OOP se inspiró en modelos de diseño tradicionales, por lo que las similitudes con el diseño de automóviles no son una coincidencia.

Sin embargo, aquí hay algunas formas en que la POO tiene más matices que lo que has dicho:

  • Encapsulación: no se trata solo de tener una interfaz establecida para un módulo (es decir, abstracción), se trata de prohibir el acceso más allá de esta interfaz. En Java, acceder a una variable privada es un error de compilación, mientras que en el diseño de su automóvil, puede (en algunos casos) usar las cosas de una manera diferente a la interfaz deseada.

  • Herencia: Esto es realmente lo que hace que la POO sea única. Una vez que haya definido una interfaz, puede hacer varias cosas implementando esa interfaz, y puede hacerlo de forma jerárquica, alterando partes específicas de su implementación, mientras hereda todas las partes anteriores, reduciendo enormemente la duplicación de código.

    Si piensa en términos de los componentes encapsulados de un automóvil, no hay realmente un equivalente a esto. No hay una manera de hacer una marcha tomando una marcha diferente y cambiando una parte específica de su implementación. (Al menos no lo creo, no sé mucho sobre automóviles).

  • Polimorfismo : una vez que haya definido una interfaz, cualquier cosa que use esa interfaz debería ser indistinguible, desde el punto de vista de qué operaciones están disponibles, y no debería necesitar saber qué implementación se está utilizando para usar una interfaz. Aquí es donde el subtipo y el Principio de sustitución de Liskov se vuelven importantes.

  • Acoplamiento : Un aspecto clave de OOP es que relacionamos estrechamente las cosas con las mismas operaciones y distribuimos las diferentes formas que pueden tener. Los datos se agrupan con operaciones en esos datos. Esto significa que es muy fácil agregar una nueva forma de datos (una nueva implementación), pero muy difícil agregar una nueva operación a una interfaz (ya que tendría que actualizar cada clase que implementa la interfaz). Esto contrasta con los tipos de datos algebraicos en lenguajes funcionales, donde es muy fácil agregar una nueva operación (solo escribe una función que se ocupe de todos los casos), pero es difícil agregar una nueva variante (ya que necesita agregar una nueva caso a todas sus funciones).

jmite
fuente
1
¡Buena respuesta! Una parte con la que no estoy de acuerdo: la distinción que está haciendo sobre la encapsulación no es válida. La encapsulación siempre significa "prohibir el acceso más allá de esta interfaz"; eso es cierto tanto para las configuraciones OOP como para las que no lo son. Entonces, esta parte no es realmente algo que sea exclusivo de OOP.
DW
@DW He tratado de aclarar esto, diciendo que no es exclusivo de OOP sino que es la diferencia entre encapsulación y abstracción. ¡Gracias por la respuesta!
jmite
2
OKAY. Pero todavía tengo una opinión diferente sobre lo que está escrito aquí sobre ese tema. Usted escribió que "aquí hay algunas formas en que la POO está más matizada de lo que ha dicho", pero la encapsulación no es una forma en que la POO esté más matizada de lo que se escribió en la pregunta. La encapsulación es lo que es, en cualquier paradigma. Y cuando escribiste que "Lo que estás describiendo no es POO, es abstracción", pensé que la pregunta original estaba tratando de describir la encapsulación (no solo la abstracción). Supongo que dejaré este comentario como una perspectiva diferente. ¡Creo que la respuesta es muy útil!
DW
La herencia es una característica común, pero varios idiomas importantes de OO carecen de ella.
Bradd Szonye el
Buena respuesta, pero en mi opinión, estás exagerando el ejemplo del automóvil. Un motor para un modelo dado tiene una interfaz bien definida (eje de leva, "receptáculos" de soporte de montaje, etc.). Puede reemplazar un carburador viejo por uno con inyección de combustible, agregar un turbocompresor, etc. sin afectar la transmisión. (Aunque un motor diesel requiere un tanque de combustible IIRC modificado). Por el contrario, puede reemplazar una transmisión manual por una automática y AFAIK que no afecte el motor en absoluto.
David
11

¿Realmente necesitamos lenguajes OO para gestionar la complejidad del software?

Esto depende del significado de la palabra "necesidad".

Si "necesidad" significa requiere, no, no lo requerimos.

Si "necesidad" significa "proporciona fuertes beneficios", entonces diría "Sí", lo deseamos.

Cuadro grande

Los lenguajes OO vinculan la funcionalidad a los datos.

Puede evitar este enlace y funciones de escritura que pasan valores de datos.

Pero entonces probablemente terminará con constelaciones de datos que van juntas, y comenzará a pasar tuplas, registros o diccionarios de datos.

Y realmente, esas son todas las llamadas a métodos: funciones parciales en conjuntos de datos vinculados.

Característica por característica

Características de OOP:

  • La herencia permite la reutilización del código (mixins) y el concepto (clases / interfaces base abstractas), pero puede obtener esto redecorando funciones y variables en un sub-alcance.
  • La encapsulación permite ocultar información para que podamos trabajar en niveles más altos de abstracción, pero puede hacerlo con archivos de encabezado, funciones y módulos.
  • El polimorfismo nos permite usar argumentos de diferentes tipos siempre que esos argumentos admitan las mismas interfaces, pero también podemos hacerlo con funciones.

Sin embargo, ninguna de esas cosas sucede tan fácilmente como con un lenguaje orientado a objetos con soporte de primera clase de esas características.

Referencias

Hay muchos críticos de OOP .

Sin embargo, los estudios parecen indicar que obtenemos una mayor productividad del programador a partir de la reutilización del código a través de OOP. Este es un hallazgo controvertido, y algunos investigadores dicen que no pueden reproducir estas ganancias de productividad, dadas ciertas restricciones. (fuente)

Conclusión

No "necesitamos" POO. Pero en algunos casos el usuario quiere OOP.

Tengo entendido que los programadores maduros pueden ser bastante productivos en el estilo orientado a objetos. Y cuando los paquetes tienen objetos centrales con interfaces simples que se entienden fácilmente, incluso los nuevos programadores pueden ser bastante productivos rápidamente.

Aaron Hall
fuente
10

Intentaré ser breve.

El principio central de OO es la combinación de datos y comportamiento en una sola unidad organizativa (un objeto).

Esto es lo que nos permite controlar la complejidad y fue un concepto bastante innovador cuando surgió. Compare eso con los archivos por un lado (datos puros), los programas que leen y procesan esos archivos por el otro lado (lógica pura) y la salida (datos puros nuevamente).

Solo una vez que tenga ese paquete de datos y lógica juntos, modelando alguna entidad del mundo real, puede comenzar a intercambiar mensajes, crear clases secundarias, separar datos y comportamientos privados de públicos, implementar comportamientos polimórficos, hacer toda esta magia específica de OO.

Entonces, sí, OO es un gran problema. Y no, no es solo un montón de cosas viejas con un nombre elegante.

Desmontarlo todo, mirar los elementos y luego decir "oh, bueno, aquí no hay nada que no haya visto antes" no es reconocer el ensamblaje que contiene la innovación. El resultado es más que la suma de sus partes.

Martin Maat
fuente
8

No existe una definición "oficial" de programación orientada a objetos, y personas razonables no están de acuerdo con lo que realmente define la calidad de OO. Algunos dicen mensajes, algunos dicen subtipos, otros dicen herencia, algunos dicen la agrupación de datos y comportamiento. Eso no significa que el término no tenga sentido, solo que no debería quedar atrapado en disputas sobre lo que es OO real .

La encapsulación y la modularidad son principios más fundamentales del diseño y deben aplicarse en todos los paradigmas de programación. Los defensores de OO no afirman que estas propiedades solo se puedan lograr con OO, solo que OO es particularmente adecuado para lograr esto. Por supuesto, los defensores de otros paradigmas, como la programación funcional, afirman lo mismo para su paradigma. En la práctica, muchos lenguajes exitosos son multi-paradigmáticos y el OO, funcional, etc. debe ser visto como una herramienta más que como "la única forma verdadera".

Creo que todos los principios utilizados para gestionar la complejidad pueden realizarse mediante lenguajes de programación de procedimientos.

Es cierto, porque al final puedes hacer cualquier cosa en cualquier lenguaje de programación. Puede ser más fácil en algunos idiomas que en otros, ya que todos los idiomas tienen diferentes fortalezas y debilidades.

JacquesB
fuente
7

Algo que las otras respuestas no han mencionado: estado.

Hablas de OO como una herramienta para gestionar la complejidad . ¿Qué es la complejidad? Ese es un término difuso. Todos tenemos este sentido gestalt de lo que significa, pero es más difícil precisarlo. Podríamos medir la complejidad ciclomática, es decir, el número de rutas de tiempo de ejecución a través del código, pero no sé de qué estamos hablando cuando usamos OO para gestionar la complejidad.

De lo que creo que estamos hablando es de la complejidad relacionada con el estado.

Hay dos ideas principales detrás de la encapsulación . Uno de ellos, la ocultación de los detalles de implementación , está bastante bien cubierto en las otras respuestas. Pero otro está ocultando su estado de tiempo de ejecución . No jugamos con los datos internos de los objetos; pasamos mensajes (o métodos de llamada si prefiere detalles de implementación sobre el concepto, como señaló Jörg Mittag). ¿Por qué?

La gente ya ha mencionado que es porque no puede cambiar la estructura interna de sus datos sin cambiar el código al que accede, y desea hacerlo en un lugar (el método de acceso) en lugar de 300 lugares.

Pero también es porque hace que el código sea difícil de razonar : el código de procedimiento (ya sea en un lenguaje de naturaleza procesal o simplemente escrito en ese estilo) ofrece poca ayuda para imponer restricciones a la mutación del estado. Cualquier cosa puede cambiar en cualquier momento desde cualquier lugar. Las funciones / métodos de llamada pueden tener acción a distancia espeluznante. Las pruebas automatizadas son más difíciles, ya que el éxito de las pruebas está determinado por el valor de las variables no locales a las que se accede / accede ampliamente.

Los otros dos grandes paradigmas de programación (OO y funcional) ofrecen soluciones interesantes, pero casi diametralmente opuestas, al problema de la complejidad relacionada con el estado. En la programación funcional, se intenta evitarlo por completo: las funciones son generalmente puras, las operaciones en estructuras de datos devuelven copias en lugar de actualizar el original en su lugar, etc.

OO, por otro lado, ofrece herramientas para manejar el estado de gestión (en lugar de herramientas para evitarlo). Además de las herramientas de nivel de lenguaje como modificadores de acceso (protegidos / públicos / privados), captadores y establecedores, etc., también hay una serie de convenciones relacionadas, como la Ley de Demeter, que aconseja no llegar a través de los objetos para obtener datos de otros objetos. .

Tenga en cuenta que no necesita objetos para hacer nada de esto: podría tener un cierre que tenga datos inaccesibles y devuelva una estructura de datos de funciones para manipularlos. ¿Pero no es eso un objeto? ¿No se ajusta eso a nuestra concepción de lo que es un objeto, intuitivamente? Y si tenemos este concepto, ¿no es mejor volver a aplicarlo en el lenguaje en lugar de (como han dicho otras respuestas) confiar en una explosión combinatoria de implementaciones ad-hoc en competencia?

Jared Smith
fuente
5

¿Realmente necesitamos lenguajes OO para gestionar la complejidad del software?

No. Pero pueden ayudar en muchas situaciones.

He usado principalmente un solo lenguaje OO durante décadas, pero la mayor parte de mi código es en realidad estrictamente de procedimiento previo al estilo OO. Sin embargo, para cualquier cosa que involucre una GUI, utilizo la vasta biblioteca OO del lenguaje de métodos y objetos integrados, porque simplifica enormemente mi código.

Por ejemplo, una aplicación de Windows que usa la API original de Windows de bajo nivel para mostrar un formulario, un botón y un campo de edición requiere mucho código, mientras que en su lugar, usar las bibliotecas de objetos que vienen con Visual Basic o C # o Delphi hacen lo mismo programa pequeño y trivial. Por lo tanto, mi código OO suele ser relativamente pequeño y para la GUI, mientras que mi código que invocan esos objetos suele ser mucho más grande y generalmente no tiene que ver con ser OO (aunque puede variar según el problema que estoy tratando de resolver).

He visto programas OO que eran demasiado complicados, se basaban en reglas esotéricas complicadas sobre cómo se implementaron los objetos, y podrían haber sido mucho más simples si se escribieran sin conceptos OO. También he visto lo contrario: sistemas complejos que claman por ser reimplementados y simplificados mediante el uso de objetos.

A medida que gane experiencia, encontrará que diferentes situaciones requieren diferentes herramientas y soluciones, y un tamaño no sirve para todos.

Joe snyder
fuente
3

Como alguien involucrado en un proyecto muy grande completamente escrito en C, definitivamente puedo decir que la respuesta es un claro "no".

La modularidad es importante. Pero la modularidad se puede implementar en prácticamente cualquier lenguaje decente. Por ejemplo, C admite compilación modular, archivos de encabezado y tipos de estructura. Esto es suficiente para el 99% de los casos. Defina un módulo para cada nuevo tipo de datos abstractos que necesite y defina las funciones para operar en el tipo de datos. A veces, desea rendimiento y esas funciones están en el archivo de encabezado como funciones en línea, otras veces utilizará funciones estándar. Todo es invisible para el usuario de qué manera se elige.

Estructura de soporte de la composición. Por ejemplo, puede tener una tabla hash bloqueada que consta de un bloqueo mutex y una tabla hash normal. Esto no es programación orientada a objetos; No se realiza ninguna subclasificación. La composición es una herramienta mucho más antigua que la idea de la programación orientada a objetos.

Para el 1% de los casos en los que la modularidad del nivel de compilación no es suficiente y necesita modularidad en tiempo de ejecución, existe una cosa llamada punteros de función. Permiten tener implementaciones individuales de una interfaz bien definida. Tenga en cuenta que esto no es programación orientada a objetos en un lenguaje no orientado a objetos. Esto es definir una interfaz y luego implementarla. Por ejemplo, la subclase no se usa aquí.

Considere quizás el proyecto de código abierto más complejo que existe. A saber, el kernel de Linux. Está escrito completamente en lenguaje C. Se realiza principalmente mediante el uso de herramientas de modularidad de nivel de compilación estándar, incluida la composición, y ocasionalmente, cuando se necesita modularidad en tiempo de ejecución, se utilizan punteros de función para definir e implementar una interfaz.

Si intenta encontrar un ejemplo de programación orientada a objetos en el kernel de Linux, estoy seguro de que encontrar ese ejemplo es muy difícil, a menos que extienda la programación orientada a objetos para incluir tareas estándar como "definir una interfaz y luego implementarla".

Tenga en cuenta que incluso el lenguaje de programación C admite la programación orientada a objetos si realmente lo necesita. Por ejemplo, considere el kit de herramientas de interfaz gráfica de usuario GTK. En realidad, está orientado a objetos, aunque esté escrito en un lenguaje no orientado a objetos. Entonces, esto muestra que la idea de que necesita un "lenguaje orientado a objetos" es profundamente defectuosa. No hay nada que un lenguaje orientado a objetos pueda hacer que otro tipo de lenguaje no pueda hacer. Además, si eres un programador experto, sabes cómo escribir código orientado a objetos en cualquier idioma con mucha facilidad. No es una carga usar C, por ejemplo.

Entonces, las conclusiones son que los lenguajes orientados a objetos probablemente sean útiles solo para programadores novatos que no entienden cómo se implementa realmente el concepto. Sin embargo, no quisiera estar cerca de ningún proyecto en el que los programadores sean programadores novatos.

juhist
fuente
1
"[...] las conclusiones son que los lenguajes orientados a objetos probablemente sean útiles solo para programadores novatos que no entienden cómo se implementa realmente el concepto". Interesante. ¿Qué idiomas tienes en mente? ¿Tiene ejemplos de proyectos de código abierto escritos en estos idiomas que fallaron o no fallaron?
Vincent Savard
3
Planteas algunos puntos buenos, pero tu idea principal es errónea. Sí, es posible implementar conceptos OO como encapsulación, despacho virtual, herencia e incluso recolección de basura en un lenguaje como C. También es posible hacerlo en ensamblador. No facilita la programación. Programar y especialmente diseñar en un lenguaje como C es definitivamente más difícil que en un lenguaje OO. En C necesita asignar los conceptos a su implementación, en un lenguaje OO no necesita hacer ese paso (al menos no para los conceptos OO).
fishinear
1
"[los punteros de función] permiten tener implementaciones individuales de una interfaz bien definida. Tenga en cuenta que esto no es programación orientada a objetos en un lenguaje no orientado a objetos. Esto es definir una interfaz y luego implementarla". Lo siento, pero eso está completamente mal, porque esto es exactamente lo que es OOP. "Por ejemplo, la subclasificación no se usa aquí" La subclasificación no es una característica requerida de OOP. Tenga en cuenta, por ejemplo, que JavaScript es un lenguaje orientado a objetos que no presenta subclases (o, para el caso, clases en absoluto ... Solo objetos que contienen referencias de funciones).
Jules
1
Para aclarar mi último comentario, mi punto es que el principal factor distintivo b entre OOP (no necesariamente cualquier lenguaje OO específico) y otros métodos es que en OOP definimos interfaces que operan de manera abstracta en los datos sin necesidad de conocer el formato de esos datos. vinculando la implementación de las interfaces a los datos en sí. Eso es lo que es OOP. El método de implementación es irrelevante, ya sea una clase de estilo Java, un objeto JavaScript (efectivamente un mapa de nombre a atributo, que puede ser datos o código) o una estructura que contiene punteros de función y un vacío * para los datos.
Jules
1
"Entonces, las conclusiones son que los lenguajes orientados a objetos probablemente sean útiles solo para programadores novatos que no entienden cómo se implementa realmente el concepto" ... Y esto, francamente, es simplemente insultante. Sé bastante bien cómo se implementan estos conceptos. He hecho suficiente trabajo usando entonces para ser competente, incluso. Incluso he implementado un intérprete y un compilador para lenguajes OO en el pasado. Pero debido a que prefiero trabajar en lenguajes de nivel superior que tienen objetos de primera clase, ¿debo ser un programador novato con el que preferirías no trabajar?
Jules
2

La razón para introducir paradigmas de programación, incluidos los métodos orientados a objetos, es facilitar la creación de programas más sofisticados y potentes. En la edición de agosto de 1981 de la revista Byte, Daniel Ingalls , uno de los creadores clave de Smalltalk, definió "orientado a objetos" como la participación de las siguientes capacidades:

  • gestión automática de almacenamiento
  • capacidad de intercambiar mensajes
  • Una metáfora uniforme que se aplica a todas las operaciones del lenguaje.
  • ningún componente depende de lo interno de otro componente (modularidad)
  • El programa define solo el comportamiento de los objetos, no su representación (polimorfismo)
  • cada componente debe aparecer en un solo lugar (factorización)
  • El uso de una máquina virtual que es independiente del hardware
  • todos los componentes accesibles para el usuario deben estar disponibles para observación y control (principio reactivo)
  • no debería haber un controlador general (sin sistema operativo)

Estos fueron los principios que Ingalls identificó como las consideraciones de diseño de conducción para SmallTalk-80 desarrollado por Xerox Parc Research. En el artículo de la revista mencionado anteriormente, puede leer una descripción detallada de cada uno de estos principios y cómo contribuyen al paradigma orientado a objetos según Ingalls.

Todos estos principios se pueden aplicar utilizando cualquier lenguaje completo de Turing, ya sea de procedimiento, lenguaje ensamblador o lo que sea. Estos son principios de diseño, no una especificación de lenguaje. El objetivo de un lenguaje orientado a objetos es facilitar el uso de estos principios al crear software.

Por ejemplo, para tomar el primero de los principios de Ingall (administración automática de almacenamiento), cualquiera puede escribir su propio sistema automático de administración de almacenamiento en un lenguaje de procedimiento, pero sería mucho trabajo hacerlo. Cuando se utiliza un lenguaje como SmallTalk o Java que tiene integrada la administración automática de almacenamiento, el programador no tiene que hacer tanto trabajo para administrar la memoria. La desventaja es que el programador obtiene menos control sobre la forma en que se usa la memoria. Entonces, hay un beneficio y un inconveniente. La idea de un paradigma de diseño como la programación orientada a objetos es que los beneficios del paradigma superarán las desventajas para al menos algunos programadores.

Tyler Durden
fuente
Creo que se aplicarían las mismas reglas en el caso de lenguajes específicos de dominio. Las mismas ventajas y desventajas ... La única diferencia es que las DSL pueden simplificarse lo suficiente para que los usuarios finales trabajen, porque el 'lenguaje' corresponde a su comprensión del espacio del problema, y ​​no se incluye nada más.
0

Una forma de administrar la complejidad del software es separar el marco de las acciones deseadas por completo utilizando un lenguaje específico de dominio . Esto significa que el nivel de código de programación es distinto del nivel en el que se configuran los resultados deseados, un lenguaje o sistema completamente diferente. Cuando esto se hace correctamente, el código convencional se convierte esencialmente en una biblioteca, y el usuario u otra persona que crea los resultados deseados conecta todo junto con un lenguaje de script o una herramienta de diseño visual, como un generador de informes.

Para funcionar, esto requiere dibujar un límite estricto en torno a qué operaciones serán posibles y cómo se vinculan (lenguaje de script o diseño visual, como una herramienta de construcción de formularios). Los metadatos son una forma importante de abstraer la configuración del tiempo de ejecución de los detalles de codificación, haciendo posible que un sistema admita una amplia gama de resultados deseados. Si los límites se establecen y se mantienen (sin aceptar todas las solicitudes de extensión que se presenten), puede tener un sistema duradero y robusto que funcione para las personas, sin que tengan que ser programadores para lograr lo que quieren.

Martin Fowler ha escrito un libro sobre esto, y la técnica es casi tan antigua como la programación misma. Casi se podría decir que todos los lenguajes de programación son lenguajes específicos de dominio, por lo que la idea es endémica, pasada por alto porque es muy obvia. Pero aún puede crear sus propias herramientas de diseño visual o de secuencias de comandos para facilitarle la vida. ¡A veces, generalizar un problema hace que sea mucho más fácil de resolver!


fuente
0

Esta es una muy buena pregunta y siento que las respuestas dadas aquí no han hecho justicia, así que seguiré adelante y agregaré mis pensamientos.

El objetivo es: administrar la complejidad del software . El objetivo no es "usar lenguaje OO".

No hay "razón" para introducir un nuevo paradigma. Es algo que sucedió naturalmente cuando la codificación se hizo más madura. Tiene más sentido escribir código donde agreguemos un entrenador al final del tren (el tren se modela usando una lista vinculada) en lugar de agregar un nuevo nodo al final de la lista vinculada.


Codificación en términos de entidades del mundo real es simplemente la manera más obvia y adecuada de codificar cuando nos estamos codificando sobre las entidades del mundo real.


Una computadora puede trabajar agregando un nodo al final de la lista vinculada tan fácilmente como puede agregar un entrenador adicional al final del tren. Pero para los humanos es más fácil trabajar con el tren y el entrenador que con la lista y los nodos vinculados, aunque cuando vamos a un nivel profundo, encontramos que el tren se modela mediante una lista vinculada.

Proteger o cifrar los archivos no puede lograr la encapsulación. Lo opuesto al cifrado es el descifrado. Lo opuesto a la encapsulación es la decapsulación, que significa descomposición de estructuras y clases en lenguajes de programación para lograr un mejor rendimiento. El rendimiento obtenido al reducir el tráfico de memoria y evitar las verificaciones de las reglas de OOP

Por lo tanto, puede escribir código que esté encriptado y bien encapsulado porque estos dos son conceptos diferentes.

La encapsulación ayuda a gestionar la complejidad en virtud de estar cerca de la realidad.

Por lo tanto, programe en objetos porque es más fácil para usted codificar y es más rápido para usted y para todos los demás comprender.

nombre para mostrar
fuente
0

Lo único que debe recordar es esto:
OOP no se trata de características del lenguaje; se trata de la forma en que estructura su código .

OOP es una forma de pensar y de diseñar la arquitectura de su código, y se puede hacer en casi cualquier idioma. Esto incluye especialmente los lenguajes de bajo nivel que no son OO, que se llaman ensamblador y C. Puede realizar una programación perfectamente orientada a objetos en ensamblador, y el núcleo de Linux, que está escrito en C, está bastante orientado a objetos en muchos aspectos .

Dicho esto, las características de OO en un idioma reducen en gran medida la cantidad de código repetitivo que necesita escribir para lograr los resultados deseados . Cuando necesite definir explícitamente una tabla de funciones virtuales y llenarla con los punteros de función apropiados en C, simplemente no hace nada en Java, y ya está. Los lenguajes OO simplemente eliminan todo lo que permite el cruft del código fuente, ocultándolo detrás de agradables abstracciones de nivel de lenguaje (como clases, métodos, miembros, clases base, llamadas implícitas de constructor / destructor, etc.).

Entonces, no, no necesitamos idiomas OO para hacer OOP. Es solo que OOP es mucho más fácil de hacer con un lenguaje OO decente.

cmaster
fuente
-1

La programación orientada a objetos es más que solo módulos + encapsulación. Como usted dice, es posible usar módulos + encapsulación en un lenguaje no orientado a objetos (de procedimiento). OOP implica más que solo eso: involucra objetos y métodos. Entonces, no, eso no captura la POO. Ver, por ejemplo, https://en.wikipedia.org/wiki/Object-oriented_programming o la introducción de un buen libro de texto a OOP.

DW
fuente
Gracias por la respuesta. ¿Me puede recomendar uno?
steakexchange
-2

La razón principal es que, a medida que un programa se vuelve más complejo, debe hacer que algunas partes del mismo sean invisibles de otras partes, o la complejidad de la aplicación y la cantidad de funciones harán que su cerebro gotee fuera de sus oídos.

Imaginemos un sistema de 100 clases, cada una con aproximadamente 20 operaciones que se pueden realizar en ellas; Eso son 2.000 funciones. Sin embargo, de esos, tal vez solo 500 son operaciones completas como 'Guardar' y 'Eliminar', mientras que 1500 son funciones internas que realizan un poco de mantenimiento o tienen alguna función de utilidad. Considerar;

// intentionally in a non-specific language!

setName(person, name) {
    nameParts = splitPersonName(name);
    person.firstName = nameParts[0];
    person.lastName = nameParts[1];
    person.modified = true;
}

splitPersonName(name) {
    var result = [];
    result.add(name.substring(0, name.indexOf(" ")));
    result.add(name.substring(name.indexOf(" ") + 1));
    return result;
}

Entonces, SetNamees una función que las personas deberían estar haciendo a una persona, pero SplitPersonNamees una función de utilidad utilizada por la persona.

La programación procesal directa no hace distinción entre estas dos operaciones. Eso significa que sus 2,000 funcionalidades compiten por su atención. Sin embargo, si pudiéramos marcar estas funciones como 'disponibles para todos los que tienen un registro de persona' y 'utilizadas solo como una función de utilidad dentro del registro de persona', entonces nuestra atención ahora es 500 'funciones disponibles para todos' y 15 'utilidad' funciones para la clase que estás editando.

Eso es publicy privatehacer;

public class Person {
    public void setName(...) {...}
    private string[] splitPersonName(...) { ...}
}
usuario62575
fuente
1
No estoy seguro si entendiste mi pregunta correctamente. Ya conozco la encapsulación y la ocultación de datos como una forma de gestionar la complejidad. Simplemente creo que esto también se puede hacer fácilmente en lenguajes de procedimiento dividiendo el programa en módulos que realizan tareas simples bien definidas cuyo funcionamiento interno se especifica en fuentes protegidas separadas. Entonces, ¿por qué OOP cuando podemos hacer esas cosas en lenguajes de procedimiento? Esa es mi pregunta
steakexchange
2
Supongo que mi respuesta es que si desea hacer este tipo de cosas, tendrá que escribir herramientas especiales y construcciones de lenguaje para hacerlo (por ejemplo, una llamada especial 'incluir' a un archivo de inclusión que no ser incluido en otra parte). Una vez que ha comenzado ese camino, ha comenzado a implementar un lenguaje orientado a objetos a su manera. Por ejemplo, C ++ era originalmente un preprocesador que producía C simple , y sospecho que una vez que está implementando su sistema, se parece mucho a C ++ sobre C.
user62575
3
@steakexchange Tenga en cuenta que OOP se desarrolló en un momento en que muchos lenguajes de procedimiento no tenían módulos como ese. Algunos ni siquiera llamarían a tales lenguajes procesales. De hecho, no hay nada que diga que un lenguaje de procedimiento no debe ser OO o viceversa. Tenga cuidado con las etiquetas, pueden confundirlo fácilmente. Si su lenguaje de procedimiento admite módulos que tienen campos y procedimientos públicos y privados, es bueno para usted :) La principal diferencia entre "procedimiento tradicional" y "OOP" es que el despacho de llamadas es más flexible en OOP; de hecho, en OOP estricto, usted nunca se sabe a qué código llamas.
Luaan
2
@steakexchange En los lenguajes de la familia ML, los módulos funcionan muy bien y, en combinación con lambdas, le brindan todo el poder de cualquier lenguaje OO (después de todo, una función es una interfaz con un único método, ¿no es eso lo que recomiendan? "buen código" chicos en OO?: P). Por varias razones, todavía son menos utilizados que los lenguajes más procesales como C ++ o Java, pero tienen su atractivo, y muchas personas están tratando de educar a las personas sobre cómo pueden simplificar su vida (con más o menos éxito).
Luaan
C efectivamente tiene estas cosas. Tiene módulos (archivos .c) con interfaces (archivos .h) y puede tener métodos (funciones) públicos (extern) y no públicos (extern). Usted puede incluso tener el polimorfismo del hombre pobre con matrices de punteros de función, no estoy diciendo que es fácil OO en C (o tal vez, en su sano juicio), pero encapsulación es bastante fácil,
Nick Keighley