¿El alcance de la clase no es puramente para la organización? [duplicar]

13

¿No es el alcance solo una forma de organizar clases, impidiendo que el código externo acceda a ciertas cosas a las que no quieres acceder?

Más específicamente, ¿hay alguna ganancia funcional de tener los métodos de public , protected o private ? ¿Hay alguna ventaja en clasificar el alcance del método / propiedad en lugar de, digamos, simplemente public -ize todo?

Mi presunción dice no simplemente porque, en el código binario, no hay un sentido de alcance (aparte de r / w / e, que no es realmente un alcance en absoluto, sino permisos globales para un bloque de memoria). ¿Esto es correcto?

¿Qué pasa con lenguajes como Java y C # [.NET]?

    
pregunta Qix 23.10.2012 - 09:18

9 respuestas

16

Como señala, el motivo principal es la organización.

Lo veo como un canal de comunicación entre los codificadores y los mantenedores, para aclarar la intención del diseño y mantener el código limpio el mayor tiempo posible.

Por supuesto, esto es cierto no solo para OOP sino también para cualquier diseño modular.

    
respondido por el mouviciel 23.10.2012 - 09:23
18

Estoy escribiendo desde una perspectiva de Java (para evitar tener que poner 'desde una perspectiva de Java' en todas partes).

El diseño cuidadoso de una API es algo más que una simple "organización". Muchas de las clases públicas que escribo son utilizadas por muchos clientes y al usar el modificador de acceso más bajo posible, soy libre de cambiar el funcionamiento interno de mis clases sin romper su código (¡y por lo tanto recibir llamadas y correos electrónicos desagradables!).

tl; dr : la encapsulación / ocultación de información, puede cambiar su representación y funcionamiento interno sin romper el código del cliente, los campos mutables públicos no son seguros para subprocesos, promueven la inmutabilidad.

Un módulo que está bien diseñado ocultará sus datos internos y los detalles de implementación de otros módulos y separará limpiamente su API de su implementación. Esto significa que la comunicación entre los módulos se realiza solo a través de sus API y son ajenos al funcionamiento interno de cada uno.

La importancia de esto es que desacopla los módulos entre sí, lo que permite desarrollarlos, probarlos, utilizarlos, optimizarlos y modificarlos de forma aislada, y se pueden desarrollar en paralelo. También aumenta la reutilización porque los módulos que no están estrechamente acoplados pueden potencialmente usarse en otros contextos.

En el libro de Joshua Bloch "Java efectiva", afirma que la regla de oro es:

  

haga que cada clase o miembro sea lo más inaccesible posible. En otras palabras, use el nivel de acceso más bajo posible en consonancia con el correcto funcionamiento del software que está escribiendo.

Después de diseñar su API pública, su instinto debe ser hacer que todo lo demás sea privado, y solo si otra clase en el mismo paquete realmente necesita acceder a un miembro, debe hacerlo privado del paquete (eliminar el modificador). La necesidad de miembros protegidos en una clase pública debe ser relativamente rara, ya que un miembro protegido se convierte en parte de la API exportada de la clase.

Cuando tiene todo como público, significa que se accede directamente a los campos de datos de la clase y que no puede cambiar su representación sin cambiar la API. En general, tampoco puede cambiar el funcionamiento interno de su clase, ya que tiene el potencial de romper el código de quienquiera que esté usando su clase. Este problema / riesgo se multiplica por el número de sus clientes, ya que su clase puede usarse en todas partes.

Si un campo no es definitivo o es una referencia final a un objeto mutable (por ejemplo, Fecha) y es public , renuncia a la capacidad de limitar lo que está almacenado en el campo o imponer invariantes en el campo. Entonces, si desea limitar un int a un cierto rango de valores, tener el campo public significa que ya no tiene control sobre lo que está almacenado en el campo. También pierde la capacidad de realizar cualquier acción cuando se modifica un campo, lo que significa que las clases con campos mutables públicos no son seguras para subprocesos .

Los campos

Public final con un objeto mutable en ellos también tienen todas las desventajas de un campo no final. Si bien no puede cambiar la referencia del objeto, el objeto aún puede modificarse, lo que puede romper el funcionamiento interno de su clase y generar resultados no deseados y desastrosos.

Al hacer que los campos sean privados, también minimiza la mutabilidad de su clase. Las clases inmutables son generalmente más fáciles de diseñar, implementar y usar que las clases mutables. Los campos privados impiden que los clientes de su clase obtengan acceso a objetos mutables y modifiquen los objetos directamente. Por lo general, tampoco le da a un cliente referencias a los objetos mutables (les da copias).

A medida que su clase minimiza la mutabilidad o se vuelve completamente inmutable, también se convierte en inherentemente seguro para subprocesos y no requiere sincronización. No se pueden corromper por múltiples hilos que acceden a ellos simultáneamente. Una enorme ganancia funcional de inmutabilidad es que es una de las formas más fáciles de lograr la seguridad de subprocesos.

    
respondido por el Deco 23.10.2012 - 10:29
10

Me pregunto por qué nadie lo ha mencionado, pero hay una posible ganancia. Como alguien señaló, permite razonar sobre el comportamiento de un programa. Las herramientas que permiten que el análisis estático le indique que una función o variable no son necesarias en absoluto (para que pueda descartarlas) o que no estén escritas desde cualquier lugar (por lo que probablemente tampoco la necesite). Sin embargo, podría considerar solo esta organización.

Pero también permite al compilador optimizar . Deseche las funciones y variables innecesarias (programa más pequeño), o analice el flujo del programa para que se pueda almacenar en caché un valor conocido.

    
respondido por el MPi 23.10.2012 - 14:56
8
  

Quiero decir, ¿tener un método privado en lugar de un método público te da alguna ventaja en cuanto a cómo funciona o funciona el programa?

Bueno, no. Si tomara un programa de trabajo y elevara todos los modificadores de acceso a public , todavía tendría un programa de trabajo *. De forma similar, si tomara un programa operativo y reemplazara todos los bucles for y while con construcciones equivalentes goto , también tendría un programa en funcionamiento . De manera similar, si tomara un programa de trabajo y reemplazara todas las operaciones de cadena con manipulaciones de arrays manuales char equivalentes, todavía tendría un programa working .

Pero 'Trabajar' no es la única medida de la bondad del programa. La legibilidad y la capacidad de mantenimiento también se incluyen, y para esos , los modificadores de acceso son útiles.

* modulo cualquier cosa de tipo Reflexión que busque modificadores de acceso específicos, etc.

    
respondido por el AakashM 23.10.2012 - 11:35
5

Al hacer públicos los métodos, define la interfaz de su clase. De esa manera se define cómo otro código puede usarlo y cómo debe ser probado. Así que usted define de esa manera cómo otro código puede comunicarse con él. Lo bueno es que puede volver a escribir sus elementos internos como métodos privados sin cambiar la interfaz.

Eso genera código reutilizable y reduce la cantidad de cohesión. El uso de una clase de interfaz real abstrae y asegura aún más esta interfaz.

Verlo tal vez como una API, no debes cambiarlo y dejarlo muy claro para usar. Maneja los internos internos complejos sin hacerlos visibles.

    
respondido por el Luc Franken 23.10.2012 - 09:29
3

No hay beneficio funcional.

El beneficio más importante es que hace que sea posible razonar sobre el comportamiento de un programa. Si cualquier parte de un sistema puede llamar a cualquier otra parte, se vuelve demasiado difícil para los humanos mortales reales entender el programa y deducir cómo se comportará. Comenzará a ahogarse en insectos y se convertirá en una gran bola de barro. Un hito importante en la mejora personal es reconocer que su cerebro es finito , y necesita mantener las cosas lo más simples posible para aprovechar al máximo.

También es beneficioso para la comunicación entre desarrolladores. Pero ese no es el principal beneficio; de lo contrario, los desarrolladores solitarios desarrollarían grandes programas sin organizarlos en absoluto.

    
respondido por el MarkJ 23.10.2012 - 12:47
3

Intenta escribir una API

Digamos que quieres escribir una biblioteca para compartir con el resto del mundo. Hay dos cosas importantes a considerar.

  • ¿Mi biblioteca entrará en conflicto con otras bibliotecas?
  • ¿Cómo puedo evitar que los usuarios dependan del código que puede cambiar más adelante?

Para la primera pregunta, las clases proporcionan un alcance para evitar nombrar colisiones. Solo intente escribir código en JavaScript por un tiempo, donde todo se encuentra en el espacio de nombres global de forma predeterminada. Sin implementar algún tipo de espacios de nombres o clases, puede ser muy rápido.

La segunda pregunta es controvertida. Como usuario, quiero poder ver la implementación interna de los métodos / parámetros de una clase. Como desarrollador, quiero limitar la accesibilidad del usuario para evitar que cambien la implementación interna de una clase. Muchas personas ven las limitaciones como draconianas, pero existen por una buena razón.

Hay un simple dicho que encarna el problema, "si existe, alguien dependerá de él".

Es la misma razón por la que Windows todavía contiene aplicaciones que se crearon en los 3.1 días. Las bibliotecas, al igual que las aplicaciones, están diseñadas para ser utilizadas a largo plazo. El problema es que también deben cambiar y evolucionar con el tiempo.

La estabilidad proviene del diseño de una API pública estable. Eso significa que la organización de la estructura de clases no debería cambiar y, si lo hace, se toman medidas para proporcionar compatibilidad hacia atrás.

La flexibilidad proviene de limitar la cantidad de código en la que los usuarios pueden confiar. Desea darles una estructura que tenga un nombre lo suficientemente bueno para que pueda entender lo que hace, pero no quiere mostrarles cómo lo hace. Por qué, porque el método para lograrlo puede cambiar en el futuro.

Si su uso supera el esfuerzo es discutible. En el mundo de los lenguajes dinámicos que no se molestan con los modificadores de acceso, no hay mucha diferencia. Si la gente quiere depender de un código que es interno a una biblioteca, entonces aprenderán de la manera más difícil por qué es una mala idea. Todavía hay una noción de privado / público / global, pero se utilizan para clasificar el alcance, no la política.

    
respondido por el Evan Plaice 23.10.2012 - 11:40
1

En Java (y supongo que en .NET también) los modificadores de acceso significan tanto como dice SecurityManagers. Por lo tanto, si tiene el control del mismo, puede acceder a miembros privados a través de la reflexión.

Pero si tu código se ejecuta en otra aplicación donde SM está configurado para no permitir que tu código haga magia de reflexión, en realidad no puedes acceder a miembros privados.

No sé si algo como esto es posible en C ++ (y supongo que no lo es).

Por lo tanto, por encima de los beneficios de la organización (que son enormes), en algunos idiomas donde se aplica, proporciona una diferencia funcional.

    
respondido por el user470365 23.10.2012 - 11:32
1

Por lo que sé, la mayoría de los compiladores de C ++ eliminan los modificadores de acceso cuando compilan el código. Además, C ++ y Java le ofrecen la posibilidad de cruzar estos modificadores (con C ++ realmente puede acceder a cualquier parte de la memoria que desee, y el mecanismo de reflexión / reflexión de Java puede permitirle llamar al código marcado como privado) aunque esto puede volverse poco intuitivo. y no-ejecutante si se abusa, por no mencionar que en ambos casos prácticamente no sirve de nada la verificación del tiempo de compilación.

Entonces, sí, puedes decir que los modificadores de acceso son solo una forma activa de imponer la "sintaxis" de la API codificada, cosas como la encapsulación, la ocultación de la implementación, etc. Aún puedes decir que tienen un rol "funcional" como Bueno, ya que el compilador le avisará cuando intente violar los modificadores de acceso (a través de los canales "oficiales") y también generará un error. Esta es una ventaja funcional sobre, por ejemplo, C, donde realmente no se puede decir al compilador "esta parte del código aquí no debe ser accesible a esa parte".

    
respondido por el Shivan Dragon 23.10.2012 - 13:18

Lea otras preguntas en las etiquetas