Palavra:   

Revista PHP / PHP

Marcus Brasizza

Utilzando o Design Pattern OBSERVER utilizando as interfaces SPL.

Utilzando o Design Pattern OBSERVER utilizando as interfaces SPL (STANDARD PHP LIBRARY)

Introdução:


Quando queremos avisar o termino de um método normalmente utilizamos return 1 ou return true, false, dentre outros processos que indicam que o processo foi executado ou em que parte do processo o código esta executando.

Pensando em uma estruturação de objetos esta prática pode ser considerada errada, pois isso é uma programação procedural dentro de um objeto.

Para enviarmos o fim da execução ou até mesmo em que "pé" esta o processo de atualização, inserção , Utilizaremos o Observer Pattern.

Definição:

A utilização é um objeto que será observado por um ou mais objetos , que são os observadores, que obviamente são associados como observadores deste objeto, e quando o observador disparar um método de notificação, todos os objetos associados (os observadores) executarão cada um sua rotina específica, assim fazendo com que o processo seja organizado e evitando colocar instancias de objetos dentro de outros objetos ou até mesmo um aninhado de instancias para cada objeto que irá executar algo.

Utilização:

Utilizarem duas interfaces já disponíveis no PHP chamadas de SplObserver e SplSubject, disponíveis dês do começo do PHP 5.1.xxxx

- Interface SplSubject: é a interface que será implementada no Observado. contém os metodos attach e detach e notify
-- attach: Adiciona observadores ao objeto.
-- detach: Remove observadores.
-- notify: Envia a notificação para todos os observadores do objeto.

- Interface SplObject: é a interface do observador. contém somente o método update.

NOTA : Todos os métodos dessas interfaces, são explícitos em relação aos métodos, chamados de type-hint, ou seja , para o método attach só deve ser enviado como parâmetro um objeto do tipo SplObserver, o mesmo para o detach, tudo isso existe uma documentação, e vou colocar um código de exemplo.

Desenvolvendo:

Vamos primeiro criar a classe que será observada pelos demais objetos, chamaremos ela de Materia
  1. <?php
  2.  
  3. class Materia implements SplSubject {
  4.  
  5. private $nome_materia;
  6. // Os observadores é um array onde ele guardará todas as instâncias dos objetos que forem adicionados
  7. private $_observadores = array();
  8. // Coloquei um array de log só para mostrar o funcionamento do Observer
  9. private $_log = array();
  10. // Encapsuladores
  11. public function GET_materia()
  12. {
  13. return $this->nome_materia;
  14. }
  15.  
  16. function SET_log($valor){
  17. $this->_log[] = $valor ;
  18. }
  19. function GET_log(){
  20. return $this->_log;
  21. }
  22. // Função construtora que irá somente associar um nome ao professor
  23. function __construct($nome){
  24. $this->nome_materia = $nome;
  25. $this->_log[] = " Materia $nome foi incluida com sucesso";
  26. }
  27. // Implementa o método attach do SplSubject, enviando como parâmetro um observador e associando ao array de objetos
  28. public function attach(SplObserver $classes){
  29. $this->_classes[] = $classes;
  30. $this->_log[] = " O ".$classes->GET_tipo()." ".$classes->GET_nome()." foi adicionado";
  31. }
  32. // Implementa o método detach do SplSubject, que somente remove a instância do objeto
  33. public function detach(SplObserver $classes){
  34. foreach ($this->_classes as $key => $obj){
  35. if ($obj == $classes){
  36. unset($this->_classes[$key]);
  37. $this->_log[] = " O ".$classes->GET_tipo()." ".$classes->GET_nome()." foi removido";
  38. }
  39. }
  40. }
  41. // Implementa o método notify do SplSubject, que percorre todo o array de observadores e chama o método update de do observador, que esta implementado dentro da sua classe
  42. public function notify(){
  43. foreach ($this->_classes as $classes){
  44. $classes->update($this);
  45. }
  46. }
  47. }
  48. ?>
Feito isso, criaremos uma classe de Professor.
  1. <?php
  2. class Professor implements SplObserver{
  3. protected $tipo = "Professor";
  4. private $nome;
  5. private $endereco;
  6. private $telefone;
  7. private $email;
  8. // Encapsulador
  9. public function GET_tipo(){
  10. return $this->tipo;
  11. }
  12.  
  13. public function GET_nome()
  14. {
  15. return $this->nome;
  16. }
  17.  
  18. public function GET_email()
  19. {
  20. return $this->email;
  21. }
  22.  
  23. public function GET_telefone()
  24. {
  25. return $this->nome;
  26. }
  27. // Construtor que somente associa o nome do professor
  28. function __construct($nome) {
  29. $this->nome = $nome;
  30. }
  31. // Implementa o método update do SplObserver, que executa o método de acordo com a necessidade do objeto Professor
  32. public function update(SplSubject $object){
  33. $object->SET_log("Vindo de ".$this->nome.": Dou aula de ".$object->GET_materia());
  34. }
  35. }
  36. ?>
Criaremos agora uma classe de Aluno.
  1. <?php
  2. class Aluno implements SplObserver{
  3. protected $tipo = "Aluno";
  4. private $nome;
  5. private $endereco;
  6. private $telefone;
  7. private $email;
  8. // Encapsulador
  9. public function GET_tipo(){
  10. return $this->tipo;
  11. }
  12.  
  13. public function GET_nome()
  14. {
  15. return $this->nome;
  16. }
  17.  
  18. public function GET_email()
  19. {
  20. return $this->email;
  21. }
  22.  
  23. public function GET_telefone()
  24. {
  25. return $this->nome;
  26. }
  27. // Construtor que somente associa o nome do aluno
  28. function __construct($nome) {
  29. $this->nome = $nome;
  30. }
  31. // Implementa o método update do SplObserver, que executa o método de acordo com a necessidade do objeto Aluno
  32. public function update(SplSubject $object){
  33. $object->SET_log("Vindo de ".$this->nome.": Sou aluno de ".$object->GET_materia());
  34. }
  35.  
  36. }
  37. ?>
Com as classes criadas, iremos associar os observadores na classe observada e depois notificaremos.
  1. <?php
  2. require_once("professor.class.php");
  3. require_once("aluno.class.php");
  4. require_once("materia.class.php");
  5.  
  6. $materia = new Materia("Matematica");
  7. $marcus = new Professor("Marcus");
  8. $rafael = new Aluno("Rafael");
  9. $vinicius = new Aluno("Vinicius");
  10. // Associando os observadores no objeto Materia Matemática
  11. $materia->attach($rafael);
  12. $materia->attach($vinicius);
  13. $materia->attach($marcus);
  14.  
  15. $materia2 = new Materia("Portugues");
  16. $renato = new Professor("Renato");
  17. $fabio = new Aluno("Fabio");
  18. $tiago = new Aluno("tiago");
  19. // Associando os observadores no objeto Materia Portugues
  20. $materia2->attach($renato);
  21. $materia2->attach($vinicius);
  22. $materia2->attach($fabio);
  23. $materia2->attach($tiago);
  24.  
  25.  
  26. // Removendo Alunos da Materia 1
  27. $materia->detach($rafael);
  28.  
  29.  
  30. // Notificando as 2 Matérias
  31. $materia->notify();
  32. $materia2->notify();
  33.  
  34. echo "Materia 1 <br>";
  35. echo "<pre>";
  36. print_r($materia->GET_log());
  37. echo "</pre>";
  38. echo "<hr>";
  39. echo "Materia 2 <br>";
  40. echo "<pre>";
  41. print_r($materia2->GET_log());
  42. echo "</pre>";
  43.  
  44. ?>
O output esperado é esse:

Materia 1
  1. (
  2. [0] => Materia Matematica foi incluida com sucesso
  3. [1] => O Aluno Rafael foi adicionado
  4. [2] => O Aluno Vinicius foi adicionado
  5. [3] => O Professor Marcus foi adicionado
  6. [4] => O Aluno Rafael foi removido
  7. [5] => Vindo de Vinicius: Sou aluno de Matematica
  8. [6] => Vindo de Marcus: Dou aula de Matematica
  9. )
Materia 2
  1. (
  2. [0] => Materia Portugues foi incluida com sucesso
  3. [1] => O Professor Renato foi adicionado
  4. [2] => O Aluno Vinicius foi adicionado
  5. [3] => O Aluno Fabio foi adicionado
  6. [4] => O Aluno tiago foi adicionado
  7. [5] => Vindo de Renato: Dou aula de Portugues
  8. [6] => Vindo de Vinicius: Sou aluno de Portugues
  9. [7] => Vindo de Fabio: Sou aluno de Portugues
  10. [8] => Vindo de tiago: Sou aluno de Portugues
  11. )
Esse é um exemplo simples de como utilizar um observer sem precisar colocar uma instância do professor e aluno dentro da matéria.
Pode ser feito muito mais com isso, como por exemplo um observer que ao cadastrar uma pessoa , envia um email para o admin. Use a imaginação e espero que gostem
Qualquer dúvida, crítica,sugestão ou incentivo para escrever mais artigos: mvbdesenvolvimento@gmail.com

Abraços

Opções de Interação

Comentários

Ótimo
Por: Diana, 11/05/2010   11:38:13
Parabéns pela publicação. O texto esta detalhado e claro e o exemplo foi ótimo para uma melhor compreensão do Pattern.