Using the Built-in Observer and Observable Classes10:39 with Craig Dennis
In the java.util package there is a class named Observable. It's been there a while, let's dust it off and use it to make our Restaurant Simulator hummmm.
So in order to make all the different configuration changes to our restaurant 0:00 simulator throughout our day, 0:03 it's clear that we're going to need to make things more extensible. 0:05 Different clients are gonna have different needs, and 0:09 we need to be able to configure things for each of our clients specifically. 0:11 Observer to the rescue. 0:15 So I've got some great news for you. 0:16 The Observer pattern has been included in the JDK pretty much from the beginning. 0:18 It's fairly well documented, and it's pretty straightforward to implement. 0:23 There are some complaints about the way that it's implemented, 0:26 and we'll explore those after we get our hands dirty with it a little bit. 0:29 Now, a quick word of warning here. 0:32 There's been a somewhat recent trend in what is known as reactive extensions. 0:34 RxJava is the Java flavored version. 0:38 Reactive extensions make use of the Observer pattern combined 0:41 with the the Iterator pattern to deal with strands of data and events. 0:44 It's everywhere these days. 0:47 But I wanted to warn you that there's a bit of a namespace collision 0:49 around a term that we are about ready to use. 0:52 That term is observable. 0:55 The observable from the reactive extensions world 0:57 is different than what we're going to be exploring. 1:00 Check out the teacher's notes for more and 1:02 just know that they are two different things. 1:04 Ready? 1:07 Let's dive in. 1:07 All right, so in java.util there is a class named Observable, and 1:10 this is what we're going to use to mark our subjects. 1:15 So in our case, the staff and 1:17 the dashboard are observing changes to the table. 1:19 So the table is the subject. 1:22 So let's go ahead and let's pop open the table. 1:25 And what we'll do is we'll have it extend that Observable class. 1:29 So we'll say extends Observable. 1:32 Now we have all of the methods available to us from Observable. 1:37 Now, basically, we have now exposed the ability to have Observer subscribe and 1:40 have added the ability to notify them when things change. 1:46 While we're in here, why don't we set up what it is that we want to broadcast? 1:49 So we're interested when the status changes, right. 1:54 So let's go to that status setter here. 1:57 We'll come in here, so status newStatus, and 2:00 what we'll do is we'll notify the observers. 2:04 So let's say notify, and see, it's now part of this, Observers. 2:08 Now this notifyObservers takes an optional argument, which can be anything at all. 2:12 Now, the parameter is used to narrow the focus of 2:17 what it was specifically that was changed. 2:20 So in our case, it probably makes sense for us to push the status through. 2:23 You don't have to do this. 2:27 This is a totally fine call. 2:28 Let's do it anyway, though. 2:29 So let's say, we'll pass through the new status that got set. 2:30 Now, there is one thing that we need to remember to do when we're 2:34 using the Observable class. 2:37 And pay close attention here, because this will for sure bite you. 2:39 So the way that notifyObservers works is it will 2:42 only send out notifications only if it's been told that changes were made. 2:46 Now, this allows you to make sure that you can control when your observers 2:52 are notified. 2:56 You must call setChanged, and you need to do it before the notifyObservers happens. 2:57 So it's called setChanged. 3:04 So what that does is that it lets it know that things changed. 3:06 So after the notification happens, the state will turn back to unchanged. 3:09 So you can also check that by using a method called hasChanged. 3:15 Now, I'm not gonna add any protection here, 3:19 as I want any tweak in our status to trigger events, right? 3:21 So what do you say we look at how to create an observer to observe changes to 3:24 our table. 3:29 Okay, so let's go ahead and we'll tackle this first issue here, right? 3:30 The staff will not like needing to refresh the desk dashboard, right. 3:33 So let's do that. Let's go over to the dashboard. 3:37 So let's open it up, we'll go Shift Shift dashboard. 3:39 And what we'll do is we'll have the Dashboard implement 3:42 the Observer interface, also in java.util. 3:47 Now, immediately, we'll see a squiggly, 3:51 because the interface has a required method, which if we go ahead and 3:54 try to see what it's angry about, it'll ask us to implement it. 3:59 So implement methods. 4:04 And it's one named update, and it takes an Observable and an Object. 4:06 So this is a method that is called from within that notifyObservers method 4:14 on the other side, right. 4:19 So as you can see, it's passed an Observable, which it's called o here. 4:20 And the second parameter arg is an object. 4:26 So in our case that would be the status object that we passed across, or 4:29 it's null in most cases. 4:32 So the idea here is, in this update method, it's where you add the code that 4:34 will respond to the change in the class that this will eventually observe. 4:39 That make sense? 4:43 So what do we want the dashboard to do when a specific table changes? 4:44 Well, ideally and 4:49 probably realistically, we'd update that single table in the dashboard. 4:50 But we don't have a way to do that right now. 4:55 So let's just go ahead and call the render method, right? 4:57 So if I put in here, say, render. 5:00 Now any time a table changes, the dashboard will update automatically. 5:03 Well, that is, of course, if we're observing it. 5:08 So let's go take a look at our simulator, 5:11 the main method here, and take a look at what's happening. 5:14 First of all, we can get rid of this refreshDashboard, right? 5:18 Before, the server was having to do it, and the assistant was having to do it. 5:21 So we'll remove this. 5:26 There's no more dashboard refresh. 5:28 It looks like most of this is actually gonna start going away here pretty 5:30 soon, right? 5:33 Really what we want, is we want for each table, 5:35 we'll make the dashboard observe it. 5:38 And there's a method that was added by the Observable superclass named addObserver. 5:40 Our tables have that. 5:45 So let's go ahead and let's, right after we go here, 5:47 let's do tables.forEach, 5:52 for each table, we'll add 5:57 the observer of dashboard. 6:01 There we go. 6:08 Now the dashboard is watching all the tables, and when the table state changes, 6:09 it will notify all of its observers and the dashboard will render. 6:14 Nice. So 6:21 I'm pretty sure we can remove this concern, right? 6:21 The staff will not liking needing to refresh it, so 6:24 we'll automatically refresh now. 6:26 Awesome. 6:27 Okay, let's see if we can't take care of this next one. 6:29 The servers should be assigned to a table. 6:31 Well, now that we know about addObserver, 6:34 it seems like we just need to have them observe specific tables, right? 6:36 You know what, let's do that for server. 6:41 Let's go ahead and let's come over here to the simulator, 6:43 and let's cut this logic for the server out of the main loop here, right. 6:49 So we're gonna grab, these two cases are both server-based, right, so, 6:54 they're gonna not be in here, server-based solution there. 7:00 Okay, and now let's open up server. 7:05 So I'm just gonna do Shift Shift server. 7:07 And we'll make this server implement the observer. 7:12 Now, wait a second, all employees should be able to observe a table. 7:16 So let's do that, let's make the employee actually implement the observer. 7:21 So we'll say implements Observer. 7:26 And you'll notice that we don't get a squiggly, and 7:30 that's because it's abstract. 7:33 So it's not required to be there yet. 7:35 But if we come back to our server, 7:37 now our server needs to have the observer method there. 7:38 So let's go ahead and implement the methods, and we'll do the update. 7:42 And I have in my clipboard, I pasted that original. 7:48 I pasted it at the wrong place. 7:58 There we go, so we'll paste. 8:01 All right. 8:03 So we will do, first I'm gonna clean up this little bit. 8:05 Get rid of all of this optional stuff here. 8:15 So if it's available, we'll do a leadToTable and we'll break. 8:17 And if it's finished, we'll just close out the table. 8:24 And it's complaining about not knowing what the table is. 8:29 So we need to define that, don't we? 8:32 We also need to define the switch bit here. 8:35 So we definitely need to access the table, right? 8:38 So what can we do? 8:41 So we can say table, and remember, it's passed in through that observable there. 8:42 But it is an observable, so we need to do a downcast to the table. 8:47 Yuck, right? 8:53 And now let's go ahead and add that switch statement, now that we have that. 8:56 So we'll say switch, and we'll do table.getStatus. 9:00 And in here, we'll add our case statements that we had from before. 9:07 Tab that in once there. 9:13 There, that's looking a lot better. 9:15 Okay, so if the table's available, we'll view the table, 9:18 otherwise we'll finish on that. 9:20 Cool. 9:23 Okay, and now, we know how to assign these tables, right, we just assign them, right? 9:25 So we add observers to those tables. 9:29 So let's come in, and why don't we move our observer stuff down below. 9:31 So let's move all the stuff where we started doing the observers down here. 9:38 And so let's just for each table, we'll say, 9:42 table1.addObserver, and we'll have Alice watch the first three. 9:46 That sound good? 9:52 So we'll say, Alice, 2, 3. 9:53 And then let's for 4 and 5, let's have Bob watch those. 9:57 So Alice and Bob all both servers. 10:02 So Bob's got 4 and 5, and Alice only has 1 and 2. 10:05 So now they shouldn't pick up each other's checks, right? 10:09 That's what the client was concerned about here. 10:13 So let's flip over, server should be assigned to a table, bam. 10:17 All right, so why don't we take a quick break, 10:23 this has been going on for a little bit. 10:25 And we'll return and fix up the assistant to use the pattern as well. 10:26 You know, why don't you try to then tackle the assistant, right? 10:31 Try to make that assistant observable. 10:34 And then tune back in and check out how I did it. 10:36 You got this. 10:38
You need to sign up for Treehouse in order to download course files.Sign up