Nov 19 2008

Patrón Decorador - Definición, diagramas e implementación {

Tag: Decorador, Java, Patrones

El patrón decorador, (decorator pattern), añade nuevas responsabilidades a un objeto dinamicamente, ofreciendo una alternativa flexible a la herencia.

En otras palabras, es una forma de agregar funcionalidades a una clase, extendiéndola pero sin recurrir a la herencia. ¿Por qué no heredar? Bueno, tal vez no desees dar acceso a toda la clase primaria y entonces sólo se daría acceso a lo necesario.

Veamos un ejemplo simple, tenemos las siguientes clases:

  • Persona (ID, Nombre, Apellido y Fecha de Nacimiento)
  • Usuario (ID, Nombre, Apellido, Usuario, Passwd)
  • Cliente (ID, Nombre, Apellido, Teléfono, Email)
  • Cliente VIP (ID, Nombre, Apellido, Teléfono, Email, Nro de Cuenta, Límite de Crédito)

Cómo vemos todos tienen campos comunes a Persona, pero no tienen todos los campos de la clase Persona, por eso no podemos heredar, así es que podremos implementar decoradores para la clase Persona, tendremos los decoradores Usuario, Cliente y Cliente VIP. (Ver figura 1).

Pero si analizamos lo que hemos diseñado hasta el momento podremos observar que Cliente VIP podría llegar a convertirse en un decorador de Cliente, que como recordamos es un decorador de Persona, de esa manera no tendremos que reescribir la lógica detrás de los atributos Teléfono e Email. (Ver figura 2).

La pregunta es cómo decorar una clase, pues a grandes rasgos podríamos decir que se trata de tener una variable privada de la clase a decorar, escribir los métodos o atributos que se deseen publicar de la clase a decorar y luego agregar las decoraciones en nuestra nueva clase, entendiendo por decoraciones los nuevos métodos y/o atributos.

Por último veamos el código correspondiente a nuestras clases.

class Persona
{
	private int ID;
	private String Nombre;
	private String Apellido;
	private Date FechaNac;
 
	public int getID()
	{
		return ID;
	}
 
	public String getNombre()
	{
		return Nombre;
	}
 
	public String getApellido()
	{
		return Apellido;
	}
 
	public Date getFechaNac()
	{
		return FechaNac;
	}
}
 
class Usuario
{
	private Persona mPersona;
 
	private String Usuario;
	private String Passwd;
 
	public int getID()
	{
		return mPersona.getID();
	}
 
	public String getNombre()
	{
		return mPersona.getNombre();
	}
 
	public String getApellido()
	{
		return mPersona.getApellido();
	}
 
	public String getUsuario()
	{
		return Usuario;
	}
 
	public String getPasswd()
	{
		return Passwd;
	}
}
 
class Cliente
{
	private Persona mPersona;
 
	private String Telefono;
	private String Email;
 
	public int getID()
	{
		return mPersona.getID();
	}
 
	public String getNombre()
	{
		return mPersona.getNombre();
	}
 
	public String getApellido()
	{
		return mPersona.getApellido();
	}
 
	public String getTelefono()
	{
		return Telefono;
	}
 
	public String getEmail()
	{
		return Email;
	}
}
 
class Cliente_VIP
{
	private Cliente mCliente;
 
	private String NroCuenta;
	private Double LimiteCredito;
 
	public int getID()
	{
		return mCliente.getID();
	}
 
	public String getNombre()
	{
		return mCliente.getNombre();
	}
 
	public String getApellido()
	{
		return mCliente.getApellido();
	}
 
	public String getTelefono()
	{
		return mCliente.getTelefono();
	}
 
	public String getEmail()
	{
		return mCliente.getEmail();
	}
 
	public String getNroCuenta()
	{
		return NroCuenta;
	}
 
	public Double getLimiteCredito()
	{
		return LimiteCredito;
	}
}

}


Nov 10 2008

Python: Funciones que devuelven más de un valor {

Tag: Python

Muchas veces nos encontramos con situaciones en las que nos vendría muy bien poder devolver más de un valor en una función… generalmente podemos recurrir a arrays, colecciones, diccionarios, hastables, etc. Pero en Python podemos devolver múltiples valores en una misma función y lo mejor de todo es que esos valores de retorno pueden ser de diferente tipo.

Dejo un par de ejemplos, escribo la función y luego la ejecuto para probar.

def masUnoMasDos(x):
     return x+1, x+2
 
print ""
print "masUnoMasDos()"
 
a,b = masUnoMasDos(7)
print "x+1 = "+str(a)
print "x+2 = "+str(b)
 
print "---------"
 
def rojo():
     return 255, 0, 0
 
print ""
print "rojo()"
 
print rojo()
 
print "---------"
 
def rojoHexa():
     return "ff", "00", "00"
 
print ""
print "rojoHexa()"
 
print rojoHexa()

Obtendremos la siguiente salida:

masUnoMasDos()
x+1 = 8
x+2 = 9
---------

rojo()
(255, 0, 0)
---------

rojoHexa()
('ff', '00', '00')

Para probar este código rápidamente, en caso de no tener Python instalado pueden utilizar http://codepad.org que es una excelente herramienta online, la misma permite compilar y ejecutar código en varios lenguajes, incluyendo: C/C++, D, Haskel, PHP, Pearl, Python y Ruby, entre otros.

}


Nov 03 2008

ObsoleteAttribute - Para refactorear y mantener compatibilidad {

Tag: C#, Mini Tips, VB.Net

Algo muy común a la hora de refactorear es que se elimine algún método o alguna clase, pero si estamos trabajando en un grupo de soluciones con referencias entre ellas, eliminar un método puede causar bastantes problemas… y molestias en quienes estén trabajando con nuestro código.

.Net ofrece una ayuda, es un atributo que se puede aplicar a clases, métodos, propiedades, variables y constantes y que sirve de alternativa para no romper compatibilidad, el attributo Obsolete() nos permite marcar como obsoleta una porción del código sin eliminarlo y nos brinda la posibilidad de mostrar un mensaje y generar una advertencia o bien un error a la hora de compilar.

Veamos un pequeño ejemplo en VB.Net y luego en C#

Public Class MiClase
 
	<Obsolete("Este constructor fue reemplazado por New(String, Boolean)", True)> _
	Public Sub New(Arg1 as String, Arg2 as String)
		' Código del ctor obsoleto
		' Ahora genera un error al compilar
	End Sub
 
	Public Sub New(Arg1 as String, Arg2 as Boolean)
		'Código del nuevo ctor
	End Sub
 
	<Obsolete("Esta propiedad está obsolete. Por favor eliminar toda referencia a la misma antes del release 2.0")> _
	Public ReadOnly Property IsObsolete() As Boolean
		Get
			Return True
		End Get
	End Property
 
End Class

class Ejemplo
{
    [Obsolete()]
    public const string MI_CONSTANTE = "NuevosProgramadores.com";
 
    [Obsolete("No usar esta variable. Utilizar la variable FechaHoraActual en su lugar.", false)]
    DateTime Fecha = DateTime.Now;
 
}

A simple vista se puede ver que la única diferencia entre su uso en VB.net y C# es que los atributos se aplican de manera diferente.

Por último veamos las 3 firmas de este atributo:

  • Obsolete() - Genera una advertencia (warning) sin descripción alguna.
  • Obsolete(String) - Genera una advertencia con con la descripción indicada en el parámetro.
  • Obsolete(String, Boolean) - Utiliza el parámetro String como descripción y el Boolean indica si genera una advertencia (false) o un error (true).

}


Oct 30 2008

Patrón Observador - Ejemplo en C# {

Tag: C#, Observador

El patrón observador define una relación de uno a muchos, en la que un objeto único, al que llamaremos observable deberá notificar cada vez que cambie de estado a muchos objetos, que llamaremos observadores.

El funcionamiento de este patrón de diseño puede compararse con el de una suscripción a una revista, ya que los observadores se suscriben y cada vez que la revista, (observable), se actualiza, la misma se envía a los observadores suscriptos.

La definición del patrón observador es la siguiente: define una dependencia entre objetos de uno a muchos, de manera tal que cuando un objeto cambia su estado, todos sus dependientes son notificados y actualizados automaticamente.

Para demostrar el uso de este patrón, se ha creado un ejemplo en el que tenemos un form principal que tiene 2 botones, uno para abrir múltiples instancias de observadores, que en nuestro caso serán forms que mostrarán un listado desde una fuente de datos, un archivo XML más concretamente; y otro botón para abrir nuestro simulador de edición, que no es más que un form que nos permitirá editar la fuente de datos y nos permitirá observar que cada vez que alteramos los datos nuestros observadores serán notificados y actualizados automáticamente.

Es importante destacar que para una correcta implementación del patrón se utilizan interfaces que definen el rol de una clase como Observable u Observador, con lo cual nos olvidamos, por ejemplo de cómo se comporta cada clase cuando es notificada de un cambio de estado.

Veamos el diagrama de clases y a continuación el enlace para descargar nuestra mini-aplicación que implementa el patrón observador en C#.

Ejemplo de Patrón Observador en C# (155.92 KB)

}


Sep 25 2008

Convertir un entero base 10 a binario en Java (Recursivo) {

Tag: Algoritmos, Java

En este ejemplo tenemos una aplicación simple que pide un número y lo convierte a binario utilizando un algoritmo recursivo con una variable externa.

Lo primero que tenemos que saber es cómo convertir un número de base 10 a binario, (base 2). Para ello, se divide el número deseado entre 2 y cada resultado de la división tantas veces como sea necesario hasta obtener el número indivisible, el 1. Luego se toman el último resultado, 1 y todos los restos de las divisiones, viendo la imagen va a quedar mucho más claro el concepto.
Divisiones necesarias para convertir un número a binario

A continuación veremos el código en Java necesario para pedir el número en base 10 y devolverlo en binario, por supuesto que se pueden agregar validaciones, de hecho hay que agregar validaciones para asegurarnos que el usuario ingrese un número, pero ese no es el objetivo de este post.

import java.io.BufferedReader;
import java.io.InputStreamReader;
 
class binario
{
	public static void main(String[] args)
	{
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader rdr = new BufferedReader(isr);
		System.out.print("Ingrese un número entero: ");
		String buffer = "0";
		try
		{
			buffer = rdr.readLine();
		}
		catch(java.io.IOException e) // Es obligatorio manejar la IOException, si se omite no compila
		{
			System.out.println(e);
		}
 
		int dec = Integer.parseInt(buffer);
		System.out.print("El valor binario correspondiente es: ");
 
		if(dec == 0)
			System.out.println(dec); // Cero en cualquier base es cero
		else
			System.out.println(obtenerBinario(dec)); // llamamos a la func. recursiva
	}
 
 
	static String aux = ""; // variable auxiliar utilizada para almacenar el resto de cada división
 
	static String obtenerBinario(int decimal)
	{
		if(decimal == 1) // Límite de la recursividad
			return Integer.toString(decimal) + aux; // Devolvemos 1 y los restos anteriores
		else
		{
			aux = aux + Integer.toString(decimal % 2); //guardamos el resto en la variable auxiliar
			return obtenerBinario(decimal / 2); // hacemos el llamado recursivo con el resultado de la división
		}
	}
}

Además del algoritmo para convertir los números, vale la pena ver la forma en que se lee la entrada estándar, utilizando un BufferedReader, pero eso lo veremos con mayor profundidad en otro post.

}


Sep 18 2008

Patrón Estrategia: Definición y ejemplo en Java {

El patrón Estrategia (Strategy) define una familia de algoritmos, los encapsula y hace intercambiables. Permitiendo a cada algoritmo variar independientemente de los clientes que lo utilizan.

Se utiliza para encapsular aquellas partes del código que varían, haciendo que éstas variaciones no afecten al resto del código, evitando así consecuencias inesperadas y brindando a nuestro código una mayor flexibilidad.

Para ilustrarnos con un ejemplo, supongamos que tenemos un grupo de terminales las cuales tienen su propio método de entrada y salida de datos, por ej. teclado, monitor, mouse, etc.
Supongamos que en éste momento sólo tenemos 3 métodos de entrada y 2 de salida, pero sabemos que en el futuro se van a agregar más, por ello recurriremos al Patrón Estrategia para encapsular los métodos de entrada y salida, permitiéndonos en el futuro implementar las nuevas terminales con gran facilidad y sin afectar a las ya existentes.

Para encapsular los métodos de entrada recurriremos al uso de interfaces, crearemos una interface Entrada y una Salida, las cuales serán implementadas por cada método de entrada/salida de datos. A su vez, necesitamos tener varias terminales y poder agregar los nuevos tipos, para ello utilizaremos herencia, todas nuestras terminales heredarán de la superclase Terminal.

La clase Terminal tendrá una variable de instancia del tipo Entrada (interface) y una del tipo Salida (interface).
Además crearemos una clase por cáda método de entrada y salida las cuales implementarán la interface correspondiente. También podremos definir una clase, por ejemplo Monitor_TouchScreen que implemente ambas interfaces, por lo que podremos utilizarlo como método de entrada y salida.

En los diagramas vemos las interfaces Entrada y Salida con las clases que la implementan, y la superclase Terminal con sus subclases.

Ahora podemos ir un paso más allá y crear una Terminal Mutable, (qué nombre, no?), por ese nombre me refiero a una Terminal que pueda cambiar sus método de entrada y/o salida en tiempo de ejecución, lo cual suena mucho más complejo de lo que realmente es, ya que la única diferencia con las terminales que hemos creado hasta el momento es que en esta tendremos que definirnos un setter para el método de entrada y uno para el método de salida, mientras que el resto no varía.

Luego de descargar esta implementación en Java hay que ir al directorio bin/ y ejecutar java TestTerminales

Ejemplo de Patrón Estrategia en Java (7.72 KB)

}


Sep 16 2008

Corte de Control - Algoritmo y Ejemplo en C# {

Tag: Algoritmos, C#

Un Corte de Control es un algoritmo muy usado a la hora de listar datos. Actualmente es más factible obtener los datos con una consulta SQL, pero el Corte de Control aún es una técnica válida.

Un Corte de Control se compone de 3 partes básicas: principio, cuerpo y fin, en pseudo código sería así:

while(i < cantidadElementos)
{
     principio; // inicializar variables y condiciones, obtener datos, etc.
 
     cuerpo; // recorrer los datos respetando la condición.
 
     fin; // mostrar los datos.
}

En nuestro ejemplo tendremos datos de alumnos y cursos, la estructura es como si fuese una base de datos, entonces nuestras tablas tendrían la siguiente estructura:

Alumnos Cursos
ID int ID int
IDCurso int Descripción string
Nombre string

Y nosotros necesitamos hacer un Corte de Control por ID de Cursos (criterio del corte) para listar los alumnos agrupados por curso, entonces el algoritmo se vería de la siguiente manera:

static void corteDeControl()
        {
            // -- principio del corte
            int i= 0; // variable utilizada para iterar en la lista de cursos
            int IDCursoAnterior = 0; // variable con la condición del corte
            Dictionary<int, List<alumno>> resultado = new Dictionary<int, List<alumno>>(); // resultado del corte
            Console.WriteLine("\n\nListado de alumnos por curso\n"); // imprimir encabezado
 
            // -- cuerpo del corte
            while (i < DS.Cursos.Count)
            {
                IDCursoAnterior = DS.Cursos[i].ID; // condición del corte
 
                while (i < DS.Cursos.Count && DS.Cursos[i].ID == IDCursoAnterior) // mientras se cumpla la condición del corte
                {
                    foreach (alumno a in DS.Alumnos) // buscar los alumnos que pertenezcan a ese curso
                    {
                        if (a.IDCurso == IDCursoAnterior)
                        {
                            if (resultado.ContainsKey(IDCursoAnterior))
                            {
                                resultado[IDCursoAnterior].Add(a);
                            }
                            else
                            {
                                List<alumno> lista = new List<alumno>();
                                lista.Add(a);
                                resultado.Add(IDCursoAnterior, lista);
                            }
                        }
                    }
                i++; // siguiente iteración
                }
            }
 
            //fin del corte
            imprimir(resultado); // mostrar el listado
        }

Resumiendo, en pseudo código, el cuerpo del corte de control se vería más o menos así:

while(i < cantidadElementos)
{
     IDAnterior = items[i]; // condición del corte
     while(i < cantidadElementos && IDActual = IDAnterior)
     {
          // proceso datos
     }
     i++;
}

Puedes descargar una solución de Visual Studio 2005 con el ejemplo (25.93 KB).

}


Ago 29 2008

Como filtrar las filas de un DataTable usando un RowFilter (VB.Net) {

Tag: VB.Net

Más de una vez me he encontrado con un formulario en el cual muestro datos con un DataGridView, pero los datos a mostrar son demasiados, entonces es bueno agregar algún filtro para minimizar la cantidad de registros mostrados.

Para hacer esto hay 2 opciones, la más lenta sería recargar los datos desde la base aplicando filtros y la más rápida, ya que funciona en memoria es filtrar los datos que ya estamos mostrando en pantalla. Para realizar esto, en este ejemplo utilizaremos un DataTable con datos de alumnos el cual filtraremos dinámicamente.

Para empezar con este ejemplo necesitaremos un Form que tenga un CheckBox para indicar si se debe aplicar el filtro o no, un ComboBox para seleccionar el campo a filtrar, un TextBox para ingresar el valor del filtro y un DataGrid para mostrar los datos.

Lo primero que haremos será llenar el ComboBox con el nombre de las columnas de nuestro DataTable:

Private Sub LlenarComboColumnas()
	If TodosAlumnos IsNot Nothing Then ' TodosAlumnos es el DataTable
		For Each c As DataColumn In TodosAlumnos.Columns
			Me.cmbCampo.Items.Add(c.ColumnName)
		Next
	End If
End Sub

Luego agregaremos un método que se encargará de manejar 3 eventos: CheckBox.CheckedChanged, ComboBox.SelectedIndexChanged y TextBox.TextChanged. En éste método se optará por aplicar el filtro o mostrar todos los registros nuevamente:

Private Sub AplicarFiltro(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkFiltro.CheckedChanged, cmbCampo.SelectedIndexChanged, txtValor.TextChanged
	cmbCampo.Enabled = chkFiltro.Checked ' Habilitar o Deshabilitar el ComboBox y TextBox
	txtValor.Enabled = chkFiltro.Checked
 
	If chkFiltro.Checked Then
		Filtrar()
	Else
		Me.cmbCampo.SelectedIndex = 0 ' Resetear el filtro
		Me.txtValor.Text = String.Empty
		AlumnosFiltrados = TodosAlumnos.Copy() ' Mostrar todos los datos nuevamente
		Me.DataGridView1.DataSource = AlumnosFiltrados.DefaultView
	End If
End Sub

Ahora nos resta filtrar, lo que haremos en este caso, ya que el ejemplo es simple, será chequear si el tipo de datos correspondiente a la columna seleccionada es String usaremos como condición LIKE y agregaremos un comodín (*) al final del valor, si en cambio es Integer usaremos = y chequearemos que el valor ingresado sea numérico.

Private Sub Filtrar()
	Try
		AlumnosFiltrados = TodosAlumnos.Copy()
 
		If chkFiltro.Checked AndAlso Me.cmbCampo.SelectedIndex >= 0 AndAlso Not String.IsNullOrEmpty(Me.txtValor.Text) Then
			Dim columna As String = Me.cmbCampo.SelectedItem.ToString()
			Dim condicion As String = "="
			Dim valor As String = txtValor.Text
			' Si no se obtienen todos los datos no se aplica el filtro
			If AlumnosFiltrados.Columns(columna).DataType Is GetType(String) Then
				condicion = "LIKE"
				valor = String.Format("'{0}*'", valor) ' Comodín al final para obtener los valores que empiezan con 'valor'
			ElseIf AlumnosFiltrados.Columns(columna).DataType Is GetType(Integer) Then
				If Not IsNumeric(valor) Then ' Chequear que sea numérico
					Throw New ArgumentException("El valor ingresado no es correcto. Debe ingresar un valor numérico.")
				End If
			End If
 
			Me.AlumnosFiltrados.DefaultView.RowFilter = String.Format("{0} {1} {2}", columna, condicion, valor)
		End If
 
		Me.DataGridView1.DataSource = Me.AlumnosFiltrados.DefaultView ' Mostramos los datos filtrados
	Catch ex As Exception
		MostrarExcepcion(ex)
	End Try
End Sub

Para probar este ejemplo puedes descargar una solución de Visual Studio 2008 (37.03 KB).

}


Ago 26 2008

Factorial en C++ - Función recursiva vs. función iterativa {

Tag: Algoritmos, C/C++

Siguiendo con el tema Recursividad, ahora vamos a ver un ejemplo en C++ que es otro de los clásicos a la hora de aprender algoritmos recursivos, el cálculo del factorial de un número.

El factorial de un número n, se define como el producto de todos los números naturales comprendidos entre 1 y n, o sea que el factorial de 3 es 1 x 2 x 3 = 6. Por definición además, el factorial de 0 es 1.
Veamos lo anterior con ejemplos y a continuación la función iterativa para realizar el cálculo del factorial en C++.

  • 3! = 3 x 2 x 1
  • n! = n x (n-1) x (n-2) … x 1

int factorial(int n) { 
	int i; 
	int fact = 1; 
	for(i = 1; i <= n; i++) { 
		fact = fact * i; 
	} 
	return fact; 
}


Ahora si analizamos un poco más podemos ver que n! = n x (n-1)! (para n > 0), de donde surge la recursividad, ahora veamos un ejemplo y luego la función recursiva.

  • 4! = 4 x 3 x 2 x 1
  • 4! = 4 x 3!
  • 3! = 3 x 2 x 1
  • 3! = 3 x 2!
  • 2! = 2 x 1

int factorial(int n) { 
	if(n == 0) { 
		return 1; 
	} 
	else 
	{ 
		return n * factorial(n-1); 
	} 
}

}


Ago 21 2008

Métodos de extensión en VB.NET (Extension Methods) {

Tag: VB.Net

Los métodos de extensión, extension methods en inglés, son una de las novedades de la última versión de .Net Framework. Como su nombre lo indica, estos métodos permiten extender la funcionalidad de una clase sin la necesidad de tener el código fuente de la misma.

En VB.NET se utiliza un módulo para escribir los métodos de extensión, y justamente esa es la causa de muchas críticas negativas respecto a la utilización de éstos métodos.

Dentro del módulo necesitaremos definir los métodos y en su firma incluir el atributo que es el que definirá a nuestro método como método de extensión.

Luego hay que tener al menos un parámetro en la firma, que es el que indicará la clase que este método va a extender, por ejemplo hagamos un método para extender la clase String:

<Extension()> _ 
Public Function ReemplazoArroba(ByVal Cadena As String) As String 
	Return Cadena.Replace("@", "(a)") 
End Function

Entonces podremos llamar a nuestro método como un método de instancia:

Me.TextBox1.Text = Me.TextBox2.Text.ReemplazoArroba()

En la firma del método está el parámetro que define la clase que se extiende, pero a la hora de llamarlo, ese parámetro no se utiliza, ahora hagamos que nuestro método de extensión acepte en un parámetro el reemplazo que utilizará para el caracter @.

<Extension()> _
Public Function ReemplazoArroba(ByVal Cadena As String, Reemplazo as String) As String 
	Return Cadena.Replace("@", Reemplazo) 
End Function

Ahora si, a la hora de llamarlo tendremos que pasar el parámetro Reemplazo:

Me.TextBox1.Text = Me.TextBox2.Text.ReemplazoArroba("[arroba]") 

De la misma manera y en el mismo módulo podremos implementar métodos de extensión para varias clases, también se podrían implementar en un módulo ya existente de nuestro proyecto, pero por prolijidad yo prefiero hacerlo en uno aparte.

El siguiente método extiende la clase System.Windows.Forms.Control.ControlCollection y le agrega un método que puede resultar realmente útil, es un método que busca recursivamente todos los controles de tipo TextBox y borra su contenido.

<Extension()> _
Public Sub EmptyAllTextBoxes(ByVal Controls As Windows.Forms.Control.ControlCollection) 
	For Each c As Control In Controls 
		If c.Controls IsNot Nothing AndAlso c.Controls.Count > 0 Then 
			EmptyAllTextBoxes(c.Controls) ' Llamado recursivo 
		ElseIf c.GetType().Equals(GetType(TextBox)) Then 
			CType(c, TextBox).Text = String.Empty 
		End If 
	Next 
End Sub

Pueden descargar una solución de VS2008 con ejemplos de métodos de extensión (55.25 KB) para probar y modificar el código.

}


Página 1 de 3123»