Creo que puede ser útil una publicación mía en el blog sobre abstracciones con fugas. Aquí está el trasfondo relevante:
La abstracción es un mecanismo para ayudar a tomar lo que es común entre un conjunto de fragmentos de programas relacionados, eliminar sus diferencias y permitir a los programadores trabajar directamente con una construcción que represente ese concepto abstracto. Esta nueva construcción (virtualmente) siempre tiene parametrizaciones : un medio para personalizar el uso de la construcción para satisfacer sus necesidades específicas.
Por ejemplo, una List
clase puede abstraer los detalles de una implementación de lista enlazada, donde en lugar de pensar en términos de manipulación next
y previous
punteros, puede pensar en el nivel de agregar o eliminar valores a una secuencia. La abstracción es una herramienta esencial para crear características útiles, ricas y a veces complejas a partir de un conjunto mucho más pequeño de conceptos más primitivos.
La abstracción está relacionada con la encapsulación y la modularidad, y estos conceptos a menudo se malinterpretan.
En el List
ejemplo, la encapsulación se puede usar para ocultar los detalles de implementación de una lista vinculada; en un lenguaje orientado a objetos, por ejemplo, puede hacer que los punteros next
y sean previous
privados, donde solo la implementación de la Lista tiene acceso a estos campos.
La encapsulación no es suficiente para la abstracción, porque no implica necesariamente que tenga una concepción nueva o diferente de las construcciones. Si todo lo que hizo una List
clase fue darle métodos de acceso de estilo ' getNext
' / ' setNext
', se encapsularía de usted a partir de los detalles de implementación (por ejemplo, ¿nombró el campo ' prev
' o ' previous
'? ¿Cuál era su tipo estático?), Pero tendría un grado muy bajo de abstracción.
La modularidad se refiere a la ocultación de información : las propiedades estables se especifican en una interfaz, y un módulo implementa esa interfaz, manteniendo todos los detalles de implementación dentro del módulo. La modularidad ayuda a los programadores a hacer frente al cambio, porque otros módulos dependen solo de la interfaz estable.
La encapsulación ayuda a ocultar la información (de modo que su código no dependa de detalles de implementación inestables), pero la encapsulación no es necesaria para la modularidad. Por ejemplo, se puede implementar una List
estructura en C, la exposición de los ' next
' y ' prev
punteros' al mundo, sino que también proporcionan una interfaz, que contiene initList()
, addToList()
yremoveFromList()
funciones Siempre que se sigan las reglas de la interfaz, puede garantizar que ciertas propiedades siempre se mantendrán, como garantizar que la estructura de datos esté siempre en un estado válido. [El clásico artículo de Parnas sobre modularidad, por ejemplo, fue escrito con un ejemplo en asamblea. La interfaz es un contrato y una forma de comunicación sobre el diseño, no necesariamente tiene que verificarse mecánicamente, aunque eso es en lo que confiamos hoy.]
Aunque los términos abstracto, modular y encapsulado se usan como descripciones de diseño positivas, es importante darse cuenta de que la presencia de cualquiera de estas cualidades no le proporciona automáticamente un buen diseño:
Si un algoritmo n ^ 3 está "bien encapsulado", seguirá funcionando peor que un algoritmo n log n mejorado.
Si una interfaz se compromete con un sistema operativo específico, ninguno de los beneficios de un diseño modular se logrará cuando, por ejemplo, un videojuego necesite ser portado de Windows al iPad.
Si la abstracción creada expone demasiados detalles no esenciales, no podrá crear una nueva construcción con sus propias operaciones: simplemente será otro nombre para la misma cosa.