Pregunta

Nota: Esta pregunta es un extracto editado de un Publicación de blog Escribí hace unos meses. Después de colocar un enlace al blog en un comentario en programadores. SEA alguien solicitó que publiqué una pregunta aquí para poder responderla. Esta publicación es mi más popular, ya que la gente parece escribir "No obtengo una programación orientada a objetos" en Google mucho. Siéntase libre de responder aquí, o en un comentario en WordPress.

¿Qué es la programación orientada a objetos? Nadie me ha dado una respuesta satisfactoria. Siento que no obtendrá una buena definición de alguien que diga "objeto" y "orientado a objetos" con la nariz en el aire. Tampoco obtendrá una buena definición de alguien que no haya hecho nada más que programación orientada a objetos. Nadie que entienda la programación de procedimientos y orientados a objetos me ha dado una idea consistente de lo que realmente hace un programa orientado a objetos.

¿Alguien puede darme sus ideas sobre las ventajas de la programación orientada a objetos?

¿Fue útil?

Solución

Piense en el software como una máquina o línea de ensamblaje que existe dentro de la computadora. Algunas materias primas y componentes se alimentan a la máquina, y sigue un conjunto de procedimientos para procesarlas en algún producto final. Los procedimientos se configuran para realizar una operación específica en alguna materia prima o componente a un conjunto específico de parámetros (por ejemplo, tiempo, temperatura, distancia, etc.) en un orden particular. Si los detalles de la operación a realizar fueran incorrectos, o los sensores de la máquina no están correctamente calibrados, o si alguna materia prima o componente no estuviera dentro de los estándares de calidad esperados, podría cambiar el resultado de la operación y el producto no resultaría como se esperaba.

Tal máquina es muy rígida en su funcionamiento y entradas aceptables. Las máquinas no cuestionan la inteligencia de los diseñadores ni su entorno operativo actual. Continuará siguiendo los procedimientos siempre que esté dirigido a. Incluso si un cambio en materias primas o componentes pudiera tener un efecto dramático en lo que sucedió en operaciones posteriores, la máquina aún realizaría sus procedimientos. El proceso debería revisarse para ver qué cambios en los procedimientos eran necesarios para compensar y producir el resultado deseado. Un cambio en el diseño o configuración del producto también puede requerir un cambio significativo en las operaciones realizadas o su pedido. Aunque aquellos a cargo de la producción aprendieron rápidamente la importancia de aislar las operaciones tanto como sea posible para reducir los efectos indeseables entre ellos, se hacen muchos supuestos de los componentes de la condición a medida que se procesan; Suposiciones que podrían no detectarse hasta que el producto final esté en manos del usuario en un entorno operativo diferente.

Así es la programación de procedimientos.

Lo que proporciona la orientación de objetos es una forma de eliminar los supuestos de la condición de los componentes; Por lo tanto, las operaciones que se realizarán en ese componente y cómo integrarlo en el producto final. En otras palabras, OOP es como tomar los detalles del proceso para tratar con algún componente particular y darlo a una máquina más pequeña para hacer. La máquina más grande responsable del proceso le dice a la máquina específica del componente qué operación espera que se realice, pero deja los detalles de los pasos a la máquina específica del componente.

En cuanto a las ventajas de la orientación de objetos sobre el software no orientado al objeto:

  • comportamiento específico de componentes - Hacer detalles sobre cómo manejar un componente particular La responsabilidad de la máquina específica de componentes más pequeña garantiza cualquier momento en que se maneje el componente, su máquina lo hará adecuadamente;
  • expresiones polimórficas - Debido a que las máquinas específicas de componentes realizan operaciones adaptadas a su componente particular, el mismo mensaje enviado a diferentes máquinas puede actuar de manera diferente;
  • Tipo de abstracción - A menudo tiene sentido que varios tipos diferentes de componentes usen el mismo vocabulario para las operaciones que realizan sus máquinas;
  • separación de intereses - Dejar los detalles específicos de los componentes en sus máquinas significa que la máquina de proceso solo necesita manejar las preocupaciones más generales y más grandes de su proceso y los datos requeridos para administrarlo; Además, es menos probable que se vea afectado por los cambios en otros componentes;
  • adaptabilidad - Los componentes que se centran en su área de especialidad se pueden adaptar para un uso imprevisto simplemente cambiando los componentes que utiliza o poniéndolo a disposición de otra máquina de proceso;
  • reutilización de código - Los componentes con un enfoque estrecho y una mayor adaptabilidad pueden aprovechar su costo de desarrollo al utilizar con más frecuencia.

Otros consejos

De su blog, parece que está familiarizado con la programación imperativa y funcional, y que está familiarizado con los conceptos básicos involucrados en la programación orientada a objetos, pero nunca ha tenido realmente "hacer clic" en cuanto a qué lo hace útil. Intentaré explicar en términos de ese conocimiento y espero que sea útil para usted.

En esencia, OOP es una forma de utilizar el paradigma imperativo para gestionar mejor los altos grados de complejidad mediante la creación de estructuras de datos "inteligentes" que modelan el dominio del problema. En un programa (no orientado al procedimiento estándar), tiene dos cosas básicas: variables y código que sabe qué hacer con ellos. El código toma la entrada del usuario y varias otras fuentes, la almacena en variables, opera y produce datos de salida que van al usuario o en otras ubicaciones.

La programación orientada a objetos es una forma de simplificar su programa tomando ese patrón básico y repitiéndolo a menor escala. Al igual que un programa es una gran recopilación de datos con código que sabe qué hacer con él, cada objeto es un pequeño datos vinculado al código que sabe qué hacer con él.

Al romper el dominio del problema en piezas más pequeñas y asegurarse de que la mayor cantidad de datos posible esté directamente al código que sepa qué hacer con él, hace que sea mucho más fácil razonar sobre el proceso en su conjunto y también sobre el sub- problemas que componen el proceso.

Al agrupar los datos en clases de objetos, puede centralizar el código relacionado con esos datos, lo que facilita el código relevante tanto para encontrar como para depurar. Y al encapsular los datos detrás de los especificadores de acceso y solo acceder a ellos a través de métodos (o propiedades, si su lenguaje los apoya), reduce en gran medida el potencial de corrupción de datos o la violación de los invariantes.

Y al usar la herencia y el polimorfismo, puede reutilizar clases preexistentes, personalizándolas para que se ajusten a sus necesidades específicas, sin tener que modificar los originales o reescribir todo desde cero. (El cual es un cosa que nunca debes hacer, si puede evitarlo.) Solo tenga cuidado de comprender su objeto base, o podría terminar con canguros asesinos.

Para mí, estos son los principios fundamentales de la programación orientada a objetos: gestión de complejidad, centralización del código y modelado de dominio de problemas mejorado a través de la creación de clases de objetos, herencia y polimorfismo, y mayor seguridad sin sacrificar el poder o el control mediante el uso de la encapsulación y propiedades. Espero que esto te ayude a entender por qué tantos programadores lo encuentran útil.

Editar: en respuesta a la pregunta de Joel en los comentarios,

¿Puede explicar lo que contiene un "programa orientado a objetos" (aparte de estas definiciones elegantes que ha esbozado) que es fundamentalmente diferente de un programa imperativo? ¿Cómo se "consigue la pelota?"

Un pequeño descargo de responsabilidad aquí. Mi modelo de "un programa orientado a objetos" es básicamente el modelo Delphi, que es muy similar al modelo C#/. Net, ya que fueron creados por ex miembros del equipo de Delphi. Lo que digo aquí puede no aplicar, o no aplicar tanto, en otros idiomas OO.

Un programa orientado a objetos es uno en el que toda la lógica está estructurada en torno a los objetos. Por supuesto, esto tiene que ser arrancado en alguna parte. Su programa típico de Delphi contiene código de inicialización que crea un objeto singleton llamado Application. Al comienzo del programa, llama Application.Initialize, entonces una llamada a Application.CreateForm Para cada forma que desea cargar en la memoria desde el principio, y luego Application.Run, que muestra el formulario principal en la pantalla e inicia el bucle de entrada/evento que forma el núcleo de los programas de computadora interactivos.

La aplicación y sus formularios sondean para eventos entrantes del sistema operativo y los traducen en llamadas de método en su objeto. Una cosa que es muy común es el uso de controladores de eventos o "delegados" en .NET-speak. Un objeto tiene un método que dice: "Haga X e Y, pero también verifique si se asigna este controlador de eventos en particular, y llamarlo si es así". Un controlador de eventos es un puntero de método, un cierre muy simple que contiene una referencia al método y una referencia a la instancia del objeto, que se usa para extender el comportamiento de los objetos. Por ejemplo, si tengo un objeto de botón en mi formulario, personalizo su comportamiento al conectar un controlador de eventos OnClick, que hace que algún otro objeto ejecute un método cuando se hace clic en el botón.

Entonces, en un programa orientado a objetos, la mayor parte del trabajo se realiza definiendo objetos con ciertas responsabilidades y vinculándolos, ya sea a través de punteros de método o por un objeto que llama directamente a un método definido en la interfaz pública de otro objeto. (Y ahora volvemos a la encapsulación). Esta es una idea de que no tenía concepto de espalda antes de tomar clases de OOP en la universidad.

Creo que OOP es básicamente un nombre dado a algo que puede haber sido tentado a hacer en el camino, como yo.

Hace mucho tiempo, cuando era un programador de bebés, incluso en Fortran, había un puntero a una subrutina. Es realmente útil poder pasar un puntero a una subrutina como argumento a otra subrutina.

Luego, lo siguiente que sería realmente útil sería almacenar un puntero a una subrutina dentro de un registro de una estructura de datos. De esa manera, podría decir que el registro "sabe" cómo hacer operaciones en sí misma.

No estoy seguro de si alguna vez lo convirtieron en Fortran, pero es fácil de hacer en C y sus descendientes.

Entonces, debajo, es una idea simple y útil que podría haber tenido la tentación de hacer usted mismo, y es más fácil de hacer en idiomas más recientes, incluso si algunas personas lo convirtieron en un carro gigante lleno de palabras de moda.

Hay varios tipos de sistemas OO, y es difícil obtener una definición en la que todos estarán de acuerdo. En lugar de tratar de mostrar cómo el OO de Java es similar al sistema de objetos Lisp Common, comenzaré con algo más convencional, paso a paso.

Supongamos que tiene muchos objetos existentes como datos dispersos. Los puntos, por ejemplo, pueden ser elementos en una matriz X, A Y y A Z. Para considerar un punto en sí, tiene sentido unir todos los datos en algo como una C struct.

Ahora, para cualquier objeto de datos, tenemos los datos todos juntos. Sin embargo, en un programa de procedimiento, el código está disperso. Supongamos que estamos lidiando con formas geométricas. Hay una gran función para dibujar formas, y necesita saber sobre todas las formas. Hay una gran función para encontrar área y otra para el perímetro. El código para un círculo se dispersa a través de múltiples funciones y, para agregar otro tipo de forma, necesitamos saber qué funciones cambiar. En un sistema orientado a objetos, reunimos las funciones en el mismo tipo de cosas (class) como los datos. Por lo tanto, si queremos mirar todo el código del círculo, está ahí en el Circle definición, y si queremos agregar un Quartercircle Simplemente escribimos su clase y tenemos el código.

Un beneficio secundario de esto es que podemos mantener invariantes de clase, cosas que son ciertas sobre cada miembro de la clase. Al restringir el código fuera de la clase de jugar directamente con los miembros de los datos de la clase, tenemos todo el código que puede cambiar los datos de clase en un solo lugar, y podemos confirmar que no hace nada atornillado (como tener un triángulo con una pierna. más largo que los otros dos combinados). Esto significa que podemos contar con algunas propiedades de cada miembro de la clase, y no tenemos que verificar si un objeto es sano cada vez que lo usamos.

El principal beneficio viene con la herencia y el polimorfismo. Definiendo todas estas diversas formas como subclases de una clase llamada Shape, podemos hacer que nuestro código manipule ShapeS, y es el trabajo de los subobjetos de forma hacer lo que sea requerido por las manipulaciones. Esto significa que no necesitamos tocar el código probado en el antiguo cuando agregamos nuevas formas o refinamos el comportamiento de las mayores. Tenemos automáticamente un código antiguo que puede aprovechar directamente el nuevo código. En lugar de hacer que el código de control consciente de todas las diferentes formas posibles y tener que mantener funciones que sean conscientes de todas las diferentes formas posibles, simplemente tratamos con formas y sus propiedades, mientras mantenemos Shape subclases. Esto simplifica el código de control.

Tenemos varias ventajas aquí. Como tenemos invariantes de clase, podemos razonar sobre objetos de datos más grandes de la misma manera que razonamos sobre los tipos incorporados, lo que significa que a menudo podemos dividir conceptos complejos en otros más simples. Dado que el código del círculo está en gran medida contenido en Circle, hemos aumentado la localidad. Dado que no hay conceptos de un círculo disperso a través de varias funciones diferentes en diferentes lugares, obtenemos menos acoplamiento entre las rutinas y no tenemos que preocuparnos por mantenerlas sincronizadas. Dado que las clases son, en efecto, tipos, podemos aprovechar el sistema de tipo existente para atrapar el uso incompatible de nuestras clases.

OO tiene muchas definiciones diferentes, sí. Estoy seguro de que puedes encontrar muchos de estos por tu cuenta. Personalmente me gusta Rees Re: OO Como una forma de darle sentido a ellos. Supongo que ya has leído eso desde que citas a Paul Graham. (Se lo recomiendo a cualquier persona interesada en OO.) Voy a adoptar más o menos la definición de Java aquí {1,2,3,7,8,9}.

La cuestión de la utilidad de OO, especialmente la forma en que lo abordo, merece una respuesta mucho más grande con unos pocos miles de líneas de código (en parte para no ser un montón de afirmaciones). Sin embargo, aquí hay un resumen de ese documento hipotético.

No creo que OO sea terriblemente útil a pequeña escala, por ejemplo, sobre unos pocos cientos de líneas. En particular, los idiomas OO sin buenas influencias funcionales tienden a hacer que sea realmente doloroso hacer cosas simples con cualquier tipo de recopilación o cualquier cosa que necesite muchos tipos de datos. Aquí es donde la mayoría de los patrones de diseño entran en juego; Son auxiliares en la baja potencia del lenguaje subyacente.

A aproximadamente mil líneas, comienza a ser más difícil realizar un seguimiento de todas las operaciones y estructuras de datos y cómo se relacionan. Ayuda, en este punto, tener una forma de organizar explícitamente las estructuras y operaciones de datos, dibujar límites de módulos y definir responsabilidades, y tener una forma conveniente de comprender esas definiciones mientras intenta programar contra ellos.

Java-ish OO es una solución a mitad de camino a estos problemas que han ganado el concurso de popularidad. Debido a que es el mismo mecanismo que las personas Java aplican a los problemas de pequeña escala creados por un lenguaje con poca potencia, tiende a comenzar a parecerse más a una solución mágica a todo que a una forma de mantenerse organizado. Las personas familiarizadas con la programación funcional tienden a preferir otras soluciones, como las clases de tipo de Clos o Haskell, o la metaprogramación de plantillas cuando se queda atrapada en C ++, o de lo contrario (como yo, trabajando diariamente en C#) Use oo pero no se entusiasme todo lo que se entusiasme con eso .

OOP intenta modelar conceptos del mundo real en términos de objetos e interacciones entre ellos. Como humanos, tendemos a procesar el mundo en términos de objetos. El mundo está lleno de objetos que tienen ciertas propiedades y pueden hacer cosas como interactuar con otros objetos. OOP permite modelar el mundo en términos similares. Por ejemplo,

  • La persona es un objeto. Una persona tiene algunas propiedades, como la edad y el género. Una persona puede hacer cosas: comer, dormir, conducir un automóvil.
  • El automóvil también es un objeto (aunque de tipo diferente). También tiene propiedades como Make, Model y Year. Un coche puede hacer cosas: moverse.

Pero un automóvil no puede moverse por sí solo, necesita una persona que lo impulse: interacción entre objetos.

OOP = Estructuras de datos + Paso de mensajes + herencia, todas las cuales son evoluciones lógicas en los modelos de programación.

OOP puede ser entendido (por programadores) en aproximadamente 90 segundos (vea mi perfil para un enlace). Los conceptos son muy simples.

Cómo aplicarlo es otro asunto. El hecho de que sepa cómo balancear un martillo no significa que sepa cómo diseñar y construir una casa. ;-)

Escribí una publicación de blog hace un tiempo que podría encontrar útil: Procedimiento vs. OOP explicado.

La forma en que lo entendí por primera vez es:

Antes de la programación orientada a objetos, tenías Programación estructurada. Todo está centrado en el proceso. La primera pregunta que tienes que hacerte es "¿Qué quiero hacer con la información?".

Con la programación orientada a objetos, se centra en los datos. La primera pregunta que tienes que hacerte es "¿Información de bruja con la que necesito hacer trato?". Esto hace que la abstracción sea más fácil.

Dado que comprende las estructuras, y comprende los punteros de la función, y comprende las estructuras con punteros de funciones, desde su perspectiva, definiría la programación orientada a objetos como simplemente "programación, con un gran uso de estructuras que tienen punteros de funciones". Todavía es programación en el sentido tradicional: todos son datos y código los que actúan sobre los datos. La diferencia es simplemente cómo se define toda esa información y cómo se acerca a la definición.

Quizás una simplificación excesiva es que la programación tradicional es "código, con algunas estructuras de datos", y la programación orientada a objetos es "estructuras de datos, con algún código". Ambos todavía tienen estructuras de datos, y ambos todavía tienen código. La programación orientada a objetos, entonces, no es más que el acto de definir tipos de datos por adelantado, y hacer cumplir los contratos sobre cómo se comunican a través de conjuntos de funciones.

Como ha observado, hay una gran clase de aplicaciones para las cuales esta no es una excelente manera de implementar una solución. Parece que vives en un mundo compuesto predominantemente de tales aplicaciones. En la publicación de su blog, menciona observar las implementaciones del problema "99 botellas de cerveza" (su "escaparate de programación favorito"). 99 botellas de cerveza es ciertamente parte de esa categoría. Tratar de comprender la programación orientada a objetos al observar las implementaciones de 99 botellas de cerveza es un poco como tratar de comprender la arquitectura de gran altura al mirar una casa en el árbol. Incluso una casa en el árbol muy bien construida solo puede enseñarte mucho.

TL; DR: La programación OO es como la programación tradicional, excepto que se enfoca más de su esfuerzo en definir las estructuras de datos por adelantado, y tiene esas estructuras de datos se comunican entre sí a través de punteros de funciones.

Creo que la página de Wikipedia es un buen lugar para obtener los fundamentos:
http://en.wikipedia.org/wiki/object-oriented_programming

Básicamente, la idea es que la programación procesal, que es lo que OOP estaba tratando de mejorar, centrada en los procesos que se modelan. OOP cambia a un modelo donde el enfoque está en las "cosas" que está modelando, y los procesos y los datos de esas cosas están contenidos dentro de esas cosas.

Entonces, como ejemplo, supongamos que estaba diseñando una aplicación para rastrear una lista de tareas. En la programación de procedimientos, sus entidades de nivel superior en el modelo serían los procesos que ocurren, como crear una tarea, eliminar una tarea, cambiar la información de la tarea, etc. En un modelo OOP, se centraría en crear una tarea, y Piense en qué datos y procesos deben ser responsables. Y luego concéntrese en con qué se debe interactuar la tarea de otros objetos, como posiblemente una nota o algo si desea mantener notas sobre las tareas.

Espero que eso ayude. Simplemente siga leyendo sobre él y mirando el código y de repente "haga clic". Esa fue mi experiencia.

Licenciado bajo: CC-BY-SA con atribución
scroll top