lunes, 7 de mayo de 2007

PATRON CREACIONAL

PATRON DE DISEÑO SINGLETON.

1) NOMBRE DEL PATRON: Singleton (Instancia única).

2) CLASIFICACIÓN DEL PATRÓN: Creacional.

3) INTENCIÓN: Consiste en garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella.

4) TAMBIÉN CONOCIDO COMO: Instancia Única.

5) MOTIVACIÓN: La forma de proceder del patrón es la siguiente: si se solicita una instancia del objeto:

a) si no existe (o sea, la primera vez que se usa) se crea la instancia.

b) si existe una instancia (es la segunda o más vez que se usa), devuelvo la existente, todas las veces que se me solicite.

c) el constructor de la clase debe permanecer "anulado" definiéndolo como "privado". De esta forma se asegura que no se puedan crear instancias de forma directa y solo se permite a través del método "getInstancia()":

6) APLICABILIDAD: Debe haber exactamente una instancia de una clase y deba ser accesible a los clientes desde un punto de acceso conocido.
Los patrones Singleton se usan normalmente cuando piensas usar un objeto global o puntero para hacer referencia a una sola instancia de una clase. Por ejemplo, una clase manager-type, donde una solo se requiere una sola instancia (esto es, el nombre del patron). Las clases que manejan el sonido de un juego, la interfaz del usuario, o hasta el propio juego son del tipo Singleton.

7) ESTRUCTURA:
8) PARTICIPANTES:

• Singleton

• Cliente

9) COLABORACIONES:

Singleton
Cuando el Singleton tiene estado, queremos realizar más de una prueba y no es un Singleton ThreadLocal, entonces las pruebas se complican porque la instancia será la misma y mantendrá el estado.
Hay varias soluciones:
• Añadir un método reset() que restaure el estado del Singleton, "solo para proposito de prueba".
Esto subvierte el carácter del Singleton.
• Obtener diferentes instancias del Singleton cargándolo con diferentes cargadores de clases. Esto
complica las pruebas porque la clase a cargar debe estar fuera del classpath. Ver el apartado "Singleton
por classloader".
• Ejecutar cada prueba en una JVM (consume muchos recursos pero puede hacerse).

Cliente
El cliente está acoplado al Singleton a través del método getInstance(), así que no podemos sustituir el Singleton por un objeto de prueba. Esto implica que las pruebas que realicemos con el cliente asumen que el Singleton será correcto, lo que en el mundo real no siempre es así.
Las únicas opciones son:
• Alterar el Singleton "solo para probarlo", pero no es prudente alterar el código sin haber hecho antes los tests, así que descartamos esta opción.
• Usar VirtualMock [http://www.virtualmock.org/], que mediante AOP y manipulación del bytecode, nos permitirá sustituir las invocaciones a métodos estáticos durante las pruebas (corazones débiles abstenerse). A agosto de 2004 solo hay distribución en código fuente, con escasa documentación.
Por lo que he visto intercepta las llamadas y reproduce valores introducidos por nuestros tests.

10) CONSECUENCIAS:

 Acceso controlado a un ejemplar único.
 Cómo y cuando los clientes pueden acceder al ejemplar.
 Espacio de nombres reducido.
 Evita la necesidad de utilizar variables globales.
 Permite refinar las operaciones y la representación.
 Se puede heredar de la clase Singleton para configurar el ejemplar para una aplicación concreta.

11) IMPLEMENTACIÓN: ¿Cómo se implementa un Singleton? En primer lugar, se debe impedir que los clientes construyan instancias de la clase que se desea hacer Singleton. Para ello, lo normal es hacer su constructor privado. Además, se debe hacer que dicha clase contenga una referencia estática a la única instancia de esa propia clase que puede existir. En el mundo de la orientación a objetos, se denomina estáticas a aquellas propiedades y métodos que son comunes de una clase, y por tanto compartidas por todas sus instancias. Por último, se debe añadir al Singleton un método público y estático que devuelva la única referencia existente de esa clase.

12) CÓDIGO DE EJEMPLO:

Cómo implementar un Singleton en Visual Basic.NET.
Listado 07 - Patrón de creación: Singleton
'-------------------------------------------
Public Class Singleton
' Variable que contiene la referencia a ESTA clase
Private Shared m_Instance As Singleton = Nothing
' constructor privado
Private Sub New()
' o hacer nada
End Sub
' método estático
' permite obtener la referencia de la clase
' siempre se devuelve la misma referencia
Public Shared ReadOnly Property Instance() As Singleton
Get
If m_Instance Is Nothing Then
m_Instance = New Singleton()
End If
Return m_Instance
End Get
End Property
End Class
'-------------------------------------------
El patrón Singleton Asegura que solo se cree una instancia de la clase y provee un punto global de acceso a esta.

13) USOS CONOCIDOS: Se utiliza en: Visual Basic.NET, C++, Java , etc.
Ejemplos:
Una implementación correcta en el lenguaje de programación Java para programas multi-hilo es la solución conocida como "inicialización en demanda" sugerida por Bill Pugh:
public class Singleton {
// El constructor privado no permite que se genere un constructor por defecto
// (público)
private Singleton() {}

public static Singleton getInstance() {
return SingletonHolder.instance;
}

private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
}

A continuación, un ejemplo correcto de inicialización diferida. Se deja para comentar un error común en Java al no tener en cuenta la sincronización de métodos.
public class Singleton {
private static Singleton INSTANCE = null;

// Private constructor suppresses
private Singleton() {}

// creador sincronizado para protegerse de posibles problemas multi-hilo
// otra prueba para evitar instantiación múltiple
private synchronized static void createInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
public static Singleton getInstance() {
if (INSTANCE == null) createInstance();
return INSTANCE;
}
}

Una solución posible en C++ (conocida como el singleton de Meyers) en la cual el singleton es un objecto local estático (notar que esta solución no es segura en programas multi-hilo):
template class Singleton
{
public:
static T& Instance()
{
static T laInstanciaSingleton; //asumir T posee un constructor por defecto
return laInstanciaSingleton;
}
};
class SoloUno : public Singleton
{
//..definir aquí el resto de la interfaz
};

14) PATRONES RELACIONADOS: Abstract Factory, Builder y Prototype.

No hay comentarios: