You are on page 1of 13
STRATEGY (Estrategia) Comportamiento de Objetos PROPOSITO Define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Permite que un algoritmo varie independientemente de los clientes que lo usan, TAMBIEN CONOCIDO COMO Policy (Politica) MOTIVACION sten muchos algoritmos para dividir en lineas un flujo de texto. Codificar dichos algoritmos en las clases que los usan no resulta una buena practica por varias razones: Los clientes que necesitan dividir el texto en lineas se vuelven mas complejos si tienen que ineluir dicho cédigo, lo que los hace mas grandes y mis dificiles de mantener, sobre todo si permiten varios algoritmos diferentes de divisién en lineas. * Los distintos algoritmos seran apropiados en distintos momentos. No tenemos porqué permitir * miltiples algoritmos si no los vamos a usar todos. Es dificil afiadir nuevos algoritmos o modificar los existentes cuando la division en lineas es parte integral de un cliente. Estos problemas pueden evitarse definiendo clases que encapsulen los diferentes algoritmos de division en lineas. Un algoritmo asi encapsulado se denomina una estrategia. ‘Composicion ko Somponedor _. componedor Recorrer() Componer() Reparar()o [componedorsimpl] |ComponedorTeX |ComponedorMatrip componedor>Componer(| — [Gompaner) Icomponer) | (Componer Supongamos que una clase Composicién debe mantener y actualizar los saltos de linea del texto mostrado en un visor. Las estrategias de divisién en lineas no estén implementadas en la clase Composicién. En vez de eso, se implementan separadamente por las subclases de la clase abstracta Componedor. Las subclases de Componedor implementan diferentes estrategias: + ComponedorSimple implementa una estrategia simple que calcula un salto de linea cada vez. + ComponedorTeX implements el algoritmo TeX para buscar los saltos de linea. Esta estrategia trata de optimizar los saltos de linea globalinente, es decir, un parrafo cada vez. + ComponedorMatriz implements una estrategia que selecciona los saltos de linea de modo que cada fila tenga up numero determinado de elementos. Es itil para dividir una serie de iconos en filas, por ejemplo. Una Composicién mantiene una referencia a un objeto Componedor. Cada vez que una Composicién vuelve a formatear su texto, reenvia esta responsabilidad a su objeto Componedor. El cliente de Composicién especifica qué Componedor deberfa usarse, y dicho Componedor sera instalado en la Composicién. APLICABILIDAD Usese el patron Strategy cuando * muchas clases relacionadas difieren s6lo en su comportamiento. Las estrategias permiten configurar una clase con un determinado comportamiento de entre muchos posibles * se necesitan distintas variantes de un algoritmo, for ejemplo, podriamos definir algoritmos que reflejasen distintas soluciones de compromiso entre tiempo y espacio. Pueden usarse estrategias cuando estas variantes se implementan como una jerarquia de clases de algoritmos [HOS7], * unalgoritmo usa datos que los clientes no deberian conocer. Usese el patron Strategy para evitar exponer estructuras de dalos complejas y dependientes del algoritmo. una clase define muchos comportamientos, y éstos se representan como miltiples sentencias condicionales en sus operaciones. En vez de tener muchos condicionales, podemos mover las ramas de éstos a su propia clase Estrategia. ESTRUCTURA Contexto >cstategia _,] estrategia InterfazContexto() InterfazAlgoritmo()} K EstrategiaConcreta [EstrategiaConcreta_| EstrategiaConcreta InterfazAlgoritmo() | | InterfazAlgoritmo() | | InterfazAlgoritmo() PARTICIPANTES « Estrategia (Componedor) © declara una interfaz comin a todos los algoritmos permitidos. El Contexto usa esta interfaz para llamar al algoritmo definido por una EstrategiaConcreta. + EstrategiaConcreta (ComponedorSimple, ComponedorTeX, ComponedorMatriz) o implementa el algoritmo usando la interfaz Estrategia. © Contexto (Composicién) © se configura con un objeto EstrategiaConereta. © mantiene una referencia a un objeto Estrategia. © puede definir una interfaz que permita a la Estrategia acceder a sus datos. COLABORACIONES * Estrategia y Contexto interactiian para implementar el algoritmo elegido. Un contexto puede pasar n la estrategia todos los datos requeridos por el algoritmo cada vez que se llama a éste. Otra alternativa es que el contexto se pase a si mismo como argumento de las operaciones de Estrategia. Eso permite a la estrategia hacer Ilamadas al contexto cuando sea necesario. * Un contexto redirige peticiones de los clientes a su estrategia. Los clientes normalmente crean un objeto EstrategiaConcreta, el cual pasan al contexto; por tanto, los clientes interactian exclusivamente con el contexto. Suele haber una familia de clases EstrategiaConcreta a elegir por el cliente. CONSECUENCIAS El patron Strategy presenta las siguientes ventajas e inconvenientes: 1. Familias de algoritmos relacionados. Las jerarquias de clases Estrategia definen una familia de algoritmos 0 comportamientos para ser reutilizados por los contextos. La herencia puede ayudar a sacar factor comin: de la funcionalidad de estos algoritmos. . Una alternativa a la herencia. La herencia oftece otra forma de permitir una variedad de algoritmos 0 comportamientos, Se puede heredar directamente de una clase Contexto para proporcionar diferentes comportamientos. Pero esto liga el comportamiento al Contexto, mezclando la implementacién del algoritmo con la del Contexto, lo que hace que éste sea mas dificil de comprender, mantener y extender. Y no se puede modificar el algoritmo dindmicamente. ‘Acabaremos teniendo muchas clases relacionadas cuya nica diferencia es el algoritmo o comportamiento que utilizan. Encapsular el algoritmo en clases Estrategia separadas nos permite variar el algoritmo independientemente de su contexto, haciéndolo més facil de cambiar, comprender y extender. . Las estrategias eliminan las sentencias condicionales. El patrén Strategy oftece una alternativa a las sentencias condicionales para seleccionar el comportamiento deseado. Cuando se juntan muchos comportamicntos en una clase es dificil no usar sentencias condicionales para seleccionar el comportamiento correcto. Encapsular el comportamiento en clases Estrategia separadas elimina estas sentencias condicionales. Por ejemplo, sin estrategias, el cédigo para dividir un texto en lineas podria parecerse a void Composicion: :Reparar () switch (estrategiapeDivision) ( giasinple: snexConConponedozsimple () Latex combina los EI patrdn Estrategia elimina esta sentencia condicional delegando la tarca de divisién en lineas en el objeto Estrategia: Un cédigo que contiene muchas sentencias condicionales suele indicar a necesidad de aplicar el patron Estrategia. Una eleccién de implementaciones. Las estrategias pueden proporcionar distintas implementaciones del mismo comportamiento. El cliente puede elegir entre estrategias con diferentes soluciones de compromiso entre tiempo y espacio. . Los clientes deben conocer las diferentes Estrategias, El patron tiene el inconveniente potencial de que un cliente debe comprender como difieren las Estrategias antes de seleccionar la adecuada. Los clientes pueden estar expuestos a cuestiones de implementacién. Por tanto, el patron Strategy deberia usarse sélo cuando la variacién de comportamiento sea relevante a los clientes. . Costes de comunicacién entre Estrategia y Contesto. La interfaz de Estrategia es compartida por todas las clases EstrategiaConereta, ya sea el algoritmo que implementa trivial 0 complejo. Por tanto, es probable que algunos objetos EstrategiaConcreta no usen toda la informacién que reciben a través de dicha interfaz; las estrategias concretas simples pueden incluso no utilizar mada de dicha informaci6n. Eso significa que habra veces en las que el contexto crea © inicializa parametros que nunca se usan. Si esto puede ser un problema, necesitaremos un acoplamiento mas fuerte entre Estrategia y Contexto. . Mayor niimero de objetos. Las estrategias aumentan el nimero de objetos de una aplicacién. A veces se puede reducir este costo implementando las estrategias como objetos sin estado que puedan ser compartidos por el contexto. El contexto mantiene cualquier estado residual, pasdndolo en cada peticién al objeto Estrategia. Las estrategias compartidas no deberian mantener el estado entre invocaciones. El patrén Flyweight (179) describe este enfoque en mis detalle. IMPLEMENTACION Examinemos las siguientes cuestiones de implementacién: 1. Definir las interfaces Estrategia y Contesto. Las interfaces Estrategia y Contexto deben permitir a una EstrategiaConereta acceder de manera enciente a cualquier dato que ésta necesite del contexto, y viceversa. Un enfoque es hacer que Contexto pase los datos como parémetros a las operaciones de Estrategia —en otras palabras, Ileva los datos a la estrategia—. Esto mantiene a Estrategia y Contexto desacoplados. Por otro lado. Contexto podria pasar datos a la Estrategia que ésta no necesita. Otra técnica consiste en que un contexto se pase a si mismo como argumento, y que la estrategia pida los datos explicitamente al contexto. Como alternativa, la estrategia puede guardar una referencia a su contexto, eliminando asi la necesidad de pasar nada. De cualquiera de las dos formas, la estrategia puede pedir exactamente lo que necesita. Pero ahora Contexto debe definir una interfaz mas claborada para sus datos, lo que acopla mds estrechamente a Estrategia y Contexto. Las necesidades del algoritmo concreto y sus requisitos de dalos determinaran cual es la mejor técnica. 2. Estrategias como pardmetros de plantillas. En C++, pueden usarse las plantillas para configurar una clase con una estrategia. Esta técnica sélo se puede aplicar si (1) se puede seleccionar la Estrategia en tiempo de compilacién, y (2) no hay que cambiarla en tiempo de ejecucidn. En este caso, la clase a configurar (por ejemplo, Contexto) se define en una clase plantilla que tiene como pardmetro una clase Estrategia: class Contexto void Operacion() { labstrategia.Hacernlgoritme(): } La clase se configura con una clase Estrategia en el momento en que se crea una instancia: Con plantillas, no hay necesidad de definir una clase abstracta que defina la interfaz de la Estrategia. Usar Estrategia como un parametro de plantilla también nos permite enlazar estdticamente una Estrategia a Su Contexto, lo que puede aumentar la eficiencia. 3. Hacer opcionales los objetos Estrategia. La clase Contexto puede simplificarse en caso de que tenga sentido no tener un objeto Estrategia. Contexto comprueba si tiene un objeto Estrategia antes de acceder a él. En caso de que exista, lo usa normalmente. Si no hay una estrategia, Contexto realiza el comportamiento predeterminado. La ventaja de este enfoque es que los clientes no tienen que tratar con los objetos Estrategia a menos que no les sirva el comportamiento predeterminado. CODIGO DE EJEMPLO A continuacién se muestra el cédigo de alto nivel del ejemplo de la seccién de la Motivacién, que esti basado en la implementacién de las clases Composicién y Componedor de Interviews [LCI+92]. La clase Composicién tiene una coleccién de instancias de Componente, que representan los elementos grificos y de texto de un documento. Una composicién distribuye los objetos componente en lineas usando una instancia de una subclase de Componedor, la cual encapsula una estrategia de divisién en lineas. Cada componente tiene un tamaiio natural asociado, una dimensién maxima y otra minima. Estas definen cuanto puede crecer el componente por encima de su tamafio natural y cuanto puede encogerse, respectivamente. La composicién pasa estos valores a un componedor, que ién para los saltos de linea. los usa para determinar la mejor pos class Composicion ( void Reparar(); int* saltosLineas// 1a posicién de los saltos de // Uinea en los componentes int contadorLineas; // el mimero de Lineas Cuando se necesita una nueva distribucién, la composicién le pide a su componedor que determine dénde situar los saltos de linea. La composicién pasa al componedor tres arrays que definen el tamafio natural y las dimensiones maximas y minimas de los componentes. También pasa el namero de componentes, el ancho de la linea y un array que rellena el componedor con la posicién de cada salto de linea. El componedor devuelve el nimero de saltos calculados. La interfaz del Componedor permite que la composicién pase a éste toda la informacién que necesita. Esto es un ejemplo de “llevar los datos a la estrategia”’: 5 Componedor componedor () 4 he Nétese que Componedor es una clase abstracta. Las subclases concretas definen estrategias concretas de divisién en lineas. La composicién Hama a su componedor en su operacién Reparar. En primer lugar, Reparar inicializa los arrays con el tamafio natural y las dimensiones maxima y minima de cada componente (omitiremos los detalles de cémo se hace esto en aras de la brevedad), A continuacién, llama al componedor para obtener los saltos de linea, Finalmente, distribuye los componentes en funcién de los saltos de linea (también omitido): void Composicion: Reparar () cord* natural? Coord* maxisnas coord* Ant contadozComponentes? los tamafos deseados de los componeates Vf determin: int contadorsaltoss donde van los saltes: adorSaltos = _componedor->componer natural, maxina, minima, contadorcomponentes, _anchoLinea, saltos saltos loca los componentes en funcién de Veamos ahora las subclases de Componedor. ComponedorSimple examina los componentes de una linea cada vez, para determinar dénde deberian ir los saltos: public: conponedor simple ComponedorTeX usa una estrategia mas global. Examina un pdrrafo cada vez, teniendo en cuenta el tamafio y la dimensién mdxima de los componentes. También trata de asignar un “color” uniforme al parrafo minimizando el espaciado entre componentes. class Componedortex : pablic Componsdor public Componedortex t) ComponedorMatriz separa los componentes en lineas a intervalos regulares. class ConponederMatele + public Componedos blict coord natur: ninima(], int contades int saltes{] Estas clases no usan toda la informacién que se le pasa a Componer. ComponedorSimple no hace uso de la dimensién maxima de los componentes, y sélo tiene en cuenta el ancho natural de éstos. ComponedorTeX usa toda la informacién que recibe, mientras que ComponedorMatriz no usa nadz Para crear una instancia de Composicién es necesario pasarle el componedor que queremos que use: Conposicion* vapida ~ new Composicion (new Conponedorsinple} + Conposicion* elegante = new Conposicion {new ConponedorTex! Conposicion* Lconos = new Composicion (new Componedortateta (100)) + La interfaz de Componedor esta cuidadosamente disefiada para permitir toda clase de algoritmos de composicién que pudieran implementar las subclases. No queremos tener que cambiar esta interfaz con cada nueva subclase, ya que eso requeriria cambiar las subclases existentes. En general, las interfaces Estrategia y Contexto determinan en qué medida consigue el patrén su propésito. USOS CONOCIDOS Tanto ET++ [WGMSS] como Interviews usan estrategias para encapsular diferentes algoritmos de divisién en lineas tal y como se ha descrito aqui. En el Sistema RTL System para optimizacién de cédigo en los compiladores [JML92], las estrategias definen diferentes esquemas de asignacién de registros (RegisterAllocator) y de politicas de planificacién de juegos de instrucciones (RISCscheduler, CISCscheduler), Esto proporciona flexibilidad a la hora de usar el optimizador para diferentes arquitecturas de maquinas. El framework de motores de cdlculo ET++SwapsManager, calcula los precios de diversos instrumentos financieros [EG92]. Sus abstracciones clave son Instrument y YieldCurve. Los diferentes instrumentos se implementan como subclases de Instrument. YieldCurve calcula los tipos de descuento, que determinan el valor actual de los flujos de caja futuros. Ambas clases delegan parte de su comportamiento en objetos Estrategia. El framework proporciona una familia de clases EstrategiaConereta para generar flujos de caja, valorar permutas financieras y calcular tipos de descuento. Se pueden crear nuevos motores de cdlculo configurando Instrument y YieldCurve con los distintos objetos EstrategiaConcreta. Este enfoque permite combinar y usar las implementaciones existentes de Estrategia asi como definir otras nuevas. Los componentes de Booch [U V90] usan estrategias como argumentos de plantillas. Las clases de colecciones de Booch permiten tres tipos de estrategias de asignacién de memoria: gestionada (asignacién mediante un pool), controlada (las asignaciones y liberaciones estan protegidas por bloqueos) y sin gestionar (el asignador de memoria predeterminado). Estas estrategias se pasan como argumentos de plantilla a una clase de coleccién cada vez que se crea una instancia de ésta. Por ejemplo, una coleccién de tamafio variable que usa la estrategia de no gestionar se crea como una UnboundectCollection. RApp es un sistema para el disefio de circuitos integrados [GA89, ‘AG90]. RApp debe dibujar cables que conectan los distintos subsistemas de un circuito. Los algoritmos que determinan por donde deben ir dichos cables se definen en RApp como subclases de una clase abstracta Router. Router es una clase Estrategia. ObjectWindows de Borland [Bor94] usa estrategias en los cuadros de didlogo para asegurar que el usuario introduzca datos validos. Por ejemplo, los nimeros podrian tener que estar dentro de un intervalo determinado, y un campo numérico sélo deberia aceptar digitos. Validar que una cadena es correcta puede necesitar una tabla de busqueda. ObjectWindows usa objetos Validator para encapsular estrategias de validacién. Los validadores son ejemplos de objetos Estrategia. Los campos de entrada de datos delegan la validacién a un objeto Validator opcional. El cliente asigna un validador a un campo que necesita ser validado (esto constituye un ejemplo de una estrategia opcional). Cuando se cierra el didlogo, los campos de entrada le piden a sus validadores que validen los datos. La biblioteca de clases proporciona validadores para los casos mas comunes, como un Range Validator (validador de intervalo) para nimeros. Se pueden definir facilmente nuevas estrategias especificas del cliente heredando de la clase Validator. PATRONES RELACIONADOS Flyweight (179): los objetos Estrategia suelen ser buenos pesos ligeros.

You might also like