sábado, 12 de marzo de 2022

Curso avanzado de C#. Encapsulación

En OOP, el concepto encapsulación se utiliza para describir el concepto de empaquetar las propiedades, métodos, y cualquier otro miembro de la clase. La encapsulación también se utiliza para referirse a la "ocultación" de los detalles de implementación de la funcionalidad de la clase y también la protección de las características de la clase.

Curso avanzado de C#. Encapsulación




Para comprender mejor esto, consideramos por ejemplo un coche. Externamente vemos ciertas características externas como el color, la forma, el tamaño. Pero hay otras características como su funcionamiento interno o su cilindrada que desconocemos y además no necesitamos conocer para operar correctamente el coche. Los controles del coche (volante, pedales)  en este caso son la interfaz para interactuar con el coche.

Si vamos al concepto de clase, al crear una clase coche crearemos ciertas características (color, dimensiones, cilindrada), en forma de variables miembro. También proporcionaremos alguna funcionalidad en la clase para encender el motor, acelerar, frenar, girar, etc.  Esta clase define una versión software de un coche.

Un coche puede ser una clase que deseamos que otros desarrolladores utilicen en su código. Para garantizar que la clase coche pueda ser utilizada por otros desarrolladores con un mínimo esfuerzo, y asegurarnos de que los otros desarrolladores no se atasquen en los detalles de cómo los diversos métodos, se utiliza la encapsulación. Los métodos de nuestra clase simplemente exponen la firma del método para el métodos de clase. Como sabemos, la firma incluye el nombre del método, cualquier tipo de devolución y los parámetros. El uso de los métodos de clase se limita a llamar al método y aceptar cualquier valor que  devuelva. Los detalles de implementación de cómo funciona el método no son importantes para alguien que utiliza la clase.

Para arrancar el motor, llamamos al método arrancar con los parámetros que se nos pida, el la clase coche arrancará, quizás llame a otros métodos, pero el programador que llama a este método podría no tiene que preocuparse de cómo el método hace esta tarea; simplemente quiere que el coche arranque.

Este aspecto de "ocultación" de la encapsulación surge con el concepto de propiedades de la clase. Las clases contienen variables miembro para almacenar ciertas características.  Si   declaramos como públicas las las variables miembro de la clase, estas, estarán disponibles fuera de la clase. Esto puede resultar peligroso para nuestra aplicación y hacerla insegura. El motivo se debe a que cualquier desarrolladores puede utilizar la clase modificando  las  variables miembro directamente, con lo que no tendremos ningún control sobre los valores  asignados  a esa variable miembro. Por ejemplo, se podría asignar inadvertidamente una cadena a una variable destinada a contener un valor numérico. El compilador generará un error.

Otra consideración más seria son los intentos de piratería, como los ataques o inyección de SQL. donde los piratas informáticos aprovechan el código no seguro para incluir caracteres en una consulta SQL. La forma de evitar estos problemas es hacer que nuestras variables miembro sean privadas y exponerlas solo a través de propiedades.

Propiedades

Las propiedades son métodos públicos que utilizan para acceder a las variables miembro privadas dentro de la clase. Hacer que las variables miembro sean privadas significa que no se puede acceder directamente desde fuera de la clase, sino mediante el uso de las propiedades. Acceso público significa que se puede acceder a los métodos fuera de la clase. Además, como las propiedades son miembros de la clase, tienen acceso a los miembros privados de la clase. Las propiedades pueden ser modificadas usando modificadores de acceso también. Podemos asignar modificadores de acceso internos públicos, privados, protegidos, internos o protegidos a una propiedad. Las propiedades también se pueden declarar con la palabra clave static, lo que significa que pueden invocarse dentro de la clase sin tener que crear una instancia de un nuevo objeto.

Al igual que los métodos en una clase base, también podemos optar por hacer que una propiedad sea virtual, lo que habilitará clases derivadas para anular el comportamiento del código en la propiedad para satisfacer mejor las necesidades de las clases derivadas. También podemos usar la palabra clave abstract al declarar una propiedad, y actuará como un método abstracto, que requiere una implementación en la clase derivada.
Aunque las propiedades pueden considerarse como componentes de una clase que representa las características de un objeto, No son las características por sí mismas. Las propiedades se basan en dos métodos clave para acceder y Modificar las variables miembro. El primer método se conoce como el método get. obtener se utiliza para acceder a la
Variable miembro que representa la propiedad. El segundo método se llama conjunto. Como es de esperar, este método se utiliza para modificar (configurar) los datos de una variable miembro que representa. La sintaxis de una propiedad.

    // sintaxis de ejemplo de propiedad de una clase  
    class Estudiante
    {
        private string nombre_var;
       public string Nombre_Prop
        {
            get { return nombre_var; }
            set { nombre_var = value; }
        }

    }

Hay que tener en cuenta las características específicas de la sintaxis de la propiedad. Primero, en la clase declaramos la variable nombre_var como privada, de modo que no será accesibre desde fuera de la clase, mientras que la propiedad Nombre_Prop es publica y por tanto accesible desde fuera de la clase incluyendo un tipo de retorno (en este caso string) y utilizamos un  nombre casi idéntico al de la variable miembro,  excepto que comienza con una letra mayúscula. Este no es un requisito de sintaxis estricto,  pero es una forma recomendada de codificación. (aquí los hemos llamado diferente para diferenciarlos) El nombre debe ser lo más cercano posible al nombre de la variable miembro que se pretende modificar para facilitar la lectura del código. Algunos desarrolladores prefieren incluir también la palabra Propiedad en el nombre, pero esto tampoco es un requisito. Dentro de la propiedad se ven dos métodos get y set. El método get devuelve el valor de la variable miembro correspondiente, y una vez obtenida podemos modificar su valor en nuestro código exterior . El método set utiliza un parámetro llamado value. Este es un componente del conjunto de métodos de  la propiedad y contiene el valor pasado en la llamada al método.

Podemos crear propiedades de solo lectura y propiedades de solo escritura simplemente omitiendo el comando get o set, respectivamente, en nuestro código de propiedad. Una propiedad de solo escritura es rara; Sin embargo, las más comunes son de lectura / escritura o de solo lectura. Los dos métodos permiten controlar los valores asignados o devueltos de nuestra clase, de esta forma podemos validar los datos pasados a una propiedad antes de asignarla, y podemos transformar los valores leídos antes de pasarlos a la aplicación que los requiere si es necesario.

Encapsulación forzada mediante el uso de propiedades


Vamos a crear una clase Estudiante con numerosas variables miembro pero las declararemos como privadas. Solo se permitirá el acceso a ellas a través de las propiedades. Iniciamos Visual Studio y creamos una nueva aplicación.  Agregamos el siguiente código a nuestra aplicación para crear la Clase estudiante.

Utilizando las propiedades


       public class Estudiante
    {
        private string nombre;
        private char iniciales;
        private string apellidos;
        private int edad;
        private string curso;
        private double calificacion_global;

        public Estudiante(string nombre_e, string apellidos_e)
        {
            this.nombre = nombre_e;
            this.apellidos = apellidos_e;
        }
        public string Nombre
        {
            get
            {
                return nombre;
            }
            set
            {
                nombre = value;
            }
        }
        public string Apellidos
        {
            get
            {
                return apellidos;
            }
            set
            {
                apellidos = value;
            }
        }
        public char Iniciales
        {
            get
            {
                return iniciales;
            }
            set
            {
                iniciales = value;
            }
        }
        public int Edad
        {
            get
            {
                return edad;
            }
            set
            {
                if (value > 6)
                {
                    edad = value;
                }
                else
                {
                    Console.WriteLine("El estudiante debe tener más de 6 años");
                }
            }
        }
        public string Curso
        {
            get
            {
                return curso;
            }
            set
            {
                curso = value;
            }
        }
        public double Calificacion
        {
            get
            {
                return calificacion_global;
            }
            set
            {
                if (value <= 10.0)
                {
                    calificacion_global = value;
                }
                else
                {
                    Console.WriteLine("La calificación no debe superar el 10");
                }
            }
        }
        public void muestraDetalles()
        {
            Console.WriteLine(this.Nombre + " " + this.Iniciales + " " + this.Apellidos);
            Console.WriteLine("Su calificación es de " + this.Calificacion);
        }
    }

En esta clase, declaramos un número de miembros como datos privados. Estos no son accesibles fuera de  esta clase a menos que pasemos a través de las propiedades o por constructor; si miramos la clase, podemos observar que el constructor todavía puede acceder directamente a las variables miembro privadas. El constructor es parte de la clase, por lo que tiene acceso a los miembros privados. Hay que tener en cuenta que el el constructor utiliza la palabra clave this para garantizar que los valores se apliquen a las variables de la instancia de la clase instanciada.

Después del constructor, hemos creado una propiedad para cada variable miembro privada,  así es como el código puede acceder a las variables miembro. A diferencia de los métodos estándar, Las propiedades no tienen parámetros. Eso es así porque aceptamos un solo valor para la Propiedad y retornamos solo un valor. El parámetro para una propiedad se conoce como valor, tal y como se muestra en los parámetros de estas propiedades.

El último fragmento de código de nuestra clase es un método llamado muestraDetalles(). En este método  concatenamos los componentes del nombre e incluimos un mensaje de texto con la calificación del estudiante. Podemos cambiar la implementación de este método siempre que deseemos, aun así no cambia la firma de la clase, y las personas que llamen a este método lo verán funcionar correctamente devolviendo un valor de salida.

Se podría haber incluido más código en cada propiedad, por ejemplo para  validaciones y verificaciones de la longitud de los valores pasados o para incluir un formato en los datos pasados, por ejemplo en la propiedad Iniciales para forzar a un máximo de tres iniciales. Como ejemplo incluiremos la lógica de validación para la edad y los valores permitidos para las calificaciones. Pero esto es sólo un ejemplo, es responsabilidad nuestra validar los datos adecuadamente antes de asignarlos a una variable miembro.

public double Calificacion
        {
            get
            {
                return calificacion_global;
            }
            set
            {
                if (value <= 10.0)
                {
                    calificacion_global = value;
                }
                else
                {
                    Console.WriteLine("La calificación no debe superar el 10");
                }
            }
        }



Ahora, utilizaremos la clase en nuestro programa para ver cómo las propiedades se han convertido en la interfaz para las variables miembro. Al escribir código nuevo IntelliSense muestra los nombres de las propiedades pero no los de las variables miembro,  Esto se debe a los modificadores de acceso utilizados en las variables miembro que las hacen privadas, mientras que las propiedades son públicas.

Intellisense en las propiedades de una clase creada por nosotros mismos



Si ingresamos el código de abajo en nuestra aplicación para hacer uso de la clase de Estudiante que creamos y Accedemos a las propiedades asignándoles valores. Después de tener el código introducido y funcionando, cambiamos los valores de la edad y la calificación global a valores fuera del rango y observamos el comportamiento.

Accediendo a las propiedades

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Estudiante miEstudiante = new Estudiante("Rodrigo", "González");
            miEstudiante.Iniciales = 'R';
            miEstudiante.Edad = 15;
            miEstudiante.Calificacion = 5.5;
            miEstudiante.muestraDetalles();

        }
    }

Este código de ejemplo es para utilizar la clase Estudiante, confiamos en el constructor para establecer los nombres y apellidos, luego llamamos a las propiedades para establecer los valores de las iniciales, la edad y la calificación. Hecho esto podemos intentar a superar los valores establecidos en las validaciones para verificar que efectivamente se configuraron correctamente.

No hay comentarios:

Publicar un comentario