Observer is a common pattern in UIs, where components need to update in response to input events or real-time changes elsewhere. You'll learn how to implement the observer pattern in this lesson.
1.Introduction1 lesson, 01:40
2.Creational Patterns2 lessons, 11:52
3.Structural Patterns4 lessons, 33:47
4.Behavior Patterns4 lessons, 36:32
5.Conclusion1 lesson, 01:06
The observer pattern is very popular, especially with graphical interfaces. Because the whole idea behind events wouldn't exist without the observer pattern. Whenever you click on a button or move the mouse or type something on the keyboard, that is going to essentially execute code that belongs inside of another class or another object. And perhaps with that little description, you have a good idea of what the observer pattern is about. So we essentially have two things, we have an object that is called the observable object. This is where something is going to happen. And then we have another object that's called the observer. And the observer is observing the observable. So when something happens in the observable, the observable is going to notify the observer that something happened, so that the observer can do whatever it is that it needs to do. Now if that's clear as mud, some code is going to help. So let's say that we are working on an application that has a shopping cart. So let's go ahead and create a class called ShoppingCart. And of course, this would be specific for an individual user, and of course, it would also include all the things that they added to their cart. So let's say that whenever a user adds something to the cart, we want to log it within our application's log. And so that would be another class. So let's just call this ShoppingCartLog. And we can say that our ShoppingCart class has a method called add item. So whenever we add an item to the cart, we want to update our log. So the ShoppingCart is going to be our observable object. The ShoppingCartLog is going to be the observer object. And we have to set up a relationship between the two, so that when the shopping cart has an item added to it, then it notifies the shopping cart. But even though they know about each other, they are still decoupled, because the shopping cart doesn't know what it is sending a message to. It just knows that it's sending a message to something. And the shopping cart knows that it's retrieving information from something. But it doesn't really know what that is. And so that's the whole idea behind the observer pattern, so that you can decouple your code while still maintaining some functionality there. So we are going to add an item. And there's a lot of information that could come with adding an item to a shopping cart. But in this case, we're just going to stick with the id of an item. And then inside of this method, we want to notify anything that is observing our cart. So lets add a TODO, update listeners, or let's use the terminology observers. And in our ShoppingCart, let's have a method that is going to be called logItem. So we would need to know the id of the item that we wanted to log. Ideally, we would have some other information like the user. Because that's kind of important, we want to log the item in accordance with the user that's adding that item. But for right now, we're just going to keep it this simple. And as far as what this method is going to do, we're just going to say that we're logging the item with a given id and that's really it. So let's go ahead and create these objects, we have our shopping cart, so we will new up our ShoppingCart constructor. Then we will say the logger, for the lack of a better term, is going to be a ShoppingCartLog. Now, we need to form some relationship between these two objects, and it depends upon the language that you're using. In the case of PHP, we're going to set the relationship between the objects themselves. With other languages, we could just use a callback function or things like that. But with PHP, we could do something like that, but that's a little more difficult to do so. So in this case, we're going to say that we have our $cart, and we are going to attach a log or something that is going to listen for whenever we add an item. So we are just going to pass in our logger object, and that's how we are going to set up this relationship. So inside of our ShoppingCart class, we need a public function attach. And we are going to call this logger, we could call it really whatever we wanted to. But we need to keep track of all of these things that we are going to notify whenever we add an item. So instead of logger, let's just call this observers, because that's what this is. And we are also going to need to store these. So that whenever we attach an observer, we want to store that within an array, so that we can have as many observers as we want. And whenever we add an item, we just need to iterate over that array, and notify each one of our observers. So let's have a private observers, and we're just going to initialize that as a new array. And then inside of the attach method, we will say $this>observers, and we're going to set that equal to our $observer. So that's now inside of the add item method. We are going to use a foreach loop, and we're going to iterate over our observers. We'll call each one of those just a simple $observer. And then we will say $observer>logItem. Although in this case, logItem really doesn't make sense. Because the shopping cart doesn't really know what types of objects are going to be used as observers. So logItem probably isn't the best name for our method here. So let's see, we are adding items. We could just call this itemAdded for the lack of a better term. And then we will pass in the id, so let's change our method inside of the shopping cart to itemAdded. Now, we're making a lot of assumptions here. We are assuming that the object that we are passing to attach has this itemAdded method. So really we should define some interfaces, so that we can ensure all of our observers have the itemAdded method. So let's call this interface ShoppingCartObserver. And all we really need here is to say that we have a function called itemAdded that is accepting an int value. Okay, so now for our ShoppingCartLog, we are going to implement the ShoppingCartObserver interface. And for the attach method inside of our shopping cart, we are going to use the ShoppingCartObserver as a typant. And you know what, let's put in the I here, IShoppingCartObserver, IShoppingCartObserver, and IShoppingCartObserver. And so now we should be able to call the addItem method. We're going to add the item with an id of 1, let's also do this a few more times, we want the id with 5 and the 1 with the id of 2745. So if we hop on over to the command line and we run this, we should hopefully see, well, there we go, we have logged item 1, item 5, and item 2745. So this is essentially the observer pattern. But one addition that you would probably see in many implementations is another method, one that's used to perform the notification to the observers. So that inside of the addItem method, we would have the code for adding item to the shopping cart. And then we would call a method called notify or something like that. And the notify method would then go through all of the observers and call them as needed, so let's do that. So we have our addItem function, we would have the code for adding the item, and then we are going to notify everything. So this is going to be a private function, we don't want this to be available outside of the class. And this is going to accept an int for the id value. And then it's simply going to iterate over everything. So just to make sure that this works, we'll run this code again and there we go. So the observer pattern is very useful when you have an object that needs to notify other objects when something happens. It decouples the relationship between those objects, so that there is no hard dependency between them.