• No results found

Contextualising the reflections and experiences of the mother with expected

CHAPTER 4:   DATA ANALYSES AND INTERPRETATION 34

4.4  Contextualising the reflections and experiences of the mother with expected

• Encapsulación

• Herencia • Polimorfismo

Las siguientes secciones definen cada uno de estos términos con detalle.

Figura 8.1. Esta clase persona tiene dos objetos persona.

Abstracción

Es importante darse cuenta de que el objetivo de la programación no es repro- ducir todos los aspectos posibles del mundo real de un concepto dado. Por ejem- plo, cuando se programa una clase Person, no se intenta modelar todo lo que se conoce sobre una persona. En su lugar, se trabaja dentro del contexto de la aplica- ción específica. Sólo se modelan los elementos que son necesarios para esa apli- cación. Algunas características de una persona, como la nacionalidad, pueden existir en el mundo real, pero se omiten si no son necesarias para la aplicación en cuestión. Una persona en una aplicación bancaria estará interesada en aspectos diferentes de los de, por ejemplo, una persona en un juego de acción. Este concep- to recibe el nombre de abstracción y es una técnica necesaria para el manejo de los conceptos infinitamente complejos del mundo real. Por tanto, cuando se haga preguntas sobre objetos y clases, tenga siempre en cuenta que debe hacerse estas preguntas en el contexto de una aplicación específica.

Tipos de datos abstractos

Los tipos de datos abstractos fueron el primer intento de determinar el modo en que se usan los datos en programación. Los tipos de datos abstractos se crea- ron porque en el mundo real los datos no se componen de un conjunto de varia-

193 Person +FirstName : String +GoToWork() : void +Eat() : void +GoToSleep() : void Person1 : Person FirstName : String = Alice

Person2 : Person FirstName : String = Bob

bles independientes. El mundo real está compuesto de conjuntos de datos relacio- nados. El estado de una persona para una aplicación determinada puede consistir en, por ejemplo, nombre, apellidos y edad. Cuando se quiere crear una persona en un programa, lo que se quiere crear es un conjunto de estas variables. Un tipo abstracto de datos permite presentar tres variables (dos cadenas y un número entero) como una unidad y trabajar cómodamente con esta unidad para contener el estado de una persona, como se ve en este ejemplo:

struct Person {

public String FirstName; public String LastName; public int Age;

}

Cuando se asigna un tipo de datos a una variable del código, se puede usar un tipo de datos primitivo o un tipo de datos abstracto. Los tipos de datos primitivos son tipos que C# reconoce en cuanto se instala. Tipos como i n t , l o n g , c h a r y string son tipos de datos primitivos de C#.

Los tipos de datos abstractos son tipos que C# no admite cuando se instala. Antes de poder usar un tipo de datos abstracto hay que declararlo en el código. Los tipos de datos abstractos se definen en el código en lugar de hacerlo en el compilador de C#.

Por ejemplo, imagine la estructura (o clase) P e r s o n . Si escribe código C# que usa una estructura (o clase) P e r s o n sin escribir código que le indique al compilador de C# a qué se parece una estructura (o clase) P e r s o n y cómo se comporta, se obtiene un error de compilación. Observe el siguiente código:

class MyClass {

static void Main() {

Person MyPerson;

Person.FirstName = "Malgoska"; }

}

Si se compila este código el compilador de C# genera el siguiente error. error CS0234: El tipo o el nombre del espacio de nombres

'Person' no existe en la clase o el espacio de nombres 'MyClass' (¿falta una referencia de ensamblado?)

El problema de este código es que el tipo de datos P e r s o n no es un tipo de datos primitivo y no está definido por el lenguaje C#. Como no es un tipo primi- tivo, el compilador de C# considera que se trata de un tipo de datos abstracto y revisa el código buscando la declaración de un tipo de datos P e r s o n . Sin embar- go, como el compilador de C# no puede encontrar información sobre el tipo abstrac-

to de datos P e r s o n genera un error. Tras definir un tipo abstracto de datos, puede usarse en el código C# exactamente igual que si fuera un tipo de datos primitivo. Las estructuras y las clases de C# son ejemplos de tipos abstractos de datos. Una vez que se ha definido una estructura (o clase), se pueden usar las variables de ese tipo dentro de otra estructura (o clase). La estructura LearningUnit, por ejemplo, contiene dos variables Person:

struct LearningUnit {

public Person Tutor; public Person Student; }

Encapsulación

Mediante la encapsulación, los datos se ocultan, o se encapsulan, dentro de una clase y la clase implementa un diseño que permite que otras partes del código accedan a esos datos de forma eficiente. Imagine la encapsulación como un envol- torio protector que rodea a los datos de las clases de C#.

Cómo ejemplo de encapsulación, observe la estructura P o i n t con la que trabajó en un capítulo anterior.

struct Point {

public int X; public int Y; }

Los datos miembros de esta estructura son públicos, lo que permite que cualquier parte de código que acceda a la estructura acceda también a los datos miembros. Como cualquier parte de código puede acceder a los datos miem- bros, el código puede asignar a los valores de datos miembros cualquier valor que pueda representarse en un valor int.

No obstante, puede surgir un problema al permitir que los clientes asignen los valores de los datos miembros directamente. Supongamos que se usa la estruc- tura P o i n t para representar una pantalla de ordenador con una resolución de 800 x 600. En ese caso, sólo tiene sentido permitir al código que asigne a X valores entre 0 y 800, y a Y valores entre 0 y 600. No obstante, con el acceso público a los datos m i e m b r o s , no hay nada que impida al código asignar a X el valor 32.000 y a Y el valor 38.000. El compilador de C# lo permite porque esos valores son posibles en un entero. El problema es que no tiene sentido permitir valores tan elevados.

La encapsulación resuelve este problema. Básicamente, la solución está en marcar los datos miembros como privados, para que el código no pueda acce- der a los datos miembros directamente. A continuación puede escribir métodos en una clase de punto como S e t X ( ) y S e t Y ( ) . Los métodos S e t X ( ) y S e t Y ( )

pueden asignar los valores y también pueden contener código que genere un error si se trata de llamar a S e t X ( ) o a S e t Y ( ) con parámetros con valores demasiado grandes. La figura 8.2 muestra el posible aspecto de una clase Point.

Figura 8.2. Las variables de miembros en la clase Point están encapsuladas.

NOTA: El signo menos delante de los datos miembros es una notación

UML que indica que los miembros tienen una visibilidad privada. El signo más delante de los datos miembros es una notación UML que indica que los miembros tienen una visibilidad pública.

La técnica consistente en marcar como privados los datos miembros resuel- ve el problema de que el código establezca sus valores directamente. Si los datos miembros son privados, sólo la propia clase puede verlos y cualquier otro código que intente acceder a los datos miembros genera un error del compilador. En lugar de acceder directamente a los datos miembros, la clase declara métodos públicos llamados S e t X ( ) y S e t Y ( ) . El código que quiera asignar los valores de los puntos X e Y llama a estos métodos públicos. Estos métodos pue- den aceptar el nuevo valor de las coordenadas y un parámetro, pero también pueden comprobar los nuevos valores para asegurarse de que están dentro de los límites adecuados. Si el nuevo valor está fuera de los límites, el método devuelve un error. Si el nuevo valor está dentro de los límites, el método puede establecer un nuevo valor. El siguiente pseudocódigo muestra cómo se puede implementar el método SetX():

bool SetX(int NewXValue) {

if (NewXValue is out of range) return false;

X = NewXValue; return true; }

Este código ha encapsulado el dato miembro de la coordenada X y permi- te a los invocadores asignar su valor a la vez que impide que le asignen un valor no válido.

Cómo los valores de las coordenadas X e Y en este diseño son privados, las otras partes de código no pueden examinar sus valores actuales. La accesibilidad

Point -X : int -Y : int +SetX() : bool +SetY() : bool +GetX() : int +GetY() : int 196

privada en la programación orientada a objetos evita que las partes que realizan la llamada lean el valor actual o guarden el nuevo valor. Para exponer estas variables privadas, se pueden implementar métodos como G e t X ( ) y G e t Y ( ) que devuelven el valor actual de las coordenadas.

En este diseño, la clase encapsula los valores de X e Y aunque permite que otras partes del código lean y escriban sus valores. La encapsulación proporciona otra ventaja: el método que realiza el acceso impide que se asignen valores ab- surdos a los datos miembros.