Patrones de Diseño
![](http://www.unicauca.edu.co/regionalizacion/sites/default/files/logo-unicauca.png)
Cada patrón describe un problema que ocurre una y otra vez en nuestro entorno, para describir después el núcleo de la solución a ese problema, de tal manera que esa solución pueda ser usada más de un millón de veces sin hacerlo ni siquiera dos veces de la misma forma
Christopher Alexander
1977
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4940934/pasted-from-clipboard.png)
Tipos de Patrones
- De creación: Iniciación y configuración de clases y objetos
- Estructurales: Composición de clases y objetos. Bajo acoplamiento entre clases.
- De comportamiento: Comunicación o interacción entre objetos. Distribución de responsabilidades.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4941187/pasted-from-clipboard.png)
Gamma, E. (1995). Design patterns: elements of reusable object-oriented software. Pearson Education India. |
Factory Method
Consiste en utilizar una clase constructora abstracta con unos cuantos métodos definidos y otro(s) abstracto(s): el dedicado a la construcción de objetos de un subtipo de un tipo determinado
Factory Method
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4941353/pasted-from-clipboard.png)
Factory Method
abstract class Creator{
// Definimos método abstracto
public abstract Product factoryMethod()
}
public class ConcreteCreator extends Creator{
public Product factoryMethod() {
return new ConcreteProduct();
}
}
public interface Product{
public void operacion();
}
public class ConcreteProduct implements Product{
public void operacion(){
System.out.println("Una operación de este producto");
}
}
public static void main(String args[]){
Creator aCreator;
aCreator = new ConcreteCreator();
Product producto = aCreator.factoryMethod();
producto.operacion();
}
Builder
Usado para permitir la creación de una variedad de objetos complejos desde un objeto fuente (Producto), el objeto fuente se compone de una variedad de partes que contribuyen individualmente a la creación de cada objeto complejo
Builder
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4941390/pasted-from-clipboard.png)
Builder
/** "Producto" */
class Pizza {
private String masa = "";
private String salsa = "";
private String relleno = "";
public void setMasa(String masa) { this.masa = masa; }
public void setSalsa(String salsa) { this.salsa = salsa; }
public void setRelleno(String relleno) { this.relleno = relleno; }
}
/** "Abstract Builder" */
abstract class PizzaBuilder {
protected Pizza pizza;
public Pizza getPizza() { return pizza; }
public abstract void buildMasa();
public abstract void buildSalsa();
public abstract void buildRelleno();
}
/** "ConcreteBuilder" */
class HawaiPizzaBuilder extends PizzaBuilder {
public HawaiPizzaBuilder(){super.pizza = new Pizza();}
public void buildMasa() { pizza.setMasa("suave"); }
public void buildSalsa() { pizza.setSalsa("dulce"); }
public void buildRelleno() { pizza.setRelleno("chorizo+alcachofas"); }
}
/** "ConcreteBuilder" */
class PicantePizzaBuilder extends PizzaBuilder {
public PicantePizzaBuilder(){super.pizza = new Pizza();}
public void buildMasa() { pizza.setMasa("cocida"); }
public void buildSalsa() { pizza.setSalsa("picante"); }
public void buildRelleno() { pizza.setRelleno("pimienta+salchichón"); }
}
/** "Director" */
class Cocina {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }
public void construirPizza() {
pizzaBuilder.buildMasa();
pizzaBuilder.buildSalsa();
pizzaBuilder.buildRelleno();
}
}
/** Un cliente pidiendo una pizza. */
class BuilderExample {
public static void main(String[] args) {
Cocina cocina = new Cocina();
PizzaBuilder hawai_pizzabuilder = new HawaiPizzaBuilder();
PizzaBuilder picante_pizzabuilder = new PicantePizzaBuilder();
cocina.setPizzaBuilder( hawai_pizzabuilder );
cocina.construirPizza();
Pizza pizza = cocina.getPizza();
}
}
/**
* 2da opción para el abstract builder quizá más transparente para su uso.
* Dentro del crear se llaman los métodos build.
* Es válido siempre y cuando no se necesite alterar
* el orden del llamado a los "build's".
*/
abstract class OtroPizzaBuilder {
protected Pizza pizza;
public Pizza getPizza() { return pizza; }
public void crearNuevaPizza() {
pizza = new Pizza();
buildMasa();
buildSalsa();
buildRelleno();
}
public abstract void buildMasa();
public abstract void buildSalsasasa();
public abstract void buildRelleno();
}
/** "Director" */
class OtraCocina {
private OtroPizzaBuilder pizzaBuilder;
public void construirPizza() {
pizzaBuilder.crearNuevaPizza();
//notar que no se necesita llamar a cada build.
}
}
Prototype
Tiene como finalidad crear nuevos objetos clonando una instancia creada previamente
Prototype
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4941431/pasted-from-clipboard.png)
Singleton
Garantiza la existencia de una única instancia para una clase y la creación de un mecanismo de acceso global a dicha instancia.
Singleton
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 instanciación múltiple
private synchronized static void createInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
public static Singleton getInstance() {
if (INSTANCE == null) createInstance();
return INSTANCE;
}
}
Composite
Sirve para construir objetos complejos a partir de otros más simples y similares entre sí, gracias a la composición recursiva y a una estructura en forma de árbol.
Composite
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4941456/pasted-from-clipboard.png)
Composite
import java.util.*;
public abstract class Componente
{
protected String nombre;
public Componente (String nombre)
{
this.nombre = nombre;
}
abstract public void agregar(Componente c);
abstract public void eliminar(Componente c);
abstract public void mostrar(int profundidad);
}
class Compuesto extends Componente
{
private ArrayList<Componente> hijo = new ArrayList<Componente>();
public Compuesto (String name)
{
super(name);
}
@Override
public void agregar(Componente componente)
{
hijo.add(componente);
}
@Override
public void eliminar(Componente componente)
{
hijo.remove(componente);
}
@Override
public void mostrar(int profundidad)
{
System.out.println(nombre + " nivel: " + profundidad);
for (int i = 0; i < hijo.size(); i++)
hijo.get(i).mostrar(profundidad + 1);
}
}
class Hoja extends Componente
{
public Hoja (String nombre)
{
super(nombre);
}
public void agregar(Componente c)
{
System.out.println("no se puede agregar la hoja");
}
public void eliminar(Componente c)
{
System.out.println("no se puede quitar la hoja");
}
public void mostrar(int depth)
{
System.out.println('-' + "" + nombre);
}
}
public class Client
{
public static void main(String[] args)
{
Compuesto raiz = new Compuesto("root");
raiz.agregar(new Hoja("hoja A"));
raiz.agregar(new Hoja("hoja B"));
Compuesto comp = new Compuesto("compuesto X");
comp.agregar(new Hoja("hoja XA"));
comp.agregar(new Hoja("hoja XB"));
raiz.agregar(comp);
raiz.agregar(new Hoja("hoja C"));
Hoja l = new Hoja("hoja D");
raiz.agregar(l);
raiz.eliminar(l);
raiz.mostrar(1);
}
}
Façade
Viene motivado por la necesidad de estructurar un entorno de programación y reducir su complejidad con la división en subsistemas, minimizando las comunicaciones y dependencias entre estos.
Façade
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4941468/pasted-from-clipboard.png)
Observable
Define una dependencia del tipo uno a muchos entre objetos, de manera que cuando uno de los objetos cambia su estado, notifica este cambio a todos los dependientes.
Observable
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4942500/pasted-from-clipboard.png)
Observable
import java.util.*;
class FuenteEvento extends Observable implements Runnable {
public void run() {
while (true) {
String respuesta = new Scanner(System.in).next();
setChanged();
notifyObservers(respuesta);
}
}
}
import java.util.Observable;
import static java.lang.System.out;
class MiApp {
public static void main(String[] args) {
out.println("Introducir Texto >");
FuenteEvento fuenteEvento = new FuenteEvento();
fuenteEvento.addObserver( (Observable obj, Object arg) -> {
out.println("\nRespuesta recibida: " + arg);
});
new Thread(fuenteEvento).start();
}
}
Strategy
Permite mantener un conjunto de algoritmos de entre los cuales el objeto cliente puede elegir aquel que le conviene e intercambiarlo dinámicamente (tiempo de ejecución) según sus necesidades
Strategy
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4942567/pasted-from-clipboard.png)
Strategy
public class Main {
public static void main(String args[])
{
//Usamos la estrategia A
Strategy estrategia_inicial = new StrategyA();
Context context = new Context(estrategia_inicial);
context.some_method();
//Decidimos usar la estrategia B
Strategy estrategia2 = new StrategyB();
context.setStrategy(estrategia2);
context.some_method();
//Finalmente,usamos de nuevo la estrategia A
context.setStrategy(estrategia_inicial);
context.some_method();
/** Salida:
* Estrategia A
* Estrategia B
* Estrategia A
**/
}
}
public class Context {
Strategy c;
public Context( Strategy c )
{
this.c = c;
}
public void setStrategy(Strategy c) {
this.c = c;
}
//Método de estrategia 'c'
public void some_method()
{
c.behaviour();
}
}
public Interface Strategy{
public void behaviour();
}
public class StrategyA implements Strategy{
@Override
public void behaviour() {
System.out.println("Estrategia A");
}
}
public class StrategyB implements Strategy{
@Override
public void behaviour() {
System.out.println("Estrategia B");
}
}
Chain of Responsibility
Evita acoplar el emisor de una petición a su receptor dando a más de un objeto la posibilidad de responder a una petición. Para ello, se encadenan los receptores y pasa la petición a través de la cadena hasta que es procesada por algún objeto.
Chain of Responsibility
Evita acoplar el emisor de una petición a su receptor dando a más de un objeto la posibilidad de responder a una petición. Para ello, se encadenan los receptores y pasa la petición a través de la cadena hasta que es procesada por algún objeto.
Chain of Responsibility
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4942575/pasted-from-clipboard.png)
By Martin.reigosa [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)], from Wikimedia Commons
Chain of Responsibility
public class Cliente {
public static void main(String argv[]) {
Unidad smith = new Coronel("Smith", null);
Unidad truman = new Coronel("Truman", "Tomar posición enemiga");
Unidad ryan = new Soldado("Ryan");
Unidad rambo = new Soldado("Rambo");
System.out.println(rambo.orden()); // rambo ->
rambo.establecerMando(truman);
System.out.println(rambo.orden()); // rambo -> truman
ryan.establecerMando(rambo);
System.out.println(ryan.orden()); // ryan -> rambo -> truman
}
}
/**
* La clase Unidad representa la clase abstracta manejadora de la cadena de responsabilidad.
* El servicio delegado en la cadena es la solicitud de una orden al mando directo
*/
public abstract class Unidad {
/* en el constructor, además de un nombre para la unidad, se inicializa la referencia
que implementa la cadena de responsabilidad (_mando): en principio no hay sucesor */
public Unidad(String nombre) {
_mando = null;
_nombre = nombre;
}
public String toString() { return _nombre; }
// cambia el mando de una unidad (modifica cadena de responsabilidad)
public void establecerMando(Unidad mando) { _mando = mando; }
/* comportamiento por defecto de la cadena: delegar en el mando directo o, si se
alcanza el final de la cadena, utilizar una resolución por defecto (sin orden) */
public String orden() {
return (_mando != null ? _mando.orden() : "(sin orden)");
}
private Unidad _mando;
private String _nombre;
}
Chain of Responsibility
/**
* La clase Coronel modifica ligeramente el comportamiento por defecto de la cadena de
* responsabilidad: si el coronel tiene una orden específica, utiliza ésta para resolver
* el servicio. Si no tiene una orden específica (_orden==null), emplea el comportamiento
* convencional de las unidades
*/
public class Coronel extends Unidad {
// inicializa la parte de unidad e inicializa el estado propio del Coronel (_orden)
public Coronel(String nombre, String orden) {
super(nombre);
_orden = orden;
}
/* refinamiento del servicio que utiliza la cadena de responsabilidad, resolviendo
localmente si tiene órdenes específicas o comportándose convencionalmente en
caso contrario */
public String orden() { return (_orden != null ? _orden : super.orden()); }
public String toString() { return ("Coronel " + super.toString()); }
private String _orden;
}
/**
* Esta clase es una extensión instanciable de la superclase Unidad que respeta el
* comportamiento por defecto de la cadena de responsabilidad
*/
public class Soldado extends Unidad {
// el constructor sólo tiene que inicializar la parte correspondiente a la superclase
public Soldado(String nombre) {
super(nombre);
}
public String toString() { return ("Soldado " + super.toString()); }
}
Template Method
Define el esqueleto de un algoritmo en un método, llamado método de plantilla, el cual difiere algunos pasos a las subclases
Template Method
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4942632/pasted-from-clipboard.png)
Template Method
/**
* An abstract class that is common to several games in
* which players play against the others, but only one is
* playing at a given time.
*/
abstract class Game {
/* Hook methods. Concrete implementation may differ in each subclass*/
protected int playersCount;
abstract void initializeGame();
abstract void makePlay(int player);
abstract boolean endOfGame();
abstract void printWinner();
/* A template method : */
public final void playOneGame(int playersCount) {
this.playersCount = playersCount;
initializeGame();
int j = 0;
while (!endOfGame()) {
makePlay(j);
j = (j + 1) % playersCount;
}
printWinner();
}
}
//Now we can extend this class in order
//to implement actual games:
class Monopoly extends Game {
/* Implementation of necessary concrete methods */
void initializeGame() {
// Initialize players
// Initialize money
}
void makePlay(int player) {
// Process one turn of player
}
boolean endOfGame() {
// Return true if game is over
// according to Monopoly rules
}
void printWinner() {
// Display who won
}
/* Specific declarations for the Monopoly game. */
// ...
}
class Chess extends Game {
/* Implementation of necessary concrete methods */
void initializeGame() {
// Initialize players
// Put the pieces on the board
}
void makePlay(int player) {
// Process a turn for the player
}
boolean endOfGame() {
// Return true if in Checkmate or
// Stalemate has been reached
}
void printWinner() {
// Display the winning player
}
/* Specific declarations for the chess game. */
// ...
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/389297/images/4940998/pasted-from-clipboard.png)
Gamma, E. (1995). Design patterns: elements of reusable object-oriented software. Pearson Education India. |
Patrones de diseño
By Gustavo Andrés Uribe Gómez
Patrones de diseño
- 543