Whether C++ or JAVA, a Notification to the observer can come along with the information of what is changed. The same methods notifyObservers(Object arg) can also be used in C++ as well.
Generally, the issue will remain is that there could be multiple subjects dispatching to one or multiple observers and hence, the class arg
cannot be hard coded.
Usually, the best way to do is to make arg in the form of generic message/tokens that forms the same data type for various classes but values differ for different observed classes. Alternatively, if all such notification values are derived out of the class on some based class which is common to all.
For observer pattern, it is important that Arg data type is not hard coded between the observee and observer - else it is a coupling that makes things difficult to evolve.
EDIT
If you want that observer not only observes but also needs to do a lot of other tasks based on the what has changed then, you can also check out Visitor pattern. In visitor pattern, the observer/visitor calls the modified object and hence can not only know what the modification is but can actually work on it
To me this is maybe not the best use case for the observer pattern, since it would require the subject to require a boatload of knowledge about who is observing it and when a particular observer should be notified. Just thinking about it and how to separate which observer gets notified under what condition had me working my way towards wanting to put the bulk of the entire game logic into the subject or something pulling its strings and telling it exactly who to notify.
The main idea of the observer pattern is to decouple and abstract away the subject from the observers, so that you can do things like attach whoever/whatever to observe the subject as it goes through state changes so that whoever/whatever can know about it. The subject shouldn't have to know much about who is observing it, and definitely not any concrete information about who is observing it. It's a broadcast mentality like, "To whomever is listening out there, something happened", not, "the player shot an arrow so I should notify this exact enemy within its line of sight about getting hit." That's way TMI for the subject to know about its observers.
Sometimes an observer implementation might distinguish subjects by some abstract concept which doesn't require much knowledge about them, like an observer group
: "notify this group of observers." But it's still very aimless. Aimless kind of broadcasting to observers who subscribe should be kind of the thinking pattern when you consider whether or not to use the observer pattern, and what you are tempted to do here is far from aimless (it has the aim of an expertly-shot arrow leading to a headshot -- sorry, lame joke).
Instead I think all you need are really abstractions for concepts like players and enemies (or maybe a "Creature" or something that unifies them -- endless ways to go here). And you might need one or more things to process your game logic. For example, input event for spacebar might trigger player to shoot an arrow doing all things you listed like subtracting ammo count. Then with the arrow projectile created (which might also be abstract as a "projectile" instead of, specifically, "arrow"), you might have something being invoked in the game loop like a physics system moving/processing all projectiles in the game. When it collides with an entity like a "creature" or something like that (something abstract so that you don't have to distinguish like an orc from a goblin), you might call an abstract function that causes it to be hit by the projectile.
This is a rather simplistic example, but something to this effect, yet this is done just by abstracting your game entities rather than using the observer pattern.
Best Answer
When implementing the Observer pattern, there are two main approaches to consider: the 'push' model and the 'pull' model.
In the 'push' model, the subject (i.e. the Observable) sends the observer on notification all the data it will need. The observer doesn't need to query the subject for information. In the 'pull' model, the subject merely notifies the observer that something happaned, and the observer queries the subject based to get the information it needs.
Let's discuss the pros and cons of both approaches:
Push
The main advantage of the 'push' model is lower coupling between the observer and the subject. The observer doesn't need to know anything about the subject in order to query it. If it needed to, we'd need to do one of the following: A- do downcasting on the side of the observer in order to invoke class-specific
get
methods on the subject. This is bad. B- make theObservable
interface more class-specific, offering specificget
methods, thus making the relationship between the observer and subject less general and making things more copupled.By implementing the 'push' model, we avoid all of this.
However the disadvantage is less flexibility: the subject may not always know what exact information the observers need in order to send it to them. This will often mean more specific Observer intefaces, such as
AgeObserver
that are notified when the 'age' of the subject is changed, andHeightObserver
which are sent the currentheight
of the subject on notification.This is one option. The other is the subject sending a whole lot of information encapsulated in an
Info
object of some sort and have the observers query it from there. But again, we can't be sure we're sending the correct info. So it's either this, or forcing the observers to implement more specific Observer interfaces, which tightens the coupling on the observer's side.Pull
I already noted the disadvantages of the 'pull' model. The observers would have to know things about the subject in order to query the right information, which leads A- to downcasting (ugly), or B- favorably to more specific
Observable
interfaces, that offer more specific accessor methods. For exampleAgeObservable
offers agetAge()
method.The advantage of this is more flexibility. Each observer can decide for itself what to query, without relying on the subject to send the correct information.
You should choose the strategy that is better for the specific project you're working on.
In reality, you'll always have specific
Observer
andObservable
intefaces, so you have some coupling between the sides anyway.So choose either 'pull' or 'push' by what fits you best.
Do all
AgeObserver
s need simply theage
of the subject? Implement the 'push' model. Less coupling and simpler.Do all
HeightObserver
s need varying information about the subject - aka one needs to query the age too, and some other object needs to query the weight in addition to the height? Implement the 'pull' model. This would force you to add accessors (getters) to theObservable
inteface (either this or pass the actual object as a parameter in it's explicit type, but doing this through the interface allows you to deny the observers access to things that don't matter to them). This soultion creates higher coupling, but it's more flexible.Choose what fits your situation best.