2010-03-28 12 views
6

Siempre me he preguntado sobre el tema de public, protected y private propiedades. Mi memoria puede recordar fácilmente los momentos en que tenía para hackear el código de alguien, y tener las variables de clase pirateadas declaradas como private siempre era molesto.Una visión pragmática en privado vs público

Además, había (más) veces que había escrito una clase y nunca había reconocido ningún beneficio potencial de privatizar la propiedad. Debo señalar aquí que el uso de vars public es no en mi costumbre: me atengo a los principios de OOP mediante la utilización de getters y setters.

Entonces, ¿cuál es el punto en estas restricciones?

+0

Espero que no uses getters y setters para todo, sino solo cuando realmente lo necesites. En general, violan los principios de OOP al exponer detalles de implementación. –

Respuesta

7

El uso de privada y pública se llama encapsulación. Es la simple idea de que un paquete de software (clase o módulo) necesita un interior y un exterior.

El exterior (público) es su contrato con el resto del mundo. Debe tratar de mantenerlo simple, coherente, obvio, infalible y, muy importante, estable.

Si está interesado en un buen diseño de software, la regla simplemente es: hacer todos los datos privados, y hacer que los métodos solo sean públicos cuando sea necesario.

El principio para ocultar los datos es que la suma de todos los campos de una clase define los objetos estado. Para una clase bien escrita, cada objeto debe ser responsable de mantener un estado válido. Si parte del estado es público, la clase nunca puede dar tales garantías.

Un pequeño ejemplo, supongamos que tenemos:

class MyDate 
{ 
    public int y, m, d; 
    public void AdvanceDays(int n) { ... } // complicated month/year overflow 
    // other utility methods 
}; 

Usted no puede evitar que un usuario de la clase de ignorar AdvanceDays() y simplemente hacer:

date.d = date.d + 1; // next day 

Pero si haces y, m, d privado y pruebe todos sus métodos MyDate, puede garantizar que solo habrá fechas válidas en el sistema.

+0

Sí, claro. Pero, ¿qué ocurre si cometo un error horrible en 'AdvanceDays'? Los usuarios de mi clase no podrán arreglarlo si todos los datos son privados. –

+1

Obviamente está trabajando en otra dirección aquí. Sus usuarios deberían simplemente patearlo (: –

+0

Si tuviera todo público, no necesitarían hacerlo) –

2

La palabra clave private no se debe utilizar para privatizar una propiedad que desea exponer, sino para proteger el código interno de su clase. Los encontré muy útiles porque te ayudan a definir las porciones de tu código que deben estar ocultas de las que pueden ser accesibles para todos.

+0

¿Por qué querrías ocultar tu código a alguien? :) –

0

Un ejemplo que me viene a la mente es cuando necesita hacer algún tipo de ajuste o comprobación antes de establecer/obtener el valor de un miembro privado. Por lo tanto, crearía un setter/getter público con alguna lógica (verifique si algo es nulo o cualquier otro cálculo) en lugar de acceder a la variable privada directamente y siempre teniendo que manejar esa lógica en su código. Ayuda con los contratos de código y lo que se espera.

Otro ejemplo son las funciones auxiliares. Puede dividir parte de su lógica más grande en funciones más pequeñas, pero eso no significa que quiera que todos vean y usen estas funciones auxiliares, solo desea que accedan a sus funciones API principales.

En otras palabras, desea ocultar algunas de las partes internas de su código de la interfaz.

Vea algunos videos en las API, como this Google talk.

+0

¿Qué pasa si me equivoco con estos setters/getters públicos? ¿Qué pasa si un usuario de mi clase lo extiende de una manera que realmente * necesita * esas funciones auxiliares? –

4

El punto es utilizar private y protected para evitar exponer detalles internos de su clase, de modo que otras clases solo tengan acceso a las "interfaces" públicas proporcionadas por su clase. Esto puede valer la pena si se hace correctamente.

Estoy de acuerdo en que private puede ser un verdadero dolor, especialmente si está ampliando las clases de una biblioteca. Hace un tiempo tuve que extender varias clases desde el marco Piccolo.NET y fue refrescante que hubieran declarado todo lo que necesitaba como protected en lugar de private, así que pude extender todo lo que necesitaba sin tener que copiar su código y/o modificar la biblioteca . Una lección importante para llevar es que si está escribiendo código para una biblioteca u otro componente "reutilizable", debe pensar dos veces antes de declarar cualquier cosa private.

+0

Si un usuario de la clase pudiera extenderlo y, presumiblemente, escribir algunos setters/getters directos, entonces todo este material 'protected' se convierte en' public'. ¿Por qué no declarar todo 'público' desde el principio? –

+0

Porque entonces no habría encapsulación. El punto de protección es que esos elementos solo pueden ser accedidos por esta clase o por sus difuntos: estos objetos necesitan conocer los detalles internos, pero cualquier código externo que los use no. –

+0

Pero cualquier usuario podría extender mi clase y romper la encapsulación de la forma que quiera. Hay * no * encapsulación efectiva con 'protected'. –

0

Después de haber tenido el lujo extremo de poder diseñar e implementar un sistema de objetos desde cero, tomé la política de forzar todas las variables (equivalentes a) protected. Mi objetivo era alentar a los usuarios a tratar siempre las variables como parte de la implementación y no como una especificación. OTOH, también lo dejé en ganchos para permitir que el código rompa esta restricción ya que quedan razones para no seguirlo (por ejemplo, el motor de serialización de objetos no puede seguir las reglas).

Tenga en cuenta que mis clases no necesitaban reforzar la seguridad; el lenguaje tenía otros mecanismos para eso.

0

En mi opinión, la razón más importante para usar miembros privados es ocultar la implementación, por lo que puede cambiar en el futuro sin cambiar los descendientes.

0

Algunos idiomas - Smalltalk, por ejemplo - no tienen modificadores de visibilidad en absoluto.

En el caso de Smalltalk, todas las variables de instancia son siempre privadas y todos los métodos son siempre públicos. Un desarrollador indica que el método es "privado", algo que podría cambiar, o un método auxiliar que no tiene mucho sentido por sí mismo, al poner el método en el protocolo "privado".

Los usuarios de una clase pueden ver que deben pensar dos veces antes de enviar un mensaje privado a esa clase, pero aún así tienen la libertad de utilizar el método.

(Nota:. "Propiedades" en Smalltalk son simplemente métodos getter y setter)

+0

Aprecio este estilo de advertencia. En realidad, eso es lo que defiendo. –

0

personalmente rara vez hacen uso de los miembros protegidos. Suelo favorecer a composition, decorator pattern o strategy pattern. Hay muy pocos casos en los que confío en una subclase (programador) para manejar las variables protegidas correctamente. A veces tengo métodos protegidos para ofrecer explícitamente una interfaz específica para subclases, pero estos casos son realmente raros.

La mayoría de las veces tengo una clase de base absract con solo virtuales puros públicos (hablando C++ ahora), y la implementación de clases los implementan. A veces agregan algunos métodos especiales de inicialización u otras características específicas, pero el resto es privado.

0

En primer lugar 'propiedades' podría hacer referencia a cosas diferentes en diferentes idiomas. Por ejemplo, en Java significaría variables de instancia, mientras que C# tiene una distinción entre los dos.

Supongo que quiere decir variables de instancia dado que menciona getters/setters.

La razón que otros han mencionado es la encapsulación. ¿Y qué nos compra Encapsulation?

Flexibilidad

Cuando las cosas tienen que cambiar (y normalmente lo hacen), que son mucho menos propensos a romperse la acumulación de propiedades adecuadamente encapsulantes.

Por ejemplo, podemos decidir hacer un cambio como:

int getFoo() 
{ 
    return foo; 
} 

int getFoo() 
{ 
    return bar + baz; 
} 

Si no hubiéramos encapsulado 'foo', para empezar, entonces tendríamos mucho más código para cambiar. (De esta línea)

Otra razón para encapsular una propiedad, es proporcionar una forma de bala a prueba nuestro código:

void setFoo(int val) 
{ 
    if(foo < 0) 
    throw MyException(); // or silently ignore 

    foo = val; 
} 

Esto también es muy útil ya que podemos establecer un punto de interrupción en el mutador, para que podamos romper cada vez que algo intente modificar nuestros datos.

Si nuestra propiedad fuera pública, ¡entonces no podríamos hacer nada de esto!

+0

Sí, podríamos. Cada programador ha aprendido a utilizar getters/setters cuando se proporcionan. La encapsulación es buena, pero la privatización no es, en mi opinión. ¿Qué piensas? –

+0

Pueden tener un método que los envuelva, pero (si puede omitir ese método) no están encapsulados. No estoy de acuerdo con que cada programador vaya a través de getters/setters si se proporcionan (y hay una opción para acceder directamente al campo) La excusa que escuché para esto es 'razones de eficiencia'. Esto no tiene sentido, y el problema de mantenimiento superaría en gran medida cualquier ciclo de procesador que pudiera guardar. –

Cuestiones relacionadas