Una aplicación escalable a modo de ejemplo

Posted on the abril 7th, 2007 under Design Patterns,Investigación,Programación Orientada a Objetos by Nacho

En el año 2005 cursé una materia electiva (Proceso de Desarrollo de Software) donde primeramente veíamos como diseñar un proyecto utilizando UML (diagramas de casos de uso, diagramas de actividad, diagramas de estado, diagramas de secuencias, diagramas de colaboración) utilizando patrones de diseño.

Luego vimos también una introducción al Proceso Unificado de Desarrollo.

Revisando el material, me encontré con software que hice en ese momento para practicar los conceptos aprendidos. Como varios que me conocen sabrán, cosa que aprendo, cosa que quiero probar.

Pues bien, este es el caso nuevamente.

Buscando en www.codeproject.com acerca de como hacer aplicaciones escalables con una arquitectura basada en plugins, escribí un par de clases y líneas en C# aplicando patrones como Strategy y Observer.

Este ejemplo es sólo un «ejemplo». Es totalmente cuestionable la eficiencia, lo que buscaba era lograr una arquitectura que me permitiera dejar cosas independientes. Y algo logré.

La clase principal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Windows.Forms;
namespace AutomatizadorPop
{
	/// <summary>
	/// Description of Main.
	/// </summary>
	public class MainClass {
		public static void Main(string[] args) {
			MainClass s = new MainClass();
		}
 
		public MainClass() {
			EmailAutomateAdapter eaa = new EmailAutomateAdapter();
			eaa.AddObserver(new Correo());
			eaa.checkForCommand();
		}
	}
}

Esta clase, crea una instancia de EmailAutomateAdapter, le agrega un observador Correo y le envia un mensaje checkForCommand. Básicamente la idea de la aplicación es esa. Checkear en busca de comandos, y si se encuentra uno, avisarle a los interesados.

Inicialmente pensé en tener un Thread con un Timer para chequear periodicamente, pero terminé optando por utilizar el Cron del sistema para simplificar la aplicación (quería probarla!!!).

La clase EmailAutomateAdapter (especializa Subject)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System;
using Pop3;
using System.Text.RegularExpressions;
namespace AutomatizadorPop
{
	/// <summary>
	/// Description of EmailAutomateAdapter.
	/// </summary>
	public class EmailAutomateAdapter: Subject {
		private Pop3Client email;
		private string passwordServ;
		private string passwordApp;
		private string server;
		private string userServ;
 
		public EmailAutomateAdapter() {
			commandKeyWord = "comando";
			userServ= "usuario";
			server= "pop.server.com";
			passwordServ = "elpassword";
			passwordApp = "123456";
			email = new Pop3Client(user, password, server);
		}
		public void checkForCommand() {
			try {
				email.OpenInbox();
				while( email.NextEmail() )   {
					if (this.verifyEmailSignature(email)) {
						this.Notify();	//Aviso a los interesados
						email.DeleteEmail();
					}
				}
				email.CloseConnection();
			}
			catch (Exception e) {}
		}
		private bool verifyEmailSignature(Pop3Client email) {
			// Verifica que el asunto sea commandKeyWord
			// y que contenga el password necesario permitir la ejecucion
			return email.Subject.ToLower().Equals(this.commandKeyWord)
				&amp;&amp;	email.Body.ToLower().Contains(this.password);
		}
		public string getCommand() {
			// Busca un comando de la forma "com: comando."
			// Comando de 3 a 10 caracteres
			// FIXME: quitar el espacio en el tag &lt; command&gt;;
			// Fue agregado para saltar el filtro de WordPress
			Match m = Regex.Match(email.Body.ToString(),
				"com:(&lt; command&gt;;[a-z]{3,10}).");
			if (m.Success) {
				return m.Result("${command}");
			} else {
				return "null";
			}
		}
	}
}

A continuación el código de el interesado Correo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
using TaskStrategy;
namespace AutomatizadorPop
{
	/// <summary>
	/// Description of EnviadorCorreo.
	/// </summary>
	public class Correo: IObserver
	{
		private ITaskStrategy task;
 
		public Correo()	{
		}
		public void Update(Subject sender) {
			EmailAutomateAdapter au = (EmailAutomateAdapter) sender;
			this.SetTaskStrategy(au.getCommand());
			task.doTask();
		}
		private void SetTaskStrategy(string stratParam) {
			stratParam = stratParam.ToLower();
			TaskManager tm = TaskManager.Instance;
			tm.LoadPlugins();
			task = TaskManager.Instance.GetStrategy(stratParam);
		}
 
	}
}

Bien. Esta clase hace uso del patrón Strategy para cambiar la tarea que se debe realizar, de acuerdo al comando. ITaskStrategy es una interfaz que puede ser realizada por cualquier clase, y crear un nuevo assemby con esta. El método SetTaskStrategy le envía al TaskManager el mensaje LoadPlugins, el cual revisará un directorio por defecto en busca de assemblies que implementen la interfaz ITaskStrategy. Con esto logro poder enviar el mensaje doTask al objeto que sea necesario y se instancie en ese momento, y que haga lo que tenga que hacer.

En un próximo post, contunúo agregando las clases restantes y además un diagrama de secuencias explicando todo el proceso.

Si bien cómo dije al principio, es algo bastante complejo para el problema que había que solucionar, la arquitectura permite probar y evaluar distintas opciones para su extensión y aplicación a otros problemas.

2 Responses to 'Una aplicación escalable a modo de ejemplo'

  1. septiembre 26, 2008 a las 10:31 pm
    Humberto
  2. diciembre 13, 2008 a las 1:18 pm
    Aoepbnmw

Leave a Reply




XHTML::
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>