Está en la página 1de 9

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

C# Patrnes de Diseo Estrategia


July 20th, 2012 by JuanK
1

En el artculo anterior revisamos uno de los pilares de los patrones de Diseo Orientado a Objetos: "Inyeccin de Dependencias" en su forma ms bsica.

C# INYECCIN DE DEPENDENCIAS
Como lo vimos la inyeccin de dependencias es una herramienta comnmente utilizada en varios patrones de diseo orientado a objetos y consiste en inyectar comportamientos a componentes. En este artculo formalizaremos un poco ms su definicin para de paso definir e implementar un conocido patrn de diseo llamado estrategia.

LO S RO BO T S
Imaginemos que tenemos una clase llamada Robot, cada Robot puede realizar una serie de operaciones fundamentales:

Caminar Disparar Desde luego hay muchas ms pero esas sern suficientes para el ejemplo. Iniciemos con el anlisis, en primera instancia revisemos la caracterstica Disparar. Si tenemos un conjunto de Robots donde todos ellos pueden disparar de manera diferente podemos pensar en crear una clase base llamada Robot la cual desde luego implementa la funcionalidad Disparar como virtual o abstract de tal forma que las implementaciones concretas puedan establecer una forma particular de disparar en cada caso. Existen inicialmente 3 implementaciones de Robot RobotVigilante: Dispara como todos los Robot RobotMilitar: Dispara como todos los Robot RobotCasero: No dispara Este es nuestro diagrama de clases

juank.black-byte.com/csharp-patrones-diseno-estrategia/

1/9

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

Y estas las implementaciones en cdigo: 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 p u b l i cc l a s sR o b o t { p u b l i cR o b o t ( ) { } p u b l i cv i r t u a lv o i dD i s p a r a r ( ) { / / B a n g ! } p u b l i cv i r t u a lv o i dC a m i n a r ( ) { / / C a m i n a r }

p u b l i cc l a s sR o b o t V i g i l a n t e:R o b o t { } p u b l i cc l a s sR o b o t M i l i t a r:R o b o t { } p u b l i cc l a s sR o b o t C a s e r o:R o b o t { p u b l i co v e r r i d ev o i dD i s p a r a r ( ) { / / N o t h i n g } }

Este esquema funciona 'bien' pero hay varios problemas que debemos afrontar si pensamos las cosas detenidamente. Cada vez que un Robot no dispare debemos sobrescribir el mtodo virtual Pueden requerirse Robots que disparen de manera diferente, en cuyo caso tambin se requiere sobrescribir el mtodo virtual Qu pasa con caminar? efectivamente pueden aparecer Robots que no caminen o Robots que lo hagan con un pie o con cuatro.
juank.black-byte.com/csharp-patrones-diseno-estrategia/ 2/9

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

Teniendo este escenario nos damos cuenta que el propsito inicial por el cual se ha utilizado la herencia se ha desvirtuado, pues no es cierto que todos los Robot hagan las actividades de la misma forma, incluso pueden haber Robots que no hagan una determinada actividad. La herencia en este punto se nos ha convertido en un problema, ya vieron cual?, puede que no. El problema es: MANTENIMIIENTO , todos sabemos que crear un programa es solo la primera parte, la segunda parte es mantener ese programa en el tiempo, hacerle mejoras , evolucionarlo etc. Y desde luego en el escenario de los Robots esto tambin es una necesidad, necesitaremos crear nuevos Robots y modificar los existentes. Pero al haber utilizado herencia nos encontraremos que algunas cosas habr que cambiarlas en la clase base y otras en las clases derivadas, peor an puede haber un grupo de clases derivadas que no utilicen las funcionalidades de la clase base pero que entre ellas si comparten la misma funcionalidad, esto es : tendremos cdigo redundante. El problema realmente puede ser muy grueso. LA SOLUCIN CLSICA Lo primero que a uno se le viene a la mente para resolver el tema de los Robot que no Disparan o que no Caminan es utilizar interfaces, lo cual suele ser una muy buena idea, sobre todo teniendo en cuenta este principio de diseo.

Programe contra una interfaz no contra implementaciones concretas.

En este sentido hay que ser claro que este principio hace referencia a interfaces desde el punto de vista del diseo de software no de ningn lenguaje en particular y en este sentido entonces una interfaz puede ser en esencia un Sper Tipo: Clase Base Clase Abstracta Interfaz Podemos crear dos interfaces para identificar que habilidades tiene cada Robot. IDisparable ICaminable *Sorry por los nombres, mi creatividad en ese sentido es limitada. Esto nos permitir tener Robots que Caminen , Disparen, que no hagan nada o que solo hagan una de las dos cosas.

Y esta es la implementacin...ligeramente ms compleja 1 2 p u b l i ci n t e r f a c eI C a m i n a b l e {


3/9

juank.black-byte.com/csharp-patrones-diseno-estrategia/

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 8 5 9 6 0 6 1 6 2 6 3

v o i dC a m i n a r ( ) ;

p u b l i ci n t e r f a c eI D i s p a r a b l e { v o i dD i s p a r a r ( ) ; } p u b l i cc l a s sR o b o t { p u b l i cR o b o t ( ) { } p u b l i cv i r t u a lv o i dM a t a r A J o h n C o n n o r ( ) { / / Y o uc o u l db em i i i n e Y e a a h h }

p u b l i cc l a s sR o b o t V i g i l a n t e:R o b o t ,I C a m i n a b l e ,I D i s p a r a b l e { p u b l i cv o i dC a m i n a r ( ) { / / C a m i n a rN o r m a l } p u b l i cv o i dD i s p a r a r ( ) { / / D i s p a r a rN o r m a l }

p u b l i cc l a s sR o b o t M i l i t a r:R o b o t ,I C a m i n a b l e ,I D i s p a r a b l e { p u b l i cv o i dC a m i n a r ( ) { / / C a m i n a rN o r m a l } p u b l i cv o i dD i s p a r a r ( ) { / / D i s p a r a rN o r m a l }

p u b l i cc l a s sR o b o t C a s e r o:R o b o t ,I C a m i n a b l e { p u b l i cv o i dC a m i n a r ( ) { / / C a m i n a rN o r m a l } } p u b l i cc l a s sR o b o t D e t e c t o r D e J o h n C o n n o r:R o b o t ,I D i s p a r a b l e { p u b l i cv o i dD i s p a r a r ( ) { / / D i s p a r a rc o ns e v i c i ah a s t al o g r a ro b j e t i v o } }

El tema de la complejidad... preocupante, pero ms preocupante an es el hecho que tenemos cdigo redundante ya que aunque varios robots disparen de la misma forma, cada uno tiene su propia implementacin. As que estamos usando uno de los principios de diseo de software pero algo anda un poco mal, vamos a solucionarlo. Para los ms experimentados el indicio de solucin salta a la vista: encapsulamiento. Pero pongmoslo en el marco del diseo de software, aqu existe otro principio fundamental:

juank.black-byte.com/csharp-patrones-diseno-estrategia/

4/9

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

Identificar los aspectos que cambian, y seprelos de los que se mantienen iguales.

Eso precisamente se hace en POO haciendo uso de encapsulamiento, cosa que los cambios en este objeto no afecten el resto del cdigo de la implementacin. Encapsular, en este caso implica necesariamente crear un objeto nuevo por cada funcionalidad 'que cambia', las funcionalidades que cambian en nuestros Robot son Disparar Caminar Estas funcionalidades que cambian las llamaremos en adelante comportamientos, behaviors en ingls. Es tiempo de extraer estos comportamientos en nuevos objetos. Cada accin ( caminar, disparar), tienen una serie de comportamientos posibles aunque exhiben la misma interfaz, es decir los mismos mtodos con los mismos tipos de datos, as que podemos pensar en generalizar dicha interfaz, de tal forma que podamos crear diferentes comportamientos, por ejemplo al caminar: CaminarNormal CaminarDeMedioLado O al disparar DispararNormal DispararAmetralladora Queda la duda de Qu hacer con los que no caminan o no disparan? esta es la parte ms bella NoCaminar NoDisparar Este es el diagrama de clases de nuestros comportamientos, y abajo la implementacin de los Robots

Ahora veamos el cdigo para los comportamientos


juank.black-byte.com/csharp-patrones-diseno-estrategia/ 5/9

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 8 5 9 6 0 6 1 6 2

p u b l i ci n t e r f a c eI D i s p a r a r B e h a v i o r { v o i dD i s p a r a r ( ) ; } p u b l i ci n t e r f a c eI C a m i n a r B e h a v i o r { v o i dC a m i n a r ( ) ; } p u b l i cc l a s sC a m i n a r N o r m a l:I C a m i n a r B e h a v i o r { p u b l i cv o i dC a m i n a r ( ) { / / C a m i n a rn o r m a l } } p u b l i cc l a s sC a m i n a r D e M e d i o L a d o:I C a m i n a r B e h a v i o r { p u b l i cv o i dC a m i n a r ( ) { / / H a c e rc o m oc a n g r e j o }

p u b l i cc l a s sN o C a m i n a r:I C a m i n a r B e h a v i o r { p u b l i cv o i dC a m i n a r ( ) { / / n a d a }

p u b l i cc l a s sD i s p a r a r N o r m a l:I D i s p a r a r B e h a v i o r { p u b l i cv o i dD i s p a r a r ( ) { / / D i s p a r a rn o r m a l }

p u b l i cc l a s sD i s p a r a r A m e t r a l l a d o r a:I D i s p a r a r B e h a v i o r { p u b l i cv o i dD i s p a r a r ( ) { / / D i s p a r a rt a c a t a c a t a c a t a c a t a c a }

p u b l i cc l a s sN o D i s p a r a r:I D i s p a r a r B e h a v i o r { p u b l i cv o i dD i s p a r a r ( ) { / / n a d a }

Este es el cdigo de implementacin de los robots haciendo uso de los comportamientos creados. 1 2 3 p u b l i ca b s t r a c tc l a s sR o b o t { p r o t e c t e dI D i s p a r a r B e h a v i o r_ d i s p a r a d o r ;
6/9

juank.black-byte.com/csharp-patrones-diseno-estrategia/

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 8 5 9

p r o t e c t e dI C a m i n a r B e h a v i o r_ c a m i n a d o r ; p u b l i cR o b o t ( ) {} p u b l i cv o i dC a m i n a r ( ) { _ c a m i n a d o r . C a m i n a r ( ) ; } p u b l i cv o i dD i s p a r a r ( ) { _ d i s p a r a d o r . D i s p a r a r ( ) ; } p u b l i cv i r t u a lv o i dM a t a r A J o h n C o n n o r ( ) { / / Y o uc o u l db em i i i n e Y e a a h h }

p u b l i cc l a s sR o b o t V i g i l a n t e:R o b o t { p u b l i cR o b o t V i g i l a n t e ( ) { _ d i s p a r a d o r=n e wD i s p a r a r N o r m a l ( ) ; _ c a m i n a d o r=n e wC a m i n a r N o r m a l ( ) ; } } p u b l i cc l a s sR o b o t M i l i t a r:R o b o t { p u b l i cR o b o t M i l i t a r ( ) { _ d i s p a r a d o r=n e wD i s p a r a r A m e t r a l l a d o r a ( ) ; _ c a m i n a d o r=n e wC a m i n a r D e M e d i o L a d o ( ) ; } } p u b l i cc l a s sR o b o t C a s e r o:R o b o t { p u b l i cR o b o t C a s e r o ( ) { _ d i s p a r a d o r=n e wN o D i s p a r a r ( ) ; _ c a m i n a d o r=n e wC a m i n a r N o r m a l ( ) ; } } p u b l i cc l a s sR o b o t D e t e c t o r D e J o h n C o n n o r:R o b o t { p u b l i cR o b o t D e t e c t o r D e J o h n C o n n o r ( ) { _ d i s p a r a d o r=n e wD i s p a r a r A m e t r a l l a d o r a ( ) ; _ c a m i n a d o r=n e wN o C a m i n a r ( ) ; } }

Es una solucin impecable, pero an se puede hacer ms! lo bueno de tener separados los comportamientos es que nada impide que podamos cambiar dichos comportamientos en tiempo de ejecucin... hell yeeaahh! Supongamos que queremos actualizar el Robot Detector De John Connor para que ahora pueda caminar, como hacerlo? gracias a que hemos programado contra interfaces y hemos encapsulado los comportamientos que cambian, es algo muy sencillo de hacer. Modificando la clase base, exponiendo de manera pblica los comportamientos: 1 2 3 4 5 6 p u b l i ca b s t r a c tc l a s sR o b o t { I D i s p a r a r B e h a v i o r_ d i s p a r a d o r ; p u b l i cI D i s p a r a r B e h a v i o rD i s p a r a d o r { g e t{r e t u r n_ d i s p a r a d o r ;}
7/9

juank.black-byte.com/csharp-patrones-diseno-estrategia/

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4

s e t{_ d i s p a r a d o r=v a l u e ;}

I C a m i n a r B e h a v i o r_ c a m i n a d o r ; p u b l i cI C a m i n a r B e h a v i o rC a m i n a d o r { g e t{r e t u r n_ c a m i n a d o r ;} s e t{_ c a m i n a d o r=v a l u e ;} } p u b l i cR o b o t ( ) {} p u b l i cv o i dC a m i n a r ( ) { _ c a m i n a d o r . C a m i n a r ( ) ; } p u b l i cv o i dD i s p a r a r ( ) { _ d i s p a r a d o r . D i s p a r a r ( ) ; } p u b l i cv i r t u a lv o i dM a t a r A J o h n C o n n o r ( ) { / / Y o uc o u l db em i i i n e Y e a a h h }

As expuestos podemos crear un objeto de cualquier tipo y modificar eso en tiempo de ejecucin!. 1 2 3 4 5 6 7 8 9 1 0 1 1 p u b l i cs t a t i cc l a s sP r o g r a m a { p u b l i cs t a t i cv o i dM a i n ( ) { v a rc o n n o r K i l l e r=n e wR o b o t D e t e c t o r D e J o h n C o n n o r ( ) ; c o n n o r K i l l e r . M a t a r A J o h n C o n n o r ( ) ; c o n n o r K i l l e r . C a m i n a d o r=n e wC a m i n a r D e M e d i o L a d o ( ) ; } C o n s o l e . W r i t e L i n e ( " Y E A H " ) ;

Digamos que ahora se nos ocurre ponernos un poco mas agresivos: 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 p u b l i cs t a t i cc l a s sP r o g r a m a { p u b l i cc l a s sC a m i n a d o r A P r o p u l s i o n:I C a m i n a r B e h a v i o r { p u b l i cv o i dC a m i n a r ( ) { / / A c t i v a rp r o p u l s o r e syd e m a s } } p u b l i cs t a t i cv o i dM a i n ( ) { v a rc o n n o r K i l l e r=n e wR o b o t D e t e c t o r D e J o h n C o n n o r ( ) ; c o n n o r K i l l e r . M a t a r A J o h n C o n n o r ( ) ; c o n n o r K i l l e r . C a m i n a d o r=n e wC a m i n a r D e M e d i o L a d o ( ) ; / / N oe sm u ye f e c t i v o ,p r o v e m o sa l g om e j o r c o n n o r K i l l e r . C a m i n a d o r=n e wC a m i n a d o r A P r o p u l s i o n ( ) ; c o n n o r K i l l e r . M a t a r A J o h n C o n n o r ( ) ; } C o n s o l e . W r i t e L i n e ( " Y E E E E E E E E E E E E A H H H H H H H H " ) ;

Te desafo a igualar esto con herencia


juank.black-byte.com/csharp-patrones-diseno-estrategia/ 8/9

06/06/13

C# - Patrnes de Diseo - Estrategia | Ideas de un Conejo

YEEEEEEEEEEEEAHHHHHHHH

juank.black-byte.com/csharp-patrones-diseno-estrategia/

9/9

También podría gustarte