Uma classe que pode ajudar – Executando evento de tempos em tempos
2011/07/05 Deixe um comentário
Boas brotherhood, no post de hoje, vou compartilhar com voces uma classe que eu bolei e achei que ficou bacaninha. Let’s rock.
Bom tudo começou com uma necessidade la no meu trampo. Existe um processo que deve ficar rodando de tempos em tempos executando uma tarefa X. A partir dessa ideia, eu resolvi bolar uma classe que me permitisse executar essa tarefa. Claro que dava pra fazer de varias formas esse tipo de logica, mas eu quis encapsular essa inteligencia em uma classe de modo a permitir o reuso dessa mesma, sem repetecos de loops e nada do genero. Bom, a ideia era construir uma classe que ficaria repetindo um processo de tempos em tempo. Bom, nisso identificamos que precisaremos de uma propriedade onde sera definido o intervalo de tempo de execução entre uma tarefa e outra. Alem disso, vamos precisar iniciar,parar,pausar,continuar,reiniciar o processo. Nisso, tambem devemos ter uma segunda propriedade que indica o status do processo. Abaixo voces podem ver a definição de um enum com os possiveis status do processo:
public enum FactoryProcessStatus
{
Stopped = 0,
Stopping = 1,
Starting = 2,
Running = 3,
Pausing = 4,
Paused = 5,
Resuming = 6,
}
Como o nosso processo vai estar em constante execução, os metodos mencionados acima irão apenas alterar os estados, ficando por conta do processo realizar determinado comando de acordo com o estado que fora alterado. Abaixo voce poderão ver a definição da classe:
public delegate void TimeoutReachedHandler();
public delegate void StatusChangedHandler(FactoryProcessStatus status);
public delegate void ProcessFinishedHandler();
public delegate void ProcessPausedHandler();
public delegate void ProcessStartedHandler();
public delegate void RunProcessDelegate();
public class FactoryProcess
{
private bool _mustRestart;
private bool _stopProcess;
public int Timeout { get; set; }
private FactoryProcessStatus _status;
public FactoryProcessStatus Status
{
get
{
return this._status;
}
set
{
this._status = value;
if (OnStatusChanged != null)
OnStatusChanged(this.Status);
}
}
public event TimeoutReachedHandler OnTimeoutReached;
public event StatusChangedHandler OnStatusChanged;
public event ProcessFinishedHandler OnProcessFinished;
public event ProcessPausedHandler OnProcessPaused;
public event ProcessStartedHandler OnProcessStarted;
public FactoryProcess(int timeout = 300000)
{
this._stopProcess = false;
this.Timeout = timeout;
}
public void Pause()
{
this.Status = FactoryProcessStatus.Pausing;
}
public void Restart()
{
this._mustRestart = true;
this.Stop();
}
public void Resume()
{
this.Status = FactoryProcessStatus.Resuming;
}
public void Start()
{
this.Status = FactoryProcessStatus.Starting;
this.RunProcessAsync();
}
public void Stop()
{
this.Status = FactoryProcessStatus.Stopping;
}
private void RunProcess()
{
while (!_stopProcess)
{
if (this.Status == FactoryProcessStatus.Stopping)
{
this._stopProcess = true;
this.Status = FactoryProcessStatus.Stopped;
}
else if (this.Status == FactoryProcessStatus.Starting)
{
this.Status = FactoryProcessStatus.Running;
this._stopProcess = false;
}
else if (this.Status == FactoryProcessStatus.Pausing)
{
this.Status = FactoryProcessStatus.Paused;
this._stopProcess = false;
if (OnProcessPaused != null)
OnProcessPaused();
}
else if (this.Status == FactoryProcessStatus.Resuming)
{
this.Status = FactoryProcessStatus.Running;
this._stopProcess = false;
}
if (this.Status == FactoryProcessStatus.Running)
{
if (this.OnTimeoutReached != null)
this.OnTimeoutReached();
}
if (this.Status == FactoryProcessStatus.Running || this.Status == FactoryProcessStatus.Paused)
{
Thread.Sleep(this.Timeout);
}
}
}
private void RunProcessAsync()
{
RunProcessDelegate process = new RunProcessDelegate(RunProcess);
AsyncCallback callback = delegate
{
this._stopProcess = false;
if (OnProcessFinished != null)
OnProcessFinished();
if (this._mustRestart)
{
this._mustRestart = false;
this.Start();
}
};
process.BeginInvoke(callback, null);
if (OnProcessStarted != null)
OnProcessStarted();
}
}
Antes que voces me xinguem, o codigo acima tem de fato mais coisas do que as que mencionei. O que mencionei acima, foram as necessidades iniciais que levantei. Para que tudo funcionasse, tive que adicionar algumas coisas. Mas calma, eu irei explicar tudinho
. Bom, das linhas 1 a 6, temos a definição dos nossos delegates. Esses delegates serão utilizados quando estivermos definindo nossos eventos que serão disparados para informar progressos do nosso processo. Ha um evento que é o evento chave da classe. O cliente que estiver utilizando a classe, devera implementar a logica que ele desejar ser executada de tempos em tempos. Mais a frente, na utilização dessa classe, as coisas ficarão mais claras (pelo menos eu espero
). A declaração dos eventos esta das linhas 27 a 31. Alem das duas propriedades mencionadas, tambem temos duas variaveis privadas para controle interno do processo. A partir da linha 33, temos as implementações dos metodos mencionados anteriormente. A maioria deles apenas altera o Status para que mais pra fente, o processo efetue os comandos conforme o status corrente. Ja da linha 60 em diante, temos dois metodos privados, onde um é o metodo assincrono que é invocado quando executamos o metodo Start definido acima. O outro, é o metodo core da nossa classe. É nele que toda a magica acontece. Ele faz uso de uma das nossas variaveis de controle para poder rodar o processo. Alem disso, ele faz as devidas verificações para que possa executar as devidas ações relacionadas ao processo. Bom, chega de falar, eu não gosto de falar muito, então vamos mostrar a implementação da classe acima criada.
public partial class MainWindow : Window
{
private FactoryProcess factory = new FactoryProcess(5000);
public MainWindow()
{
InitializeComponent();
factory.OnTimeoutReached += new TimeoutReachedHandler(Factory_OnTimeoutReached);
factory.OnStatusChanged += new StatusChangedHandler(Factory_OnStatusChanged);
factory.OnProcessFinished += new ProcessFinishedHandler(Factory_OnProcessFinished);
}
void Factory_OnProcessFinished()
{
//Implementação da logica quando o processo for finalizado.
}
void Factory_OnStatusChanged(FactoryProcessStatus status)
{
//Implementação da logica quando o status do processo for alterado. De em execução para pausado, por exemplo.
}
void Factory_OnTimeoutReached()
{
//Implementação da rotina que deverá ser executada de tempos em tempos.
//Esse é o evento core que eu mencionei. Basta colocar a logica que desejar executar e
//quando voce der o start, esse metodo sera executado, baseado no timeout definido.
}
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
factory.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
factory.Pause();
}
private void buttonResume_Click(object sender, RoutedEventArgs e)
{
factory.Resume();
}
private void buttonStop_Click(object sender, RoutedEventArgs e)
{
factory.Stop();
}
private void buttonRestart_Click(object sender, RoutedEventArgs e)
{
factory.Restart();
}
}
Acho que agora deu pra entender (espero que sim). A ideia é abstrair a complexidade(que na verdade nem é tão grande) das verificações e controles, para que quem for implementar, o faça de forma simples e elegante
. Bom por hoje é isso galera, até o proximo post! \m/







