Fundamentos de Sistemas Computacionales Patrones de Diseño Maestría en Sistemas Computacionales Estado Estado Objetivo Alterar el comportamiento de un objeto cuando su estado interno cambia, modificando aparentemente su tipo. El estado del objeto deberá ser persistente. Motivación El patrón estado surge porque en algunas clases es necesario que una clase modifique su comportamiento de acuerdo cuando se modifica su estado. Un ejemplo claro se da cuando deseamos establecer utilizar una clase que nos permite establecer una conexión, la clase puede tener varios estados diferentes como pueden ser, conectado, desconectado y conectando. Nuestra clase de ejemplo debe modificar su comportamiento dependiendo del estado en el que se encuentre, para poder hacer esto posible la clase tiene diferentes subclases que se encargan de implementar el comportamiento específico de la clase, el cual depende del estado en que se encuentra. Utilización Se utiliza cuando necesitamos cambiar el comportamiento de un objeto dependiendo de su estado. También se utiliza cuando tenemos grandes cantidades de segmentos de sentencias condicionales. El patrón estado pone cada bloque de operaciones condicionales en una clase independiente. Diagrama Participantes Contexto. Define la interfaz que utilizarán los clientes y mantiene una instancia de la subclase que implementa el estado concreto en que se encuentra la clase. Estado. Define una interfaz para encapsular el comportamiento asociado con un estado particular de la clase. Subclase Concreta por Estado. Cada subclase concreta implementa el comportamiento asociado a un estado específico de la clase. 1 Alejandro Domingo Velazquez Cruz Fundamentos de Sistemas Computacionales Patrones de Diseño Maestría en Sistemas Computacionales Estado Relación con otros patrones Manejo de cache. El patrón estado genera instancias específicas de una clase, las cuáles pueden ser reutilizadas por este patrón. Método Fábrica. El método fábrica encapsula la creación de objetos, pero no tiene un control de ellos después de su creación. Singleton. Los objetos que maneja el patrón estado son por lo general Singletons. Características 1. Separa el comportamiento asociado a un estado del objeto y lo divide en varias clases. El patrón estado pone todo el comportamiento asociado con un estado particular en un objeto. Debido a que todo el código específico para un estado en subclases, los nuevos estados y las transiciones pueden ser añadidas con facilidad definiendo nuevos estados. 2. Hace explícitas las transiciones entre estados. Cuando un objeto define su estado únicamente por los valores de sus campos, las transiciones se representan como simples operaciones de asignación de valores a variables. Tener diferentes objetos para diferentes estados hace las transiciones explícitas. 3. Los objetos que representan los diversos estados pueden ser compartidos. Si los objetos que representan a los estados no tienen variables de instancia, entonces se puede compartir el objeto estado. Implementación Definimos una clase llamada Estado la cual tendrá una variable estática de su mismo tipo, en la cual guardaremos el estado actual en el que se encuentra la clase. Tenemos dentro de la clase un método llamado cambiarEstado que dependiendo de nuestra necesidad modifica su comportamiento. El cambio en el comportamiento se debe a que regresa un tipo de subclase diferente, la cual será la responsable del comportamiento del objeto. class Estado { private static Estado estado = new Estado(); public static Estado cambiarEstado(String type) { if (type.equals("A")) estado = new A(); if (type.equals("B")) estado = new B(); return estado; } public String toString() { return "Sin Estado"; } } Creamos dos clases A y B que heredan de la clase Estado y son las responsables de implementar el comportamiento específico de la clase redefiniendo sus métodos, en nuestro ejemplo únicamente redefinimos el 2 Alejandro Domingo Velazquez Cruz Fundamentos de Sistemas Computacionales Patrones de Diseño Maestría en Sistemas Computacionales Estado método público toString para que al imprimir el objeto podamos ver que clase se encuentra contenida en él. class A extends Estado { public String toString() { return "Estado A"; } } class B extends Estado { public String toString() { return "Estado B"; } } Para poder probar que nuestra clase guarda el estado en que se encuentra lo que hacemos es declarar una variable del tipo Estado, cuya identidad imprimiremos para poder ver que efectivamente es de ese tipo. Después utilizaremos el método estático cambiarEstado de la clase para ver como se modifica el comportamiento de la clase. Podemos verificar el cambio del comportamiento, así como del tipo contenido en la variable al imprimirlas. public class ProbarEstado { public static void main(String[] args) { Estado estado = new Estado(); System.out.println(estado); estado = Estado.cambiarEstado("A"); System.out.println(estado); estado = Estado.cambiarEstado("B"); System.out.println(estado); } } El resultado de la ejecución del código es: Sin Estado Estado A Estado B Al crear e iniciar la variable no tiene un estado definido porque aún no se ha utilizado el método cambiar estado. Al usar el método cambiarEstado con el argumento “A” el comportamiento cambia porque la subclase contenida es del tipo A, lo mismo pasa cuando le enviamos el argumento “B”. En caso de que quisiéramos asignar un estado inicial a la clase bastaría con modificar el constructor para que recibiera un argumento que defina el estado inicial o que asigne un estado inicial predefinido. Ahora veremos otro ejemplo, crearemos una clase llamada Conexión la cual tiene dos posibles estados Conectado y Desconectado, cuya funcionalidad es implementada por las subclases del mismo nombre. Para poder modificar el comportamiento de la clase Conexión lo que hacemos es declarar dos métodos estáticos llamados conectar y desconectar. El método conectar devuelve un objeto del tipo Conectado y el método desconectar devuelve un objeto del tipo Desconectado. Las instancias concretas de las clases Conectado y Desconectado son las que provee el funcionamiento específico de la clase, esta característica es invisible para el cliente porque se comunica a través de la clase 3 Alejandro Domingo Velazquez Cruz Fundamentos de Sistemas Computacionales Patrones de Diseño Maestría en Sistemas Computacionales Estado Conexión utilizando los métodos comunes que fueron redefinidos por las subclases. class Conexion { private static Conexion conexion; public static Conexion conectar() { conexion = new Conectado(); return conexion; } public static Conexion desconectar() { conexion = new Desconectado(); return conexion; } public void imprimirEstado() { System.out.println("Sin Estado"); } } class Conectado extends Conexion { public void imprimirEstado() { System.out.println("Conectado"); } } class Desconectado extends Conexion { public void imprimirEstado() { System.out.println("Desconectado"); } } public class ProbarEstadoConexion { public static void main(String[] args) { Conexion conexion = new Conexion(); conexion.imprimirEstado(); conexion = Conexion.conectar(); conexion.imprimirEstado(); conexion = Conexion.desconectar(); conexion.imprimirEstado(); } } El resultado de la ejecución da como resultado lo siguiente: Sin Estado Conectado Desconectado Por lo que podemos ver que el estado del objeto es persistente, pudiendo cambiar su comportamiento pero manteniendo el estado del mismo. 4 Alejandro Domingo Velazquez Cruz