Benefits of using the Observer pattern

At the start of this chapter we saw three problems with interacting gameplay code. As we said before, these problems aren't that big, but they creep up all over the place and can lead to inflexible code as the project moves forward. The Observer pattern solves these problems in a very simple way.

The biggest benefit of using the Observer pattern is that we can reduce dependency and coupling. By using the Push version of the Observer pattern, our classes can interact completely through interfaces, so they don't depend on each other at all. In the preceding example, the Player and Player Display are completely decoupled. This means that changes to one won't affect the other. For starters, this makes each class easier to test and debug because they can be worked on separately. However, this also means that as the game changes, these classes can change independently. This means the individual class can easily be reused within the current project or in separate projects. The only problem with the Push version is that we are stuck with a single Update method signature.

Using the Pull version of the Observer pattern increases the dependencies; however, the Subject/Observer system is much more flexible. An Observer can now listen to multiple Subjects, and a Subject can share different data with each of its Observers. Even though the dependencies are increased, this is only on the Observer side, since Subjects still don't need to know about their Observers. These increased dependencies are still better than the alternative, because they are limited to only the two classes that need to interact. Without using the Observer pattern, a third class would need to be used to link these two classes together.

The second benefit of this pattern is that we no longer need to hardcode methods or requirements. Since the event is broadcast to any object that registers, there is no need to recompile if a new object needs the event. This reduces compile times as well as limits the chance of breaking code.

This isn't just limited to connecting systems to other systems. Since Observers can register and unregister at runtime, game objects can register themselves with other game objects. Imagine an Enemy Space Station that continuously spawns Raiders. By registering Raiders with the station that spawned them, each station can act as a mini commander, easily coordinating units for attack and defense.

The last benefit is that there is no need to poll objects. In the preceding example, we saw two while loops--one using the Observer pattern, and one polling for data every frame. We saw how much cleaner the code looked when using the Observer pattern. Besides just looking cleaner, the first example is less likely to have bugs because once registered, the Observer will always receive the updated data. In a larger project, the alternative requires that every object constantly asks for the data all over the code base. Ensuring that every object that needs the data asks every frame in many locations can be a Herculean task.

In addition to being very difficult to find and maintain each poll occurrence, this method leads to less efficient code. We shouldn't try to prematurely optimize our code, and most likely this won't be the bottleneck of our game, so that is why we mentioned it last. However, the fastest code is the code that never runs. When using the Observer pattern, if the data never changes and the event never occurs, the Update methods never get called. So, using the Observer method has the chance to boost our performance compared to polling dozens or hundreds of times per frame.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.190.175