Modelar usando patrones Problema: Se quiere desarrollar un editor de texto que posea comandos tales como insertar una línea, borrar una línea, insertar un caracter, borrar un caracter, etc. El editor debe contar con un mecanismo para hacer undo y redo cuyos requerimientos son los siguientes: 1. Mecanismo diseñado aplicable en una gran variedad de aplicaciones Debe ser independiente de la aplicación 2. Mecanismo no requiere rediseño al agregar un nuevo comando Evitar UNDO/REDO tratados como comandos: if ultimo__comando == INSERTAR UNDO ultima inserción else if ultimo__comando == BORRAR UNDO ultima acción de borrar Modelar usando patrones 3. Mecanismo hace un uso razonable del espacio Almacenar sólo información necesaria Ejemplo: BORRAR una línea almacena sólo el número línea y texto 4. Mecanismo aplicable una gran cantidad de Permitir un mecanismo flexible Programación orientada a objetos veces Modelar usando patrones Abstracción clave: Comando Operaciones de Comando: execute (redo) y undo “Los comandos son vistos como objetos bien equipados capaces que contienen la información necesaria para ejecutarse y deshacerse a si mismos” Programación orientada a objetos Modelar usando patrones Comenzado con Un nivel de Undo: (en pseudo- java) boolean modoUndo= false; Comando comandoActual=null; // .... if( pedido es un pedido normal){ crear pedido adecuado y almacenarlo en comandoActual comandoActual.execute(); modoUndo = false; } else if( pedido es Undo){ if( modoUndo ){ comandoActual.execute(); //Redo else{ comandoActual.undo(); modoUndo = true; } } Programación orientada a objetos Modelar usando patrones ¿Qué hemos logrado? ninguna operación es dependiente de la aplicación. ¿Cómo crear el pedido adecuado? if (pedido == InsertarLinea){ comandoActual = new InsertarLinea(...); ... } else if( pedido == BorrarLinea){ comandoActual = new BorrarLinea(); ... } else ... Comentarios: Una parte de la implementación debe conocer la lista exhaustiva Importante evitar que if-else de este tipo existan más de una vez Programación orientada a objetos Modelar usando patrones Qué patrón podemos usar? Factory method parametrizado (primera versión) class CreadorDeComandos{ public CreadorDeComandos(){} public Comando crear( int id ){ if( id == InsertarLinea) return new InsertarLinea(); if( id == BorrarLinea) retunr new BorrarLinea(); .... return null; } } Programación orientada a objetos Modelar usando patrones Segunda solución: (múltiples Undo y Redo) List<Comando> listaComandos = new ArrayList<Comando>(); Para al recorrido usar patrón iterador: Iterator iterador = listaComandos.iterator(); Métodos: hasPrevious(), hasNext(), next(), previous() /* Implementación de Undo if( iterador.hasPrevious(){ comandoActual = iterador.previous() comandoActual.undo() else error() } Programación orientada a objetos Modelar usando patrones /* Implementación de Redo if( !iterador.hasNext()){ comandoActual = iterador.next() comandoActual.execute(); else error(); } Programación orientada a objetos Modelar usando patrones /* Ejecución de comando normal // borrar todos los comandos alos que se le aplico Undo while( iterador.hasNext() ){ iterator.remove(); } iterador.add(comandoActual); comandoActual.execute(); Programación orientada a objetos Modelar usando patrones ¿Cómo crear un pedido sin if-else? Definir una constante por cada comando (Insertar- Linea = 0, BorrarLinea = 1, ...) Comando*templateDeComandos[NumeroMaxComandos]; templateDeComandos[InsertarLinea] = new InsertarLinea(); templateDeComandos[BorrarLinea] = new BorrarLinea(); ... Donde? Programación orientada a objetos Modelar usando patrones class CreadorDeComandos{ private Comando[] templatesDeComandos; private int numeroComandos; private int metodoHashing(int id){ ....} public CreadorDeComandos(){ // inicializar de un archivo o de otra forma templateDeComandos = new Comando[NumeroMaximoComandos]; templateDeComandos[InsertarLinea] = new InsertaLinea(); templateDeComandos[BorrarLinea] = new BorrarLinea() .... numeroComandos = ??; } public Comando crear( int id ){ return templateDeComandos[metodoHashing(id)].clone(); } } Programación orientada a objetos Modelar usando patrones ¿Cómo crear el comando actual? Si la interacción es a través del teclado interactuando con un usuario CreadorDeComandos creadorDeComandos = new CreadorDeComandos(); .... while( pedido != Salir){ if( pedido == Undo ){ .... // slide 7} elseif( pedido == Redo){ ... // slide 8 } else{ comandoActual=creadorDeComandos.crear(pedido); comandoActual.askUser(); //solicitar informacion al usuario while( iterador.hasNext() ){ iterator.remove(); } iterador.add(comandoActual); comandoActual.execute(); } } Programación orientada a objetos Modelar usando patrones Otros patrones usados: prototype y command Nota: dentro de el método execute se debe llamar un método llamado askUser, para solicitar la información del comando que se va a ejecutar. Por ejemplo, en el caso de InsertarLinea se debe obtener el número de línea y el texto a insertar. Se recomienda el método askUser sea implementado como un método protected dentro de los comandos que lo necesitan. Programación orientada a objetos