Cuando se implementa una estructura de datos (por ejemplo, una cola) utilizando un lenguaje OOP, algunos miembros de la estructura de datos deben ser privados (por ejemplo, el número de elementos en la cola).
Una cola también se puede implementar en un lenguaje de procedimiento utilizando ay struct
un conjunto de funciones que operan en el struct
. Sin embargo, en un lenguaje de procedimiento no puede hacer que los miembros de un struct
privado. ¿Se dejaron públicos los miembros de una estructura de datos implementados en un lenguaje de procedimiento, o hubo algún truco para hacerlos privados?
object-oriented
data-structures
history
Christopher
fuente
fuente
Respuestas:
OOP no inventó la encapsulación y no es sinónimo de encapsulación. Muchos lenguajes OOP no tienen modificadores de acceso de estilo C ++ / Java. Muchos lenguajes que no son OOP tienen varias técnicas disponibles para ofrecer encapsulación.
Un enfoque clásico para la encapsulación es el cierre , como se usa en la programación funcional . Esto es significativamente más antiguo que OOP pero es de alguna manera equivalente. Por ejemplo, en JavaScript podríamos crear un objeto como este:
El
plus2
objeto anterior no tiene ningún miembro que permita el acceso directox
, está completamente encapsulado. Eladd()
método es un cierre sobre lax
variable.El lenguaje C admite algunos tipos de encapsulación a través de su mecanismo de archivo de encabezado , particularmente la técnica de puntero opaco . En C, es posible declarar un nombre de estructura sin definir sus miembros. En ese momento, no se puede usar ninguna variable del tipo de esa estructura, pero podemos usar punteros a esa estructura libremente (porque el tamaño de un puntero de estructura se conoce en tiempo de compilación). Por ejemplo, considere este archivo de encabezado:
Ahora podemos escribir código que use esta interfaz Adder, sin tener acceso a sus campos, por ejemplo:
Y aquí estarían los detalles de implementación totalmente encapsulados:
También existe la clase de lenguajes de programación modulares , que se centra en las interfaces de nivel de módulo. La familia de idiomas ML incl. OCaml incluye un enfoque interesante para los módulos llamados functores . OOP eclipsó y moduló en gran medida la programación modular, sin embargo, muchas de las supuestas ventajas de OOP tienen más que ver con la modularidad que con la orientación a objetos.
También se observa que las clases en lenguajes OOP como C ++ o Java a menudo no se usan para objetos (en el sentido de entidades que resuelven operaciones mediante un enlace tardío / despacho dinámico), sino simplemente para tipos de datos abstractos (donde definimos una interfaz pública que oculta detalles de implementación interna). El documento Sobre la comprensión de la abstracción de datos, revisado (Cook, 2009) analiza esta diferencia con más detalle.
Pero sí, muchos idiomas no tienen ningún mecanismo de encapsulación. En estos idiomas, los miembros de la estructura se dejan públicos. A lo sumo, habría una convención de nomenclatura para desalentar el uso. Por ejemplo, creo que Pascal no tenía un mecanismo de encapsulación útil.
fuente
Adder self = malloc(sizeof(Adder));
? Hay una razón por la que se escriben punteros ysizeof(TYPE)
generalmente está mal visto.sizeof(*Adder)
, porque*Adder
no es un tipo, así como*int *
tampoco es un tipo. La expresiónT t = malloc(sizeof *t)
es idiomática y correcta. Mira mi edición.private static
variables en Java. Del mismo modo, para C podría usar punteros opacos para pasar datos en Pascal sin declarar de qué se trataba. El MacOS clásico utilizaba muchos punteros opacos, ya que las partes públicas y privadas de un registro (estructura de datos) podían pasarse juntas. Recuerdo que Window Manager hizo mucho de esto, ya que partes del Registro de Windows eran públicas, pero también se incluyó cierta información interna._private_member
youtput_property_
, o técnicas más avanzadas para hacer objetos imputables.Primero, ser procesal versus orientado a objetos no tiene nada que ver con lo público versus lo privado. Muchos lenguajes orientados a objetos no tienen noción de control de acceso.
En segundo lugar, en "C", que la mayoría de las personas llamaría de procedimiento, y no orientado a objetos, hay muchos trucos que puedes usar para hacer que las cosas sean privadas de manera efectiva. Una muy común es utilizar punteros opacos (por ejemplo, nulo *). O bien, puede reenviar la declaración de un objeto y no definirlo en un archivo de encabezado.
foo.h:
foo.c:
¡Mira el SDK de Windows! Utiliza HANDLE y UINT_PTR, y cosas así para ser manejadores genéricos de la memoria utilizada en las API, lo que hace que las implementaciones sean privadas.
fuente
"Tipos de datos opacos" era un concepto bien conocido cuando obtuve mi título en informática hace 30 años. No cubrimos OOP ya que no era de uso común en ese momento y la "programación funcional" se consideraba más correcta.
Modula-2 tenía soporte directo para ellos, ver https://www.modula2.org/reference/modules.php .
Lewis Pringle ya ha explicado cómo se puede utilizar la declaración progresiva de una estructura en C. A diferencia del Módulo 2, se tenía que proporcionar una función de fábrica para crear el objeto. ( Los métodos virtuales también fueron fáciles de implementar en C al hacer que el primer miembro de una estructura sea un puntero a otra estructura que contenía punteros de función a los métodos).
A menudo también se usó la convención. Por ejemplo, no se debe acceder a ningún campo que comience con "_" fuera del archivo que poseía los datos. Esto se hizo cumplir fácilmente mediante la creación de herramientas de verificación personalizadas.
Todos los proyectos a gran escala en los que he trabajado (antes de pasar a C ++ y luego a C #) tenían un sistema para evitar que el código incorrecto acceda a los datos "privados". Fue un poco menos estandarizado de lo que es ahora.
fuente
Tenga en cuenta que hay muchos idiomas OO sin una capacidad incorporada para marcar miembros como privados. Esto puede hacerse por convención, sin necesidad de que el compilador imponga la privacidad. Por ejemplo, las personas a menudo prefijarán variables privadas con un guión bajo.
Existen técnicas para dificultar el acceso a variables "privadas", siendo la más común el lenguaje PIMPL . Esto coloca sus variables privadas en una estructura separada, con solo un puntero asignado en sus archivos de encabezado públicos. Esto significa una desreferencia adicional y un reparto para obtener variables privadas, algo así como
((private_impl)(obj->private))->actual_value
, lo que se vuelve molesto, por lo que en la práctica rara vez se usa.fuente
Las estructuras de datos no tenían "miembros", solo campos de datos (suponiendo que fuera un tipo de registro). La visibilidad generalmente se estableció para todo el tipo. Sin embargo, eso puede no ser tan limitante como cree, porque las funciones no formaban parte del registro.
Regresemos y obtengamos un poco de historia aquí ...
El paradigma de programación dominante antes de OOP se llamaba programación estructurada . El objetivo principal inicial de esto era evitar el uso de declaraciones de salto no estructuradas ("goto" s). Este es un paradigma orientado al flujo de control (mientras que OOP está más orientado a los datos), pero todavía era una extensión natural para intentar mantener los datos estructurados lógicamente al igual que el código.
Otro resultado de la programación estructurada fue la ocultación de información , la idea de que las implementaciones de la estructura del código (que probablemente cambie con bastante frecuencia) deberían mantenerse separadas de la interfaz (que idealmente no cambiará tanto). Ahora es un dogma, pero en los viejos tiempos, muchas personas realmente consideraban mejor que cada desarrollador conociera los detalles de todo el sistema, por lo que en un momento fue una idea controvertida. La edición original de The Mythical Man Month de Brook en realidad argumentaba en contra de la ocultación de información.
Los lenguajes de programación posteriores diseñados explícitamente para ser buenos lenguajes de programación estructurados (por ejemplo, Modula-2 y Ada) generalmente incluían la ocultación de información como un concepto fundamental, construido alrededor de algún tipo de concepto de una instalación cohesiva de funciones (y cualquier tipo, constantes y objetos que puedan necesitar). En Modula-2 estos se llamaron "Módulos", en Ada "Paquetes". Muchos lenguajes OOP modernos llaman al mismo concepto "espacios de nombres". Estos espacios de nombres fueron la base organizativa del desarrollo en estos lenguajes, y para la mayoría de los propósitos podrían usarse de manera similar a las clases OOP (por supuesto, sin soporte real para la herencia).
Entonces, en Modula-2 y Ada (83) podría declarar cualquier rutina, tipo, constante u objeto en un espacio de nombres privado o público, pero si tenía un tipo de registro, no había forma (fácil) de declarar algunos campos de registro públicos y otros privados. O todo su registro es público, o no lo es.
fuente
object.method()
invocación es solo azúcar sintáctico. En mi humilde opinión, vea el Principio de acceso / referencia uniforme de Meyer, pero aún así solo el azúcar sintáctico.object.method()
como una forma alternativamethod(object, ...)
para las personas que simplemente no podían dar el salto conceptual.En C, ya podría pasar punteros a tipos declarados pero indefinidos como otros han dicho, en efecto restringiendo el acceso a todos los campos.
También puede tener funciones privadas y públicas módulo a módulo. Las funciones declaradas estáticas en el archivo fuente no son visibles para el exterior, incluso si intenta adivinar su nombre. Del mismo modo, puede tener variables globales estáticas a nivel de archivo, lo que generalmente es una mala práctica, pero permite el aislamiento por módulos.
Probablemente sea importante destacar que la restricción de acceso como una convención bien estandarizada en lugar de una construcción aplicada por el lenguaje funciona bien (ver Python). Además de eso, restringir el acceso a los campos de objetos solo protegerá al programador cuando sea necesario cambiar el valor de los datos dentro de un objeto después de la creación. Que ya es un olor a código. Podría decirse que la
const
palabra clave de C y, en particular, de C ++ para métodos y argumentos de función es una ayuda mucho mayor para el programador que la bastante pobre de Javafinal
.fuente
static
datos y operaciones globales (lo que significaba que no se presentaron al enlazador para su uso desde otras compilaciones). Puede argumentar plausiblemente que cualquier soporte que C tenía para buenas prácticas de diseño de software, aparte de eso, fue prácticamente un truco, y no forma parte del diseño original del lenguaje en 1972.Si su definición de Público es la capacidad de acceder a la implementación y a los datos / propiedades a través de su propio código en cualquier momento, la respuesta es simplemente: Sí . Sin embargo, fue abstraído por diversos medios, dependiendo del idioma.
Espero que esto haya respondido sucintamente a su pregunta.
fuente
Aquí hay un contraejemplo muy simple: en Java,
interface
s define objetos, peroclass
es no. Aclass
define un tipo de datos abstractos, no un objeto.Ergo, cada vez que usa
private
unclass
en Java, tiene un ejemplo de una estructura de datos con miembros privados que no está orientada a objetos.fuente