El uso de getters y setters para diferentes lenguajes de progtwigción

Así que sé que hay muchas preguntas sobre captadores y definidores en general, pero no pude encontrar algo exactamente como mi pregunta. Me preguntaba si la gente cambia el uso de get / set en función de los diferentes idiomas. Comencé a aprender con C ++ y me enseñaron a usar captadores y definidores. Esto es lo que entiendo:

En C ++ (y Java?), Una variable puede ser pública o privada, pero no podemos tener una mezcla. Por ejemplo, no puedo tener una variable de solo lectura que aún pueda cambiarse dentro de la clase. Es todo público (puede leerlo y cambiarlo) o todo privado (no puede leer y solo puede cambiar dentro de la clase). Debido a esto (y posiblemente a otras razones), usamos captadores y definidores.

En MATLAB, puedo controlar las propiedades “setaccess” y “getaccess” de las variables, de modo que puedo hacer que las cosas sean de solo lectura (puedo acceder directamente a la propiedad, pero no puedo sobrescribirla). En este caso, no creo que necesite un captador porque solo puedo hacer la propiedad class.property .

Además, en Python, se considera “Pythonic” no usar getters / setters y solo poner las cosas en propiedades si es necesario. Realmente no entiendo por qué está bien tener todas las variables públicas en Python, porque es lo contrario de lo que aprendí cuando comencé con C ++.

Solo tengo curiosidad por saber qué piensan los demás sobre esto. ¿Usarías getters y setters para todos los idiomas? ¿Solo lo utilizarías para C ++ / Java y harías acceso directo en MATLAB y Python (que es lo que estoy haciendo actualmente)? ¿Se considera mala la segunda opción? Para mis propósitos, solo me refiero a simples captadores y definidores (solo devuelva / establezca el valor y no haga nada más).

¡Gracias!

En realidad, los captadores y los establecedores (así como las propiedades públicas que los ocultan) son muy poco mejoradores que las variables públicas, y un indicador bastante bueno para las cuasi clases .

Está bien tener todas las variables públicas en cualquier idioma. Sí, ya sé que es lo opuesto a lo que aprendiste.

La teoría OO dice que debería haber una API pública que sea estable y variables privadas, donde pueda hacer lo que quiera, y una implementación que pueda cambiar de la manera más placentera sin cambiar la API.

Y esto es correcto. Pero lo que no es correcto es la idea de que la API privada debe ser inaccesible para otras clases. Esto es simplemente un error en la teoría OO. Es una idea que suena razonable en el papel, pero en la práctica tiene poco que ofrecer, pero causa muchos problemas.

Por ejemplo, hace muchos años necesitaba subclasificar un widget en Delphi para que se comportara de forma ligeramente diferente. No hay mucho que se vea, solo un poco. Pero el código que necesitaba para anular se llamaba un método que era privado, por lo que no podía anularlo. En su lugar, necesitaba anular ambos métodos. Y, por supuesto, ese otro método hizo cosas que eran realmente internas, así que terminé básicamente no subclasificando el widget, sino duplicándolo, solo porque hice un pequeño cambio.

La teoría OO afirma que así es como debería ser, porque el horror del horror, tal vez de lo contrario, mi subclase podría dejar de funcionar con la próxima versión de Delphi, ¡si la superclase cambia algo interno! Bueno, ¿y qué? En ese caso yo solo lo arreglaría.

Es mi problema si uso partes de sus datos internos. No necesitas preocuparte. Lo que debe hacer es marcar de alguna manera que “Este bit es interno y podría cambiar, úselo bajo su propio riesgo”. Pero cuando usted, como desarrollador de una biblioteca, me impide activamente usar bits internos, solo me está causando problemas.

Ahora he desarrollado casi exclusivamente con Python durante los próximos diez años, y la apertura de Python nunca me ha causado problemas, y el hecho me ha salvado el culo varias veces (ya que puedo corregir errores de marco simplemente parcheando el código fijo en tiempo de ejecución). El modelo OO estándar de Delphis con diferentes niveles de protección me causó problemas varias veces durante los dos años que trabajé con él.

La teoría OO es, de hecho, errónea. No hay nada útil en tener miembros privados. Todo debe ser público. Y eso va para cualquier idioma, en mi experiencia.

Generalmente, no uso captadores / setters porque la presencia de ellos indica que mi clase no está haciendo lo suficiente para estar vivo.

Cuando considero que los necesito, siempre los creo, sin importar si el lenguaje admite la mezcla de variables de acceso y wrt. Solo el tiempo que consideraría no hacerlo es en lenguajes como VB que admiten “propiedades” donde una función puede parecerse a un acceso variable. La razón clave aquí es que no quiero que los clientes estén atados al hecho de que la propiedad está implementada por una variable.

Depende de lo abstraído que necesites. Por ejemplo, recientemente necesité un getter y setter en C ++ al abstraer un objeto Text. El objeto de texto Direct3D solo contenía una cadena de texto variable de miembro. Sin embargo, el objeto de Texto Direct2D tuvo que recrearse y volver a crearse y ese tipo de cosas. Si hubiera optado por variables públicas al diseñar la abstracción original, habría tenido que rediseñar la interfaz y cambiar todo el código dependiente. Si bien estoy de acuerdo en que los captadores y establecedores en ciertos tipos de clases no tienen sentido, hay algunos casos en que son necesarios.

Por supuesto, los idiomas con propiedades no necesitan este tipo de cosas. Pero conceptualmente, son lo mismo. Definir una propiedad sobre una variable es solo un generador y un definidor con azúcar sintáctica, y si bien apoyo el azúcar sintáctico, no cambia la encapsulación. No cambiaría mi diseño de encapsulación idioma por idioma. Por supuesto, la opinión de la comunidad sobre si o no la encapsulación es algo bueno es otra cuestión, es probable que esa sea la diferencia que está viendo. En C ++, la encapsulación tiene una calificación muy alta, mientras que la comunidad Python se preocupa menos por ella.

En Matlab, cada llamada de función adicional incurre en cierta sobrecarga. Por lo tanto, si no necesita un configurador, ya que alguna función de idioma le permite hacer exactamente lo mismo, entonces realmente no puedo ver por qué no querría usar la función de idioma.

Python, al ser un lenguaje de secuencias de comandos dynamic, tiene menos que ver con las restricciones de tiempo de comstackción y más con la flexibilidad.

Getters y setters (“propiedad” es solo getter + setter) permiten una mejor encapsulación (verificación de validez, solo getter, no setter; los detalles de la implementación no importan, por ejemplo, el tiempo tiene horas, minutos, segundos, pero ¿cómo se almacenan realmente los datos? ¿Cuida?), y la extensibilidad futura (por ejemplo, el código del setter puede cambiar, a los consumidores no les importa).

En los lenguajes modernos y eficientes, como C ++, hay alineación , por lo que no hay costo de rendimiento para los captadores / configuradores simples.

El punto es, usar los campos públicos para la progtwigción estructural y simple (a pequeña escala), usar captadores y definidores para proyectos OOP a gran escala.

En realidad debería ser todo lo mismo. Siempre me refiero a una situación de la vida real, antes de poner algo en público o no. ¿Todos pueden tener acceso al motor de mi coche? . La mayoría de las veces, la respuesta es no, porque es mía. Las personas pueden verlo, pero no pueden cambiarlo, porque quieren hacerlo.

Por eso, los buscadores y los instaladores son siempre importantes en todos los idiomas. Lo único es que es diferente en diferentes idiomas sobre cómo establecer los derechos de acceso. Entonces, como dices, si Python realmente quiere poner todo en público, me parece mal. Pero establecer los derechos de acceso en MATLAB en cierta medida, me parece muy correcto.

En cuanto a la diferencia en propiedades y captadores. La mayoría de las veces, si ambos están disponibles en un idioma, existen algunas reglas para eso. Por ejemplo, en C# , se recomienda usar propiedades, cuando la propiedad se comporta como una variable normal y se asegura que la función es solo O(1) . Si la propiedad tiene más que hacer, como lógica adicional, se debe crear una función en lugar de [Reglas de propiedades en C# ] .

Concluyendo: Todo debe ser lo más private posible. Crea los puntos de acceso a ti mismo. Las propiedades son captadoras y definidoras en un diseño agradable, porque se parece a una variable y hace algunas comprobaciones adicionales si es necesario. Pero no demasiado.

Python y C ++ tienen diferentes principios. C ++ y Java son bastante “estáticos” y tienen muchos controles de tiempo de comstackción, por lo que debería explotarlos cuando use C ++ y Java: público vs. privado, corrección de constantes, etc. Además, no tienen propiedades, por lo que si encuentra Para poder realizar una validación de parámetros, no puede convertir fácilmente una variable miembro pública en un par getter-setter sin cambiar la syntax y romper el código existente. Python, por otro lado, es un lenguaje dynamic que permite que todos puedan hacer todo: puede anular todas las variables de cada módulo, no se puede aplicar la encapsulación, no hay controles de tipo estático, etc. La gente de Python suele decir “somos todos los adultos “, y que no debe confiar en el comportamiento indocumentado y utilizar pruebas de unidad en lugar de controles de tiempo de comstackción. No estoy en posición de juzgar qué es lo mejor, pero en general debería atenerse a las convenciones establecidas de su idioma.

Tienes razón: no hay necesidad de “simples” captadores y creadores en el moderno Matlab OOP; Los modificadores de acceso que mencionaste son la “forma correcta”.

En las nuevas clases de MCOS Matlab, la syntax para acceder a una propiedad de clase es la misma, ya sea que definas o configuradores personalizados o no. Los clientes siempre pueden acceder a la propiedad foo como “obj.foo”. Si decide agregar los métodos especiales “get.foo” y “set.foo”, Matlab los llama implícitamente cuando un cliente accede a esa propiedad mediante la syntax “obj.foo”. Entonces no es realmente “acceso directo a campos” como los campos públicos en Java o C ++. Es como el modelo “Acceso uniforme” de Scala. (Creo que el “.” la syntax y los controles de acceso declarativo que mencionas son sencillos y te permiten agregar de manera transparente la lógica personalizada cuando la necesitas, sin comprometerte a escribir el código de la plantilla en la parte delantera. La ubicuidad de los getters y setters definidos por el usuario en Java es parcialmente porque el lenguaje carece de estas características.

En las clases de Matlab de estilo antiguo, lo inverso es cierto: todos los campos son privados, por lo que debe escribir sus propios getter / setters. La convención que he visto es escribir un solo método con el mismo nombre que la propiedad que se obtiene o establece dependiendo de si lo llama “foo (obj)” o “foo (obj, NewValue)”.

Considere este fragmento de c ++:

 class C { public: const T &get_t() const { return t; } void set_t(const T &value) { t = value; } private: T t; }; 

En este ejemplo, el miembro “t” es efectivamente parte de la interfaz pública de C, debido a las funciones de acceso. Sin embargo, a menudo, las funciones de acceso son más complicadas, realizan cálculos, administran la concurrencia, etc. En estos casos, el acceso a “t” se encapsula con las operaciones deseadas dentro de las funciones de acceso.

En C ++ no es posible encapsular las operaciones de acceso con otras operaciones con acceso directo de miembros de datos, por lo que utilizamos funciones de acceso. De hecho, utilizamos funciones de acceso incluso cuando el acceso simple es todo lo que es necesario porque

  1. Si combina el acceso directo con las funciones de acceso, es difícil recordar qué miembros usan qué tipo de acceso, y

  2. es difícil predecir si es posible que necesite que sus encargados de accesos hagan más en el futuro. Si lo hace, y usó los accesores, puede cambiarlos sin cambiar su interfaz pública (API).

A través de las propiedades, Python proporciona una consistencia de acceso mediante la syntax natural de acceso directo, así como la capacidad de agregar funcionalidad al acceso de los miembros de datos, aunque los captadores y definidores (ocultos).

Además, la privacidad de los datos se logra mediante una convención en Python utilizando guiones bajos en los nombres de los miembros para indicar a los usuarios que un miembro en particular no es parte de la interfaz pública de una clase. Los usuarios violan la convención, pero luego son libres de guardar ambas piezas si se rompe. Los progtwigdores de Python llaman a esto la progtwigción de “Todos somos adultos aquí”.

 class C: def get_t(self): return self._t def set_t(self, t): self._t = t t = property(get_t, set_t) 

En este ejemplo, _t es convencionalmente privado y se accede a través de su interfaz de propiedad, pero aún así comparte una syntax de acceso directo y natural con otros miembros de datos.