/translations/pt-BR/observer.md

https://github.com/davidgf/design-patterns-in-ruby · Markdown · 133 lines · 109 code · 24 blank · 0 comment · 0 complexity · 3092bafa6f71b27eb5fd119b53f26f7a MD5 · raw file

  1. # O Padrão Observer (Observador)
  2. ## Problema
  3. Nós queremos construir um sistema que é altamente integrado, isso é, um sistema
  4. onde cada parte é consciente do estado do todo. Nós também querems que isso
  5. seja manutenível, então nós deveríamos evitar acoplamento entre classes.
  6. ## Solução
  7. Se nós quiseremos que algum componente (*observer*) tenha conhecimento sobre as
  8. atividades de outro componente (sujeito), nós poderíamos simplesmente conectar
  9. as duas classes e informar o primeiro sobre algumas ações executadas no segundo.
  10. Isso significa que nós deveríamos passar uma referência para o observador quando
  11. nós criamos o sujeito e chamar alguns de seus métodos quando o segundo muda. No
  12. entanto, com essa abordagem estamos fazendo algo que nós queremos evitar,
  13. aumento de acoplamento. Além disso, se nós quisermos informar algum outro
  14. observador, nós teríamos que modificar a implementação do sujeito de modo que
  15. ele notifique o novo observador, mesmo que nada tenha mudado. Uma abordagem
  16. melhor seria manter uma lista dos objetos interessados nas mudanças do sujeito
  17. e definir uma interface entre a fonte das novidades (o sujeito) e os
  18. consumidores (os observadores). Dessa forma, sempre que houver uma mudança no
  19. sujeito, nós apenas precisaríamos iterar sobre a lista de observadores,
  20. notifica-os usando a interface que definimos.
  21. ## Exemplo
  22. Vamos considerar um objeto `Employee`(funcionário) que tem uma propriedade
  23. `salary` (salário). Nós gostaríamos de ser capaz de mudar o salário dele e
  24. manter o sistema de folha de pagamentos informado sobre qualquer modificação.
  25. O jeito mais simples de alcançar isso é passando uma referência para a
  26. folha de pagamentos e informar sempre que nós modificarmos o salário do
  27. funcionário:
  28. ```ruby
  29. class Employee
  30. attr_reader :name, :title
  31. attr_reader :salary
  32. def initialize( name, title, salary, payroll)
  33. @name = name
  34. @title = title
  35. @salary = salary
  36. @payroll = payroll
  37. end
  38. def salary=(new_salary)
  39. @salary = new_salary
  40. @payroll.update(self)
  41. end
  42. end
  43. ```
  44. O problema é que, se nós quisermos notificar outro objeto (`TaxMan`, coletor de
  45. impostos por exemplo), nós teríamos que modificar a classe Empregado. Isso
  46. significa que outras classes estão guiando as mudanças para Empregado, mesmo que
  47. nada tenha mudado nela. Vamos fornecer um jeito de manter uma lista de objetos
  48. interessados nas mudanças de salário.
  49. ```ruby
  50. class Employee
  51. attr_reader :name, :title
  52. attr_reader :salary
  53. def initialize(name, title, salary)
  54. @name = name
  55. @title = title
  56. @salary = salary
  57. @observers = []
  58. end
  59. def salary=(new_salary)
  60. @salary = new_salary
  61. notify_observers
  62. end
  63. def add_observer(observer)
  64. @observers << observer
  65. end
  66. def delete_observer(observer)
  67. @observers.delete(observer)
  68. end
  69. def notify_observers
  70. @observers.each do |observer|
  71. observer.update(self)
  72. end
  73. end
  74. end
  75. ```
  76. Agora podemos usar o método `add_observer` para adicionar quantos objetos
  77. quisermos para a lista de observadores e todos eles seriam notificados quando o
  78. salário mudar.
  79. ```ruby
  80. fred = Employee.new('Fred', 'Crane Operator', 30000.0)
  81. payroll = Payroll.new
  82. fred.add_observer(payroll)
  83. tax_man = TaxMan.new
  84. fred.add_observer(tax_man)
  85. fred.salary=35000.0
  86. ```
  87. Mesmo sendo possível implementar esse padrão nós mesmos, a biblioteca padrão do
  88. Ruby contém um módulo pré-construído que nos permite tornar qualquer um de
  89. nossos objetos observáveis, nos libertando de termos que definir os mesmos
  90. métodos em todos os lugares. Vamos refatorar a classe Empregado para usar o
  91. módulo `Observable` (Observável):
  92. ```ruby
  93. require 'observer'
  94. class Employee
  95. include Observable
  96. attr_reader :name, :title
  97. attr_reader :salary
  98. def initialize(name, title, salary)
  99. @name = name
  100. @title = title
  101. @salary = salary
  102. end
  103. def salary=(new_salary)
  104. @salary = new_salary
  105. changed
  106. notify_observers(self)
  107. end
  108. end
  109. ```