Wrapping Up the Out of the Box Observer Pattern10:15 with Craig Dennis
Let's finish up our simulation improvements by adding a new tool that observes tables, the restaurant pager!
Additional possible pitfalls
- Careful of the state being stale see the Specific Implementation Problems section.
How did you do? 0:00 This is how I solved the problem. 0:01 So, if we look in the main loop here, we're gonna kill this bus table, right? 0:02 So I'm just gonna copy this part of it and I'm gonna get rid of the rest of this. 0:07 This whole switch here, let's get rid of that. 0:11 And I'm gonna flip over to the assistant. 0:14 And in here, it's complaining so implement the methods. 0:18 And I'm gonna pull out right away. 0:23 I'm gonna pull out that table. 0:25 Just like before, we'll do that downcast to a table. 0:30 And we know that if the status of the table, 0:34 if the status needs busing, we're gonna bus that table. 0:39 There we go. 0:49 Now, one thing to note is I'm not using the arg that was passed in, 0:51 even though it is status. 0:54 When update methods on observers cause other observers to be notified, 0:55 you end up in this weird nested state. 0:59 And it can happen if things get out of sync. 1:01 So be cautious of using that value as it could be 1:03 a stale representation of the actual truth. 1:06 Now that's why I'm always using the table. 1:09 We'll explore that here in a little bit. 1:11 Check the teacher's notes for more. 1:13 Okay, so now let's go make sure that those assistants are watching the tables 1:15 alongside the others. 1:19 So, in here, we can go ahead and we've got Charlie, so 1:21 let's pair up Charlie with Alice here. 1:26 So let's say, Charlie, Charlie, Charlie. 1:29 And then for Bob, we'll have Bob and Darla work together. 1:36 That should make things a little bit more even as well, 1:42 like we were seeing, Charlie was getting all the other work before. 1:45 Okay, so this loop is now nothing but silliness, right? 1:50 So let's go ahead, let's remove that. 1:54 So what we wanna do is, 1:57 right before we start now is we wanna kick off all those observers. 1:59 And one way to do that is by just setting the state. 2:03 And at the start of the day, the tables are gonna be available, right? 2:06 So we can just say, table.setStatus, and 2:09 we'll set it to status available, there we go. 2:12 So we'll loop through each one of them, set it to available and 2:16 then we want time to pass. 2:19 We still want to give them enough time, so let's just past 30 seconds. 2:20 And since everything else is gonna be running in it's own thread, 2:23 that should be enough to get all the observers to work. 2:26 So, you know what though, 2:29 we should make sure that we remove the observers when the shift is over, right? 2:31 You can remove observers one by one, 2:35 by passing in the specific observer that you'd like to remove. 2:37 Or you can just remove them all, so I think that sounds like the right answer. 2:40 So each one of our tables has an observer. 2:44 So we'll say, tables for each, forEach and hold path, we get a table. 2:47 And we'll say, table.deleteObservers, because there could be multiple observers. 2:54 In fact, there are, they got the dashboard. 2:57 After I delete observers, and 2:59 the dashboard now we have all the employees are watching the table, so. 3:02 Wow, that's looking good. 3:09 Now everything is rewritten and we close out almost all the issues. 3:10 We should probably try a test run before we get ahead of ourselves. 3:14 So let's go back up here and we'll choose run simulator.main. 3:16 Nice. 3:21 So it's going, the dashboard refreshing all the time by itself. 3:23 Quite a lot of refreshes, but that's okay. 3:28 No one's having to do that. 3:31 Alice is saying, here's your menus for five. 3:33 Look like the tables, just by the fact of getting that switch taken out, 3:35 looks like the tables are getting finished and occupied, and 3:39 the bills are getting paid more. 3:42 So the availability problem is taken care of for sure. 3:43 Looks like that was a really nice way to get things to work, right? 3:48 So, let's go and let's close out this ticket. 3:53 Probably see the favor availability of the guests. 3:57 And we have the show pager opportunity, 4:00 this is what the pager was that I was talking about. 4:02 Before we get there though, let's talk about it. 4:05 The things in this script are only loosely coupled, right? 4:06 We can change the implementation of what happens in this code in the main here, 4:12 this wouldn't change much, right? 4:16 Like this is probably just normal set up here. 4:17 And probably that would be done dynamically like this is kind of the whole 4:20 body of everything. 4:23 That's pretty cool, right? 4:25 The table isn't in the know about what is happening anymore and that's great, right? 4:27 It doesn't need to be. 4:31 Okay. So let's get back to that pager. 4:33 So remember this pager just kind of just buzzes when the tables are ready. 4:35 And it's gonna be a brand new type of observer. 4:39 So, we should be able to knock that out pretty quick, right? 4:41 The pager can observe the table and when it's available, we'll make it buzz. 4:44 Seems pretty straight forward in the style, doesn't it? 4:50 So let's see, that's the tool. 4:53 So let's just add a new tool. 4:56 Let's go in our project here, in our project and if we scroll over 4:58 here to tools, make a new Java class and we'll call it, Pager. 5:03 And I wanna go ahead and get full screen on this. 5:11 Let's go ahead and have it implement the observer. 5:17 Right away implement that missing method. 5:25 So in this case, now, I just wanna show off what it might look like. 5:30 Why don't we use the arg parameter here. 5:34 So remember the arg was the status that was pushed in, and 5:36 so what do we say, we said? 5:39 So it's a status, and we'll pull in status, and 5:42 we'll make this be a status, and again we're down casting, right? 5:45 Cuz they're objects. 5:50 And that's the right status. 5:52 And we wanted to say, if the status is equal to Status.AVAILABLE, 5:55 that's when we want it to buzz, right? 6:01 So here we'll just print out really quick, 6:05 BUZZZZZ, and we'll say table, number is ready, 6:10 given you Y, you know what? 6:16 I mean, first of all, we need to make this a printf, so 6:21 that we can pass in a format string and we need to get a hold of the table anyway. 6:24 So, we'll do that. 6:29 Pull the table out from this observable here. 6:32 And we'll say table.getPosition, no, don't want to get number of seats. 6:44 I wanna do getPosition number. 6:50 I want that to happen so that, 6:51 just we know it's clear when the buzzer is buzzing, here is what it's gonna do. 6:53 So, in this situation, a pager really shouldn't exist without a table, right? 6:57 So, why don't we make a constructor that accepts, 7:04 only way to create one of these is by passing the table, right? 7:08 It will always be assigned to a table, but I am gonna hijack our pager example here, 7:13 just to show you a little something that you should be aware of. 7:17 Since we're not gonna keep a reference at all to this table. 7:20 What we'll do, is add an observer to ourselves, right? 7:23 So, the tables passed in and the table is an observable. 7:26 So, we're gonna say table.addObserver, and we're gonna say this. 7:30 So back on our simulator here. 7:35 Now, when we are looping through these tables, let's go ahead and 7:37 let's make a pager for each of them, and then the hostess can have this. 7:41 So let's say for each table. 7:46 And now here's what we're gonna do. 7:48 Is we're gonna make this a brand new pager inside of a loop here, right? 7:50 So we're not going to have a reference at all when the page was created. 7:54 It's just gonna get created. 7:59 Now, because in the constructor we observe the table, it's gonna live on. 8:00 Now, the reason for 8:05 that is because the table holds an object reference in its observers list. 8:06 What that means is, it will never get garbage collected. 8:10 And the only way that we can get rid of it is by using that deleteObservers 8:13 method, right? 8:18 The only way to get rid of that pager is we're going to have to delete 8:18 all observers. 8:21 Now, this could potentially cause a memory leak, as you can imagine, 8:22 there could be a lot of observers that we never remove. 8:25 Don't forget to remove them. 8:28 All right, ready? 8:30 Let's do this, let's see how our pages are doing. 8:31 Let's take a look up here, there is some serious buzzing happening around, 8:35 the being one, two, three, four, [SOUND] awesome. 8:39 And they're finding the patrons and when the patrons are ready, and 8:41 they've been back, the thing should buzz again. 8:45 So there's should be a buzz in here, someplace. 8:48 There's another buzz, there we go, buzz number table four is ready. 8:53 So, guess what? 8:57 Our client is so excited, loves it and he wants even more, 8:59 he wants to buy more stuff from us. 9:02 This is amazing. 9:04 So it's a good thing that we can easily add and remove tools, right? 9:05 What are your opinions on the out of the box Java util observable observer 9:09 solution? 9:14 Then make sure to share your thoughts with the community. 9:14 So the loudest complaint about the observable class 9:17 is that it is in fact a class. 9:19 Now, that's fairly unusual in the JTK, and 9:22 due to the single inheritance nature of this language. 9:25 It makes the implementation somewhat tricky. 9:27 It also limits the ability to make your own, 9:30 since there's no interface to find just the class. 9:32 And several of the methods actually have protected access, so 9:35 you couldn't even override them if you try. 9:38 Secondly, the method that is required to be added by implementors of the observer 9:41 interface. 9:45 Which happens to be the unfortunately ambiguously named update, 9:45 takes two parameters that are objects. 9:50 So that means there's always downcasting happening. 9:53 Now remember, this original code was written before generics were available. 9:55 So, these two big complaints lead to a lot of people writing their own 9:59 implementations. 10:03 And when you have a fairly controlled set of objects attempting to perform 10:04 this pattern. 10:08 Well, sometimes, it does just make more sense to craft your own. 10:08 In fact, why don't we do that right after this quick break. 10:12
You need to sign up for Treehouse in order to download course files.Sign up