¿Por qué (/ hizo) Bertrand Meyer piensa que la subclase es la única forma de extender un módulo "cerrado"?

19

En Meyer's Object-Oriented Software Construction (1988) define el principio abierto / cerrado de la siguiente manera:

  • Se dirá que un módulo está abierto si todavía está disponible para la extensión. Por ejemplo, debería ser posible agregar campos a las estructuras de datos que contiene, o nuevos elementos al conjunto de funciones que realiza.
  • Se dirá que un módulo está cerrado si está disponible para su uso por otros módulos. Esto supone que el módulo ha recibido una descripción estable y bien definida (la interfaz en el sentido de ocultar información).

Él continúa diciendo:

Si vuelve a abrir un módulo, también debe volver a abrir todos sus clientes para actualizarlos, ya que dependen de la versión anterior. ... [Este problema] surge cada vez que un módulo debe extenderse por una nueva función o elemento de datos, lo que desencadena cambios en clientes directos e indirectos. ... Con los enfoques clásicos de diseño y programación, no hay forma de escribir módulos abiertos y cerrados.

La solución de Meyer a este dilema es: nunca amplíe un módulo de biblioteca modificando las clases existentes; en su lugar, escriba un nuevo módulo que subclasifique las clases existentes y haga que los nuevos clientes dependan de ese nuevo módulo.

Ahora, en 1988, estaba escribiendo programas de juguete (de procedimiento) en Turbo Pascal y Blankenship Basic, y mi experiencia profesional del siglo XXI es en JVM, CLR y en lenguajes dinámicos, así que no sé qué quería decir Meyer por "enfoques clásicos de diseño y programación".

El ejemplo concreto de Meyer de por qué los módulos del cliente deben volver a abrirse (una declaración de cambio en una enumeración que ahora tiene más miembros, que requiere más casos) parece bastante razonable, pero no justifica la afirmación de que cada vez que agrega funcionalidad a una biblioteca módulo, necesita actualizar todos sus clientes .

¿Hay alguna razón histórica de que esta afirmación pareciera evidente en 1988? Por ejemplo, ¿agregar funciones o estructuras de datos a una biblioteca estática en C cambió el diseño de tal manera que incluso con API compatibles con versiones anteriores, los clientes tuvieran que volver a compilarse? ¿O Meyer realmente está hablando de un mecanismo para hacer cumplir la compatibilidad con API hacia atrás?

David Moles
fuente
3
¡Interesante pregunta! Tengo la sensación de que la respuesta estará relacionada de alguna manera con la diferencia fundamental entre los tipos de datos abstractos y la abstracción de datos orientada a objetos , que son los dos mecanismos dominantes de abstracción de datos en la programación modular (a lo que Betrand Meyer se refiere como "enfoques clásicos" ") y Programación orientada a objetos (¡lea los comentarios!), respectivamente.
Jörg W Mittag
Eso es extraño. Parece descaradamente contradicha por la realidad (incluso en 1988). Además, su enfoque recomendado daría lugar a una proliferación inútil de módulos.
@ dan1111: el enfoque de la herencia de Eiffel, que incluye, entre otros, su enfoque de la herencia múltiple es diferente de C ++, Java, C #, etc., por lo que no es sorprendente que el enfoque sea diferente. Desarrolló Eiffel específicamente para apoyar sus puntos de vista sobre OO, después de todo.
Jörg W Mittag

Respuestas:

18

Por lo que puedo decir, esta pregunta ha sido respondida por el propio Bertrand Meyer, y la respuesta es que esta afirmación no es precisa. Con los enfoques clásicos de diseño y programación, de hecho, puede haber una manera de escribir módulos abiertos y cerrados.

Para descubrir esto, debe estudiar la segunda edición de este libro (publicado nueve años después, en 1997). Según el Prólogo de la segunda edición , es

No es una actualización, sino el resultado de una revisión exhaustiva. Ningún párrafo de la versión original se ha dejado intacto. (Apenas una sola línea, en realidad).

En particular, la declaración que te confunde ha desaparecido. Todavía hay un capítulo de principio abierto-cerrado en "§3.3 Cinco principios", y hay una discusión más a fondo de este tema en "§14.7 Introducción a la herencia", pero la declaración de la primera edición ya no está allí.

En cambio, lo que hay allí se centra en cómo es más conveniente e idiomático en el enfoque OO en lugar de las formas anteriores,

Gracias a la herencia, los desarrolladores de OO pueden adoptar un enfoque de desarrollo de software mucho más incremental que el que solía ser posible con métodos anteriores ... (§3.3)

Este doble requisito (abierto y cerrado) parece un dilema, y ​​las estructuras de módulos clásicas no ofrecen ninguna pista. Pero la herencia lo resuelve. Una clase está cerrada, ya que puede compilarse, almacenarse en una biblioteca, basarse y usarse por clases de clientes. Pero también está abierto, ya que cualquier clase nueva puede usarlo como padre, agregando nuevas características y redeclarando características heredadas; en este proceso no hay necesidad de cambiar el original o molestar a sus clientes ... (§14.7)

Ya que también parece preguntarse qué significa "enfoques clásicos" Meyer aquí, puede encontrar una explicación de estos en §4.7 Estructuras modulares tradicionales . Esta sección explica que esto significa "bibliotecas de rutinas" y "paquetes" (para este último, el autor dice que el término se toma de Ada y menciona otros idiomas que tienen esta característica: clústeres en CLU y módulos en Modula).

Si lo piensa, ninguno de estos enfoques fue originalmente diseñado para ayudar a escribir código que se adhiera al principio abierto-cerrado. Esto podría llevar al autor a su evaluación algo prematura que luego se corrigió en la segunda edición.


En cuanto a lo que específicamente hizo que el autor cambiara de opinión sobre esa afirmación entre la primera y la segunda edición, creo que uno puede encontrar una respuesta, nuevamente, en el libro mismo, es decir, en la Parte F: Aplicación del método en varios idiomas y entornos " . En este capítulo, el autor analiza cómo los métodos orientados a objetos se pueden usar en idiomas más antiguos:

Los lenguajes clásicos como Fortran no son OO en absoluto, pero las personas que aún deben usarlos ... tal vez quieran aplicar tantas ideas OO como sea posible dentro de las limitaciones de estos enfoques más antiguos.

En particular, en esta parte, Meyer explica en detalle cómo sería posible implementar la herencia (con algunas advertencias y limitaciones, pero aún así) en C e incluso en Fortran.

Verá, esto realmente requiere revisar esa declaración de la primera edición. Parece prácticamente imposible explicar cómo conciliar "con los enfoques clásicos ... no hay forma" con ejemplos realistas sobre cómo exactamente se puede hacer.

mosquito
fuente
Interesante, y definitivamente tendré que tratar de obtener la segunda edición, pero aún no me queda claro por qué incluso una biblioteca "clásica" que no sea OO no podría agregar (al menos ciertos tipos de) características sin alterar su clientela.
David Moles
@DavidMoles cosa es que pude , y la última parte de mi respuesta explica que, Meyer y que él mismo se dio cuenta de que (cuando él volvió a trabajar para la 2da edición) e incluso dio ejemplos de cómo se puede hacer. "En cuanto al cambio autor lo que específicamente hecho su mente ...", etc
mosquito
Hmm No veo "la versión 2 de esta biblioteca, que reemplaza la versión 1 y es compatible con versiones anteriores, agrega las siguientes funciones ..." como "herencia", excepto en la forma conceptual más amplia posible.
David Moles
(La herencia, para mí, implica que la versión 1 todavía está disponible y se llama por la versión 2.)
David Moles
@DavidMoles reemplazar con la versión 2 (como en, cambiar el código fuente y recompilar ) no calificaría como "cerrado para modificación", simplemente puede verificar esto en el artículo de Wikipedia : "la entidad puede permitir que su comportamiento se extienda sin modificar su código fuente ... "
mosquito