Observer Model Overview

The observer pattern (sometimes called model-view pattern, source-listener pattern, or subordinate pattern) is one of the software design patterns. In this mode, a target object manages all observer objects that depend on it and actively notifies itself when its state changes. This is usually done by calling the methods provided by each observer. This pattern is often used to implement event handling systems.

Basic introduction

The Observer mode perfectly separates the Observer from the object being observed. For example, the user interface can act as an observer, and business data is observed. The user interface observes changes in business data, and when the data changes, it displays them on the interface. One of the principles of object-oriented design is that each class in the system focuses on one function rather than the other. An object does one thing and does it well. The Observer pattern sets clear boundaries between modules, improving application maintainability and reuse.

The observer design pattern defines a one-to-many combinatorial relationship between objects so that when an object’s state changes, all dependent objects are notified and refreshed automatically.

implementation

The observer pattern can be implemented in many ways, but fundamentally, the pattern must contain two roles: the observer and the observed. In this example, the business data is the observed object and the user interface is the observer. There is a logical association of “observation” between the observer and the observed. When the observed changes, the observer will observe such changes and make corresponding responses.

If you use this observation process between the user interface and business data, you can ensure that there is a clear distinction between the interface and the data. If the requirements of the application change and you need to modify the performance of the interface, you just need to rebuild the user interface and the business data does not need to change.

To observe the

When implementing the observer mode, it should be noted that the interaction between the observer and the observed object cannot be reflected as direct calls between classes. Otherwise, the close coupling between the observer and the observed object will fundamentally violate the principle of object-oriented design. Either the observer “observing” the observed object or the observed “notifying” the observer of their changes should not be called directly.

Observer pattern UML diagrams

There’s too much text on it. Let’s go straight to the picture

As you can see from the figure, the observer mode has three main roles:

  • Topics. There are many methods in the topic class, such as register() and deregister(), that Observer observers can use to register with or unregister from a topic. A topic can correspond to multiple observers, and you can think of it as a message.
  • Observer, which defines a notify() interface for subjects concerned so that they can be notified when the topic changes. You can think of it as push notifications.
  • For the observer, it is the interface of the first observer to keep their status consistent with the changes in the theme. You can think of it as each hero, such as The Deppon steward Zhao Xin, the Demathian prince Gavin IV, Raven the Banish Blade, and of course the Swift scout Timo.

This process is not complicated, specific observer (such as jia article iv, sharp Vivian) provided by the observer interface registered himself with the theme, every theme state changes, the subject will use the observer (push) to provide notice to inform all the specific observer (xenzhao, jia wen, timothy, sharp Vivian) what had happened.

Why league of Legends?

Because everyone is familiar with League of Legends, and this isn’t the first TIME IG has won the LEAGUE of Legends championship for LPL division, I’m just enjoying the heat.

Can I choose another game?

Yes, as long as you can find a good example in the field you are familiar with, even if you use tank battles as an example.

What do league of Legends notices look like?

  • Welcome to league of Legends
  • Enemy troops have 30 seconds to reach the battlefield and crush them
  • The army attack
  • First blood
  • Ace League of Legends messages push messages to some or all summoners when they trigger events (such as time or action).

The process of message notification

Familiar lines are memorized, but do you know how these messages go from being generated to being delivered to each summoner?

Let’s rearrange the order:

  • Events trigger
  • Produce the message
  • Put the message on the queue
  • Other callers listen to the queue
  • The message is received when the queue changes

Consider: This process is not complicated. If you follow the flow chart and sequence above, can you write the code for the notification push?

What are the characteristics of Galen

Galen is one of the most distinctive and memorable characters in The league of Legends, and we think of him most often with his oversized sword and his “Demacia” roar.

Wait, Demacia?

How did demacia’s message reach the summoners?

Given the basics of the observer pattern, we should have a mental picture of the code. For example, write a notification class, a message queue, an observer, and 10 specific observers (league of Legends 10 players per game).

How does the news spread?

Now that the message queue is available, how do you get the “Demacia” sound to the ears of the summoner when the event is triggered (Galen’s big move)?

How do you decide who to send to, but also exclude the heroes who are far away.

The most important message class

First we create a new message class. This message class needs to provide an interface for heroes to register and unregister observers, and maintain a subscriber queue and the last message:

class NewsPublisher(object):
    """Message Topic class"""

    def __init__(self):
        self.__subscribers = []
        self.__latest_news = None

    def register(self, subcriber):
        """Observer Registration"""
        self.__subscribers.append(subcriber)

    def detach(self):
        """Observer logout"""
        return self.__subscribers.pop()
Copy the code

What do we need next? Now that the queue is in place, the subscriber list and the method responsible for message notification are not yet in place, and the interface for message creation and update needs to be written, change the message class to:


class NewsPublisher(object):
    """Message Topic class"""

    def __init__(self):
        self.__subscribers = []
        self.__latest_news = None

    def register(self, subcriber):
        """Observer Registration"""
        self.__subscribers.append(subcriber)

    def detach(self):
        """Observer logout"""
        return self.__subscribers.pop()

    def subscribers(self):
        """Subscriber List"""
        return [type(x).__name__ for x in self.__subscribers]

    def notify_subscribers(self):
        """Walk through the list, notify the subscribers."""
        for sub in self.__subscribers:
            sub.update()

    def add_news(self, news):
        """New Message"""
        self.__latest_news = news

    def get_news(self):
        """Get new news"""
        return "New message received :", self.__latest_news
Copy the code

Observer interface

Then there’s the observer interface, which is supposed to be an abstract base class where the concrete observer (hero) inherits the observer. The observer interface needs to have a listening method so that whenever a new message is sent, all qualified observers can receive the corresponding message:

from abc import ABCMeta, abstractmethod

class Subscriber(metaclass=ABCMeta):
    """Observer interface"""
    @ abstractmethod
    def update(self):
        pass

Copy the code

heroes

init

The hero should also have an update() method so that the message class can push messages to the hero:



class Garen(object):
    """Galen"""
    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class JarvanIV(object):
    ""Gavin the Fourth.""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class Riven (object):
    """Sharp Vivian"""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class Quinn(object):
    """Wings of Demacia."""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class XinZhao (object):
    """Deppon's steward."""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class AurelionSol(object):
    """Cast the Dragon King."""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class Aatrox(object):
    """Dark Blood Sword Demon."""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class Ryze(object):
    """The Mage"""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class Teemo(object):
    """Swift Scouts."""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())


class Malzahar (object):
    """Malzaha"""

    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.register(self)

    def update(self):
        print(type(self).__name__, self.publisher.get_news())



Copy the code

Summoner Canyon now has ten heroes, which means the game is now on.

Demacia!

Who can hear that demacia?

if __name__ == "__main__":
    news_publisher = NewsPublisher()  Instantiate the message class
    garen_position = (566, 300)  Set the current position of Galen
    # The current position of each hero
    role_position = [(JarvanIV, 220, 60), (Riven, 56, 235), (Ryze, 1090, 990),
                     (XinZhao, 0, 0), (Teemo, 500, 500), (Malzahar, 69, 200),
                     (Aatrox, 460, 371), (AurelionSol, 908, 2098), (Quinn, 1886, 709)]
def valid_position(role_a: int, role_b: int):
    Confirm with screen range
    if abs(role_a - role_b) < 200:
        return True
    return False

for sub in role_position:
    if valid_position(sub[1], garen_position[0]) or valid_position(sub[2], garen_position[1]):
        # only send to heroes with the same screen
        sub[0](news_publisher)

Copy the code

Now that I’ve defined all the changes, and I’ve distinguished coordinates and heroes from the same screen, how do I send a new message?

print("Heroes on the same screen are:", news_publisher.subscribers())
news_publisher.add_news("Demacia!)
news_publisher.notify_subscribers()
Copy the code

First confirm the heroes on the same screen from the subscriber list, issue Galen’s roar “Demasia” from the add_news() method in the message class, and then notify all heroes in the subscriber list using the notify_Subscribers () method in the message class.

See what the output looks like:

Heroes on the same screen are: ['Riven'.'Teemo'.'Aatrox']
Riven ('New message received :'.'Demacia! ')
Teemo ('New message received :'.'Demacia! ')
Aatrox ('New message received :'.'Demacia! ')
Copy the code

Thus the voice of “Demacia” reached the Dark Sword Demon, the Swift Scouts, and the Banished Blade.

To look again

If you don’t understand it the first time, try it out while looking at the UML diagram and you’ll understand the observer pattern once and for all.