Wzorzec projektowy obserwator - observer

Stronę tą wyświetlono już: 96 razy

Opis wzorca projektowego obserwator

Wzorzec projektowy obserwator należy do czynnościowych wzorców projektowych. Celem tego wzorca jest wywoływanie klasy zawierającej klasy obserwatorów w momencie, gdy zajdzie określona zmiana w obiekcie obserwowanym. Innymi słowy jeżeli obserwowany obiekt zmienia stan, wtedy uruchamia on odpowiednią metodę klasy zawierającej obserwatorów a ta wywołuje kolejno metody na zarejestrowanych obserwatorach.

Przykładowy diagram UML dla wzorca projektowego obserwator

Na poniższym diagramie UML klasa MovingPoint dziedziczy po interfejsie iSubject, który przechowuje wskaźnik do obiektu klasy Observers. Klasa Observers agreguje wielokrotnie interfejsy iSubject, co z kolei oznacza, że obiekty klasy MovingPoint są w tym przypadku równocześnie obserwatorami. Możliwe jest oczywiście zaimplementowanie oddzielnej klasy reagującej na zmiany w obserwowanych obiektach.

Co ważne interfejs iSubject automatycznie rejestruje się do podanego wskaźnika na obiekt klasy obserwatora Observers. Czyni to za pomocą operatora += wewnątrz konstruktora interfejsu iSubject. Również usunięcie obiektu jest realizowane przez ten interfejs w jego wirtualnym destruktorze z wykorzystaniem operatora -=.

Każdy punkt po zmianie położenia wywołuje metodę checkCollision klasy Observers, która (jak sama nazwa mówi) sprawdza czy dany punkt koliduje z resztą punktów.

Przykładowy diagram UML wzorca projektowego obserwator
Rys. 1
Przykładowy diagram UML dla wzorca projektowego obserwator

Przykładowa implementacja wzorca projektowego obserwator w C++

Listing 1
  1. #include <iostream>
  2. #include <vector>
  3. class iSubject;
  4. class Observers{
  5. protected:
  6. std::vector<iSubject*> subjects;
  7. bool subjectExist(iSubject* subject){
  8. for(std::vector<iSubject*>::iterator checkedSubject = subjects.begin(); checkedSubject < subjects.end(); checkedSubject ++){
  9. if(subject == *checkedSubject)
  10. return true;
  11. }
  12. return false;
  13. }
  14. public:
  15. Observers& operator += (iSubject* subject) {
  16. if(!subjectExist(subject)){
  17. subjects.push_back(subject);
  18. }
  19. return *this;
  20. }
  21. Observers& operator -= (iSubject* subject) {
  22. for(std::vector<iSubject*>::iterator remove = subjects.begin(); remove < subjects.end(); remove ++){
  23. if(subject == *remove){
  24. subjects.erase(remove);
  25. break;
  26. }
  27. }
  28. return *this;
  29. }
  30. void checkCollision(iSubject* from);
  31. };
  32. class iSubject{
  33. protected:
  34. float x;
  35. float y;
  36. Observers* observers;
  37. public:
  38. iSubject(float x, float y, Observers* observers) : x(x), y(y), observers(observers){
  39. if(observers){
  40. (*observers) += this;
  41. }
  42. }
  43. virtual void collision(iSubject* subject) = 0;
  44. inline float getX() const { return x; }
  45. inline float getY() const { return y; }
  46. inline void setXY(float x, float y){
  47. this->x = x;
  48. this->y = y;
  49. if(observers){
  50. observers->checkCollision(this);
  51. }
  52. }
  53. virtual ~iSubject(){
  54. (*observers) -= this;
  55. }
  56. };
  57. std::ostream & operator << (std::ostream &ostr, const iSubject* subject)
  58. {
  59. return ostr << "{" << subject->getX() << "; " << subject->getY() << "}";
  60. }
  61. void Observers::checkCollision(iSubject* from){
  62. for(std::vector<iSubject*>::iterator subject = subjects.begin(); subject < subjects.end(); subject ++){
  63. if(from != *subject)
  64. (*subject)->collision(from);
  65. }
  66. }
  67. class MovingPoint : public iSubject {
  68. public:
  69. MovingPoint(float x, float y, Observers* Observers) : iSubject(x, y, Observers){}
  70. virtual void collision(iSubject* subject) {
  71. if(subject != this){
  72. if(x == subject->getX() && y == subject->getY()){
  73. std::cout << "Collision!!! " << this << " == " << subject << std::endl;
  74. }else{
  75. std::cout << "Uff, we are safe now!!!" << std::endl << "No colision with object on position " << this << " after moving object on position: " << subject << std::endl;
  76. }
  77. }else{
  78. std::cout << "This same object!!!" << std::endl;
  79. }
  80. }
  81. };
  82. int main(){
  83. Observers Observers;
  84. MovingPoint mp(0,0, &Observers);
  85. MovingPoint mp2(10,0, &Observers);
  86. MovingPoint mp3(15,5, &Observers);
  87. MovingPoint mp4(30,20, &Observers);
  88. mp2.setXY(15,5);
  89. std::cin.get();
  90. return 0;
  91. }

Wynik działania powyższego kodu:

Uff, we are safe now!!!
No colision with object on position {0; 0} after moving object on position: {15; 5}
Collision!!! {15; 5} == {15; 5}
Uff, we are safe now!!!
No colision with object on position {30; 20} after moving object on position: {15; 5}
Strony powiązane
strony powiązane
  1. sourcemaking.com/design_patterns/observer - strona opisująca wzorzec projektowy obserwator [En]
  2. pl.wikipedia.org - opis tego wzorca na stronie Wikipedii

Komentarze