what programming paradigm oriented language first language-agnostic class oop private-members

language-agnostic - paradigm - what is a class in programming



PropĆ³sito de los miembros privados en una clase (10)

¿Cuáles son los propósitos de tener miembros privados / protegidos de una clase / estructura en la programación orientada a objetos? ¿Qué hay de malo en que todos los miembros sean públicos?


¿Cuáles son los propósitos de tener órganos internos en el cuerpo humano? ¿Cuál es el daño de tener todos los órganos fuera?

¡Exactamente!

La respuesta corta sería: porque los necesita, por lo que no puede vivir sin ellos y no puede exponerlos a todos para que los modifiquen y jueguen con ellos porque eso podría matarlo (porque su clase no funciona correctamente).


En algún momento no quieres revelar información privada a todo el mundo. Por ejemplo, no quiere que su edad sea pública, pero es posible que desee informar a las personas si tiene más de 25 años.


Encapsulacion Es decir, ocultando la implementación de sus datos de clase. Esto le permite cambiarlo más tarde, sin romper todo el código del cliente. Eg si tienes

class MyClass { public int foo; }

sus clientes pueden escribir código como

MyClass bar = new MyClass(); bar.foo++;

Ahora, si te das cuenta de que foo debería ser un doble en lugar de int, debes cambiarlo:

class MyClass { public double foo; }

y el código del cliente no compila :-(

Con una interfaz bien diseñada, el cambio de las partes internas (partes privadas) puede incluir incluso convertir una variable miembro en un cálculo o viceversa:

class Person { public String getName(); public String getStreetAddress(); public String getZipCode(); public String getCountryCode(); public int hashCode(); }

(usando las propiedades de la cadena por motivos de simplicidad, en un diseño del mundo real, algunas de estas probablemente merecerían tener su propio tipo).

Con este diseño, tiene la libertad de, por ejemplo, introducir una propiedad de Address internamente, que contendría la dirección, el código postal y el código de país, y volver a escribir a sus accesores para que usen los campos de este miembro privado, sin que sus clientes noten nada.

También puede decidir libremente si calcular el código hash cada vez, o almacenarlo en una variable privada para mejorar el rendimiento. Sin embargo, si ese campo de caché fuera público, cualquiera podría cambiarlo, lo que podría arruinar el comportamiento del mapa hash e introducir errores sutiles. Por lo tanto, la encapsulación es clave para garantizar la consistencia del estado interno de su objeto. Por ejemplo, en el ejemplo anterior, sus configuradores pueden validar fácilmente el código postal y el código de país, para evitar establecer valores no válidos. Incluso puede asegurarse de que el formato del código postal sea válido para el país real, es decir, garantizar un criterio de validez que abarque múltiples propiedades. Con una interfaz bien diseñada, puede imponer este enlace, por ejemplo, proporcionando solo un configurador para establecer ambas propiedades al mismo tiempo:

public void setCountryCodeAndZip(String countryCode, String zipCode);

Sin embargo, con los campos públicos simplemente no tiene estas opciones.

Un caso de uso especial para campos privados son los objetos inmutables; esto es muy común en, por ejemplo, Java, los ejemplos son String y BigDecimal . Estas clases no tienen establecedores públicos, lo que garantiza que sus objetos, una vez creados, no cambiarán su estado. Esto permite una gran cantidad de optimizaciones de rendimiento, así como hace que sean más fáciles de usar, por ejemplo, en programas multiproceso, ORM, etc.


Metafóricamente, exponer a los miembros privados como público es como tener una opción en el tablero de su automóvil que le permite ajustar la presión del aceite del motor.

El automóvil debe gestionar eso internamente (de forma privada), y el usuario debe estar protegido de que no lo ensucie directamente ( encapsulation ), por razones obvias.


Muy bien explicado en la Sección 7.4: Proteja sus partes privadas de este tutorial en línea de C ++ .

¿Por qué molestarse con esto?

Los especificadores permiten que una clase sea muy compleja, con muchas funciones miembro y miembros de datos, mientras que tienen una interfaz pública simple que otras clases pueden usar. Una clase que tiene doscientos miembros de datos y cien funciones de miembros puede ser muy complicada de escribir; pero si solo hay tres o cuatro funciones públicas para miembros, y el resto son todas privadas, puede ser fácil para alguien aprender a usar la clase. Solo necesita entender cómo usar un pequeño puñado de funciones públicas, y no necesita molestarse con los doscientos miembros de datos, porque no tiene permiso para acceder a estos datos. Solo puede acceder a los datos privados a través de la interfaz pública de la clase. Sin lugar a dudas, en un programa pequeño, el uso de estos especificadores puede parecer innecesario. Sin embargo, vale la pena comprenderlos si planea realizar cualquier programa de tamaño razonable (más de un par de cientos de líneas). En general, es una buena práctica hacer que los miembros de datos sean privados. Las funciones de miembro que deben llamarse desde fuera de la clase deben ser públicas, y las funciones de miembro que solo se llaman desde dentro de la clase (también conocidas como "funciones de ayuda") probablemente deberían ser privadas. Estos especificadores son especialmente útiles en un programa grande que involucra a más de un programador.

La explicación anterior explica cómo el uso private facilita la curva de aprendizaje. Aquí hay un ejemplo que explica el aspecto de "ruptura de código":

Aquí hay una clase ParameterIO que lee y escribe un vector de parámetros enteros

class ParameterIO { public: // Main member vector<int> *Params; string param_path; // Generate path void GeneratePath() { char szPath[MAX_PATH]; sprintf(szPath,"params_%d.dat",Params->size()); param_path = szPath; } // Write to file void WriteParams() { assert_this(!Params->empty(),"Parameter vector is empty!"); ofstream fout(param_path.c_str()); assert_this(!fout.fail(),"Unable to open file for writing ..."); copy(Params->begin(),Params->end(),ostream_iterator<int>(fout,"/n")); fout.close(); } // Read parameters void ReadParams(const size_t Param_Size) { // Get the path Params->resize(Param_Size); GeneratePath(); // Read ifstream fin(param_path.c_str()); assert_this(!fin.fail(),"Unable to open file for reading ..."); // Temporary integer for(size_t i = 0; i < Params->size() && !fin.eof() ; ++i) fin>>(*Params)[i]; fin.close(); } // Constructor ParameterIO(vector<int> * params):Params(params) { GeneratePath(); } // Destructor ~ParameterIO() { } // Assert void assert_this(const bool assertion, string msg) { if(assertion == false) { cout<<msg<<endl; exit(1); } } };

El siguiente código rompe esta clase:

const size_t len = 20; vector<int> dummy(len); for(size_t i = 0; i < len; ++i) dummy[i] = static_cast<int>(i); ParameterIO writer(&dummy); // ParameterIO breaks here! // param_path should be private because // the design of ParameterIO requires a standardized path writer.param_path = "my_cool_path.dat"; // Write parameters to custom path writer.WriteParams(); vector<int> dunce; ParameterIO reader(&dunce); // There is no such file! reader.ReadParams(len);


Ningún daño en absoluto dependiendo de la audiencia y el consumo de la clase. Déjame repetir eso una vez más para que se hunda.

Ningún daño en absoluto dependiendo de la audiencia y el consumo de la clase.

Para muchos proyectos pequeños de una o dos personas que demoran aproximadamente un mes, eliminar a la perfección todas las definiciones privadas y públicas podría aumentar sustancialmente la carga de trabajo. Sin embargo, en grandes proyectos, donde puede haber varios equipos y los equipos no están ubicados geográficamente juntos, obtener el diseño correcto de todas las interfaces públicas al inicio puede aumentar considerablemente la probabilidad de éxito del proyecto en general.

Entonces, realmente tiene que ver cómo se consumirá una clase y por quién, antes de que pueda comenzar a responder esta pregunta. Del mismo modo, ¿cuánto durará el ciclo de vida de desarrollo del software? Son meses? ¿Años? Décadas? ¿Habrá otras personas además de usted usando la clase?

Cuanto más "pública" sea la clase (es decir, cuanta más gente consuma y use la clase), más importante es establecer una interfaz pública sólida y atenerse a ella.


Para agregar a la respuesta de Peter, diga que su clase almacena un nombre, y desea cambiarlo usando una cadena de nombre único a una cadena de nombre y una cadena de apellido. Si sus miembros fueran públicos, otras clases podrían leer (o escribir) la variable de nombre directamente y se romperían cuando esa variable desapareciera.

Sin mencionar que es posible que no desee que otras clases tengan la capacidad de editar sus miembros en absoluto.


Realmente depende de tu ideología. La idea es ocultar información que no debería ser expuesta por alguna razón.

Si tiene una biblioteca que desea publicar en línea, muchas personas la descargarán y algunas podrán usarla en su código. Si mantiene su API pública al mínimo y oculta los detalles de la implementación, tendrá menos dificultades para actualizarla cuando encuentre errores o desee mejorar el código.

Además, en Java, por ejemplo, no tiene forma de restringir el acceso a una variable miembro sin cambiar su visibilidad, por lo que a menudo se encuentra prematuramente creando captadores y definidores y haciendo que la variable sea privada o protegida. En Python, por ejemplo, ese problema no existe porque puedes hacer que los captadores y definidores se comporten como variables para el acceso directo (allí se llaman propiedades).

Por último, a veces es necesario tener métodos que requieran un estado coherente para que sean útiles y podrían generar problemas si se acceden directamente.

Una regla de oro es: si expones algo, alguien lo usará. Y la mayoría de las veces lo usarán por razones equivocadas (es decir, no cómo pretendía que se usaran). En este caso, el ocultamiento de información es el equivalente a los seguros para niños en los armarios de armas.


Un breve ejemplo: es posible que deba garantizar ciertas condiciones en ese valor. En este caso, configurarlo directamente puede romper dicha condición.

Muchas personas argumentan como "es posible que no quiera que todos lo lean", pero creo que la restricción de establecer un valor es un ejemplo más útil.


Es posible que desee leer el tema de Ocultar información en wikipedia.

Esencialmente, los miembros privados permiten que una clase oculte sus detalles de implementación de consumidores externos. Esto permite que una clase controle mejor cómo se expresarán los datos y el comportamiento, y le permite al consumidor ignorar los detalles que no son relevantes para el propósito principal de la clase.

Ocultar los detalles de la implementación mejora la capacidad de mantenimiento de un programa al evitar que el código externo de la clase establezca dependencias en esos detalles. Esto permite que la implementación cambie independientemente de los consumidores externos, con un riesgo reducido de romper el comportamiento existente. Cuando los detalles de la implementación privada se hacen públicos, no se pueden cambiar sin la posibilidad de romper a los consumidores de la clase que dependen de esos detalles.

Los miembros privados también permiten que una clase proteja su implementación del abuso externo. Normalmente, el estado de una clase tiene dependencias internas que definen cuándo el estado es válido y cuándo no lo es. Podemos considerar que las reglas que gobiernan la validez de la información del estado son invariantes , lo que significa que la clase siempre espera que sean verdaderas. Al exponer detalles privados, permite que el código externo modifique este estado de una manera que puede violar las invariantes y, por lo tanto, comprometer la validez (y el comportamiento) de la clase.

Un beneficio adicional de la ocultación de información, es que reduce el área de superficie que los consumidores de la clase deben comprender para interactuar adecuadamente con la clase. La simplificación es generalmente una buena cosa . Permite a los consumidores enfocarse en comprender la interfaz pública, y no en cómo la clase logra su funcionalidad.