Encapsulación a través de propiedades

Encapsulación a través de propiedades

Una de las características de la OOP, la encapsulación, establece que el código de una clase debe permanecer, siempre que sea posible, protegido de modificaciones no controladas del exterior (código cliente). Nuestra clase debe actuar como una especie de caja negra, que expone un interfaz para su uso, pero que no debe permitir el acceso a la implementación de dicho interfaz.

Supongamos que en nuestra clase Empleado necesitamos crear un elemento para guardar el sueldo pagado, pero el importe del sueldo deberá estar entre un rango de valores en función de la categoría del empleado. Si la categoría es 1, el sueldo estará entre 1 y 200, mientras que si la categoría es 2, el sueldo podrá llegar hasta 300. Si abordamos este problema utilizando campos de clase, puede ocurrir lo que mostramos en el Código fuente 209.

Module General

Sub Main() Dim loEmpleado As Empleado loEmpleado = New Empleado() loEmpleado.psNombre = "Juan" loEmpleado.piCategoria = 1

© Grupo EIDOS 17. Programación orientada a objeto (OOP)

' atención, el sueldo para este empleado ' debería estar entre 1 a 200, debido a su categoría loEmpleado.pdbSueldo = 250

End Sub

End Module

Public Class Empleado Public msNombre As String Public miCategoria As Integer Public mdbSueldo As Double

End Class

Código fuente 209

¿Que está sucediendo aquí?. Hemos creado un objeto empleado al que le hemos dado categoría 1, sin embargo le estamos asignando un sueldo que no corresponde a su categoría, pero se nos permite hacerlo sin ningún problema, ya que no existe un medio de control que nos lo impida.

Afrontando el problema mediante el uso de propiedades, contamos con la ventaja de escribir código de validación en los correspondientes procedimientos Property; con ello encapsulamos el código de la clase, manteniéndolo a salvo de asignaciones incoherentes. Veamos esta solución en el Código fuente 210.

Module General

Sub Main() Dim loEmpleado As Empleado loEmpleado = New Empleado()

loEmpleado.psNombre = "Pedro" loEmpleado.Categoria = 1

loEmpleado.Sueldo = 250 Console.WriteLine("Asignación incorrecta") Console.WriteLine("Empleado {0} - Categoria {1} - Sueldo {2}", _

loEmpleado.psNombre, loEmpleado.Categoria, loEmpleado.Sueldo)

loEmpleado.Sueldo = 175 Console.WriteLine("Asignación correcta") Console.WriteLine("Empleado {0} - Categoria {1} - Sueldo {2}", _

loEmpleado.psNombre, loEmpleado.Categoria, loEmpleado.Sueldo)

Console.ReadLine() End Sub

End Module

Public Class Empleado Public psNombre As String

' variables de propiedad Private miCategoria As Integer Private mdbSueldo As Double

' procedimientos de propiedad Public Property Categoria() As Integer

Get Return miCategoria End Get

Programación con Visual Basic .NET © Grupo EIDOS

Set(ByVal Value As Integer) miCategoria = Value End Set End Property

Public Property Sueldo() As Double Get Return mdbSueldo End Get

' cuando asignamos el valor a esta propiedad, ' ejecutamos código de validación en el bloque Set Set(ByVal Value As Double)

' si la categoría del empleado es 1... If miCategoria = 1 Then

' ...pero el sueldo supera 200 If Value > 200 Then

' mostrar un mensaje y asignar un cero Console.WriteLine("La categoría no corresponde con el sueldo") mdbSueldo = 0

Else ' si todo va bien, asignar el sueldo mdbSueldo = Value

End If End If

End Set End Property

End Class

Código fuente 210

Propiedades de sólo lectura o sólo escritura

Se nos plantea ahora un nuevo caso para nuestra clase Empleado: debemos guardar el valor del código

de cuenta bancaria del empleado en el objeto, pero sin permitir que dicha información sea accesible desde el código cliente.

Igualmente y en función de los primeros dígitos de la cuenta bancaria, necesitamos mostrar el nombre

de la entidad, pero sin permitir al código cliente su modificación, ya que esta va a ser siempre una operación que debe calcular el código de la clase.

Utilizando campos de clase no es posible resolver esta situación, ya que al ser de ámbito público, permiten tanto la escritura como lectura de sus valores.

Pero si empleamos propiedades, estas nos permiten la creación de las denominadas propiedades de sólo lectura o sólo escritura, en las que utilizando las palabras clave ReadOnly y WriteOnly, conseguimos que a una determinada propiedad, sólo podamos asignarle o recuperar su valor.

Debido a esto, en una propiedad ReadOnly no podremos escribir el bloque Set, ya que no tendría sentido, puesto que no se va a utilizar. Lo mismo podemos aplicar para una propiedad WriteOnly, sólo que en esta, el bloque que no podremos codificar será Get.

Igualmente obtendremos un error del compilador, si en el código cliente intentamos asignar un valor a una propiedad ReadOnly, u obtener un valor de una propiedad WriteOnly.

© Grupo EIDOS 17. Programación orientada a objeto (OOP)

Veamos a continuación, en el Código fuente 211, un ejemplo de cómo resolver el problema comentado al comienzo de este apartado.

Module General

Sub Main() Dim loEmpleado As Empleado loEmpleado = New Empleado()

loEmpleado.psNombre = "Pedro"

' a esta propiedad sólo podemos asignarle ' valor, si intentamos obtenerlo, se producirá ' un error loEmpleado.CuentaBancaria = "2222-56-7779995555"

' en esta línea, la propiedad EntidadBancaria sólo ' nos permite obtener valor, si intentamos asignarlo ' se producirá un error Console.WriteLine("La entidad del empleado {0} es {1}", _

loEmpleado.psNombre, loEmpleado.EntidadBancaria) Console.ReadLine() End Sub

End Module

Public Class Empleado ' campo de clase Public psNombre As String

' variables de propiedad Private msCtaBancaria As String Private msEntidad As String

' variables diversas Private msCodigoEntidad As String

' esta propiedad sólo permite asignar valores, ' por lo que no dispone de bloque Get Public WriteOnly Property CuentaBancaria() As String

Set(ByVal Value As String) Select Case Left(Value, 4) Case "1111" msEntidad = "Banco Universal" Case "2222" msEntidad = "Banco General" Case "3333" msEntidad = "Caja Metropolitana" Case Else msEntidad = "entidad sin catalogar" End Select End Set End Property

' esta propiedad sólo permite obtener valores, ' por lo que no dispone de bloque Set Public ReadOnly Property EntidadBancaria() As String

Get Return msEntidad End Get End Property End Class

Código fuente 211

Programación con Visual Basic .NET © Grupo EIDOS