Head First Design Patterns PDF

Document Details

ParamountHydra

Uploaded by ParamountHydra

Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates

Tags

design patterns software design object-oriented programming computer science

Summary

This book introduces design patterns for software development. Head First Design Patterns is intended for learning design patterns. It uses an engaging approach to explain complex concepts in a fun, easy-to-understand way. The book covers various design patterns and their practical applications.

Full Transcript

Download at WoweBook.Com Praise for Head First Design Patterns “I received the book yesterday and started to read it on the way home... and I couldn’t stop. I took it to the gym and I expect people saw me smiling a lot while I was exercising and reading. This is tres ‘cool’. It is fun but they c...

Download at WoweBook.Com Praise for Head First Design Patterns “I received the book yesterday and started to read it on the way home... and I couldn’t stop. I took it to the gym and I expect people saw me smiling a lot while I was exercising and reading. This is tres ‘cool’. It is fun but they cover a lot of ground and they are right to the point. I’m really impressed.” — Erich Gamma, IBM Distinguished Engineer, and co-author of Design Patterns “‘Head First Design Patterns’ manages to mix fun, belly-laughs, insight, technical depth and great practical advice in one entertaining and thought provoking read. Whether you are new to design patterns, or have been using them for years, you are sure to get something from visiting Objectville.” — Richard Helm, coauthor of “Design Patterns” with rest of the Gang of Four - Erich Gamma, Ralph Johnson and John Vlissides “I feel like a thousand pounds of books have just been lifted off of my head.” — Ward Cunningham, inventor of the Wiki and founder of the Hillside Group “This book is close to perfect, because of the way it combines expertise and readability. It speaks with authority and it reads beautifully. It’s one of the very few software books I’ve ever read that strikes me as indispensable. (I’d put maybe 10 books in this category, at the outside.)” — David Gelernter, Professor of Computer Science, Yale University and author of “Mirror Worlds” and “Machine Beauty” “A Nose Dive into the realm of patterns, a land where complex things become simple, but where simple things can also become complex. I can think of no better tour guides than the Freemans.” — Miko Matsumura, Industry Analyst, The Middleware Company Former Chief Java Evangelist, Sun Microsystems “I laughed, I cried, it moved me.” — Daniel Steinberg, Editor-in-Chief, java.net “My first reaction was to roll on the floor laughing. After I picked myself up, I realized that not only is the book technically accurate, it is the easiest to understand introduction to design patterns that I have seen.” — Dr. Timothy A. Budd, Associate Professor of Computer Science at Oregon State University and author of more than a dozen books, including “C++ for Java Programmers” “Jerry Rice runs patterns better than any receiver in the NFL, but the Freemans have out run him. Seriously...this is one of the funniest and smartest books on software design I’ve ever read.” — Aaron LaBerge, VP Technology, ESPN.com Download at WoweBook.Com More Praise for Head First Design Patterns “Great code design is, first and foremost, great information design. A code designer is teaching a com- puter how to do something, and it is no surprise that a great teacher of computers should turn out to be a great teacher of programmers. This book’s admirable clarity, humor and substantial doses of clever make it the sort of book that helps even non-programmers think well about problem-solving.” — Cory Doctorow, co-editor of Boing Boing and author of “Down and Out in the Magic Kingdom” and “Someone Comes to Town, Someone Leaves Town” “There’s an old saying in the computer and videogame business – well, it can’t be that old because the discipline is not all that old – and it goes something like this: Design is Life. What’s particularly curious about this phrase is that even today almost no one who works at the craft of creating electronic games can agree on what it means to “design” a game. Is the designer a software engineer? An art director? A storyteller? An architect or a builder? A pitch person or a visionary? Can an individual indeed be in part all of these? And most importantly, who the %$!#&* cares? It has been said that the “designed by” credit in interactive entertainment is akin to the “directed by” credit in filmmaking, which in fact allows it to share DNA with perhaps the single most controversial, overstated, and too often entirely lacking in humility credit grab ever propagated on commercial art. Good company, eh? Yet if Design is Life, then perhaps it is time we spent some quality cycles thinking about what it is. Eric and Elisabeth Freeman have intrepidly volunteered to look behind the code curtain for us in “Head First Design Patterns.” I’m not sure either of them cares all that much about the PlayStation or X-Box, nor should they. Yet they do address the notion of design at a significantly honest level such that anyone looking for ego reinforcement of his or her own brilliant auteurship is best advised not to go digging here where truth is stunningly revealed. Sophists and circus barkers need not apply. Next generation literati please come equipped with a pencil.” — Ken Goldstein, Executive Vice President & Managing Director, Disney Online “Just the right tone for the geeked-out, casual-cool guru coder in all of us. The right reference for practical development strategies—gets my brain going without having to slog through a bunch of tired, stale professor-speak.” — Travis Kalanick, Founder of Scour and Red Swoosh Member of the MIT TR100 “This book combines good humors, great examples, and in-depth knowledge of Design Patterns in such a way that makes learning fun. Being in the entertainment technology industry, I am intrigued by the Hollywood Principle and the home theater Facade Pattern, to name a few. The understanding of Design Patterns not only helps us create reusable and maintainable quality software, but also helps sharpen our problem-solving skills across all problem domains. This book is a must read for all com- puter professionals and students.” — Newton Lee, Founder and Editor-in-Chief, Association for Computing Machinery’s (ACM) Computers in Entertainment (acmcie.org) Download at WoweBook.Com More Praise for Head First Design Patterns “If there’s one subject that needs to be taught better, needs to be more fun to learn, it’s design patterns. Thank goodness for Head First Design Patterns. From the awesome Head First Java folks, this book uses every conceivable trick to help you understand and remember. Not just loads of pictures: pictures of humans, which tend to interest other humans. Surprises everywhere. Stories, because humans love narrative. (Stories about things like pizza and chocolate. Need we say more?) Plus, it’s darned funny. It also covers an enormous swath of concepts and techniques, including nearly all the patterns you’ll use most (observer, decorator, factory, singleton, command, adapter, façade, template method, iterator, composite, state, proxy). Read it, and those won’t be ‘just words’: they’ll be memories that tickle you, and tools you own.” — Bill Camarda, READ ONLY “After using Head First Java to teach our freshman how to start programming, I was eagerly waiting to see the next book in the series. Head First Design Patterns is that book and I am delighted. I am sure it will quickly become the standard first design patterns book to read, and is already the book I am recommending to students.” — Ben Bederson, Associate Professor of Computer Science & Director of the Human-Computer Interaction Lab, University of Maryland “Usually when reading through a book or article on design patterns I’d have to occasionally stick myself in the eye with something just to make sure I was paying attention. Not with this book. Odd as it may sound, this book makes learning about design patterns fun. While other books on design patterns are saying, ‘Buehler... Buehler... Buehler...’ this book is on the float belting out ‘Shake it up, baby!’” — Eric Wuehler “I literally love this book. In fact, I kissed this book in front of my wife.” — Satish Kumar Praise for the Head First approach “Java technology is everywhere—in mobile phones, cars, cameras, printers, games, PDAs, ATMs, smart cards, gas pumps, sports stadiums, medical devices, Web cams, servers, you name it. If you develop software and haven’t learned Java, it’s definitely time to dive in—Head First.” — Scott McNealy, Sun Microsystems Chairman, President and CEO “It’s fast, irreverent, fun, and engaging. Be careful—you might actually learn something!” — Ken Arnold, former Senior Engineer at Sun Microsystems Co-author (with James Gosling, creator of Java), “The Java Programming Language” Download at WoweBook.Com Other related books from O’Reilly Learning Java Java in a Nutshell Java Enterprise in a Nutshell Java Examples in a Nutshell Java Cookbook J2EE Design Patterns Other books in O'Reilly's Head First series Head First Java Head First EJB Head First Servlets & JSP Head First Object-Oriented Analysis & Design Head First HTML with CSS & XHTML Head Rush Ajax Head First PMP Head First SQL (2007) Head First C# (2007) Head First Software Development (2007) Head First JavaScript (2007) Be watching for more books in the Head First series! Download at WoweBook.Com Head First Design Patterns Wouldn’t it be dreamy if there was a Design Patterns book that was more fun than going to the dentist, and more revealing than an IRS form? It’s probably just a fantasy... Eric Freeman Elisabeth Freeman with Kathy Sierra Bert Bates Beijing Cambridge Köln Paris Sebastopol Taipei Tokyo Download at WoweBook.Com +HDG)LUVW'HVLJQ3DWWHUQV Ja-ZQK.ZMMUIV-TQ[IJM\P.ZMMUIV3I\Pa;QMZZIIVL*MZ\*I\M[ +WXaZQOP\7¼:MQTTa5MLQI1VK)TTZQOP\[ZM[MZ^ML 8ZQV\MLQV\PM=VQ\ML;\I\M[WN )UMZQKI 8]JTQ[PMLJa7¼:MQTTa5MLQI1VK/ZI^MV[\MQV0QOP_Ia6WZ\P;MJI[\WXWT+)! 7¼:MQTTa5MLQIJWWS[UIaJMX]ZKPI[MLNWZML]KI\QWVITJ][QVM[[WZ[ITM[XZWUW\QWVIT][M7VTQVMMLQ\QWV[IZM IT[WI^IQTIJTMNWZUW[\\Q\TM[[INIZQWZMQTTaKWU.WZUWZMQVNWZUI\QWVKWV\IK\W]ZKWZXWZI\MQV[\Q\]\QWVIT[ITM[ LMXIZ\UMV\" !! !! WZKWZXWZI\M(WZMQTTaKWU (GLWRU 5QSM4W]SQLM[ &RYHU'HVLJQHU -TTQM>WTKSPI][MV 3DWWHUQ:UDQJOHUV -ZQK.ZMMUIV-TQ[IJM\P.ZMMUIV )DFDGH'HFRUDWLRQ -TQ[IJM\P.ZMMUIV 6WUDWHJ\ 3I\Pa;QMZZIIVL*MZ\*I\M[ 2EVHUYHU 7TQ^MZ 3ULQWLQJ+LVWRU\ 7K\WJMZ".QZ[\-LQ\QWV QM_IXX 6WL]KS[_MZMPIZUMLQV\PMUISQVOWN \PQ[JWWS = items.length || items[position] == null) { return false; } else { return true; } } Because the diner chef went ahead and } The hasNext() method checks to allocated a max sized array, we need to see if we’ve seen all the elements check not only if we are at the end of of the array and returns true if the array, but also if the next item is there are more to iterate through. null, which indicates there are no more items. 326 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Reworking the Diner Menu with Iterator Okay, we’ve got the iterator. Time to work it into the DinerMenu; all we need to do is add one method to create a DinerMenuIterator and return it to the client: public class DinerMenu {implements Menu { static final int MAX_ITEMS = 6; int numberOfItems = 0; MenuItem[] menuItems; // constructor here We’re not going to need the getMenuItems() method anymore and in fact, we don’t want it // addItem here public MenuItem[] getMenuItems() { because it exposes our internal implementation! return menuItems; } public Iterator createIterator() { return new DinerMenuIterator(menuItems); } Here’s the createIterator() method. It creates a DinerMenuIterator // other menu methods here from the menuItems array and } returns it to the client. We’re returning the Iterator interface. The client doesn’t need to know how the menuItems are maintained in the DinerMenu, nor does it need to know how the DinerMenuIterator is implemented. It just needs to use the iterators to step through the items in the menu. Exercise Go ahead and implement the PancakeHouseIterator yourself and make the changes needed to incorporate it into the PancakeHouseMenu. you are here 4 327 Download at WoweBook.Com the waitress iterates Fixing up the Waitress code Now we need to integrate the iterator code into the Waitress. We should be able to get rid of some of the redundancy in the process. Integration is pretty straightforward: first we create a printMenu() method that takes an Iterator, then we use the createIterator() method on each menu to retrieve the Iterator and pass it New and improved to the new method. with Iterator. public class Waitress { PancakeHouseMenu pancakeHouseMenu; In the constructor the Waitress DinerMenu dinerMenu; takes the two menus. public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) { The printMenu() this.pancakeHouseMenu = pancakeHouseMenu; this.dinerMenu = dinerMenu; } method now creates two public void printMenu() { iterators, one for Iterator pancakeIterator = pancakeHouseMenu.createIterator(); each menu. Iterator dinerIterator = dinerMenu.createIterator(); System.out.println(“MENU\n----\nBREAKFAST”); printMenu(pancakeIterator); And then calls the System.out.println(“\nLUNCH”); overloaded printMenu() printMenu(dinerIterator); with each iterator. } Test if there are The overloaded private void printMenu(Iterator iterator) { any more items. printMenu() while (iterator.hasNext()) { MenuItem menuItem = (MenuItem)iterator.next(); Get the method uses System.out.print(menuItem.getName() + “, “); next item. the Iterator to System.out.print(menuItem.getPrice() + “ -- “); step through the System.out.println(menuItem.getDescription()); menu items and } print them. } Use the item to // other methods here Note that we’re down get name, price } to one loop. and description and print them. 328 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Testing our code It’s time to put everything to a test. Let’s write some test drive code and see how the Waitress works... First we create the new menus. public class MenuTestDrive { public static void main(String args[]) { PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); DinerMenu dinerMenu = new DinerMenu(); Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu); Then we create a Waitress and pass waitress.printMenu(); her the menus. } } Then we print them. Here’s the test run... File Edit Window Help GreenEggs&Ham % java DinerMenuTestDrive First we iterate MENU through the pancake ---- menu. BREAKFAST And then K&B’s Pancake Breakfast, 2.99 -- Pancakes with scrambled eggs, and toast the lunch Regular Pancake Breakfast, 2.99 -- Pancakes with fried eggs, sausage Blueberry Pancakes, 3.49 -- Pancakes made with fresh blueberries menu, all Waffles, 3.59 -- Waffles, with your choice of blueberries or strawberries with the same LUNCH iteration Vegetarian BLT, 2.99 -- (Fakin’) Bacon with lettuce & tomato on whole wheat code. BLT, 2.99 -- Bacon with lettuce & tomato on whole wheat Soup of the day, 3.29 -- Soup of the day, with a side of potato salad Hotdog, 3.05 -- A hot dog, with saurkraut, relish, onions, topped with cheese Steamed Veggies and Brown Rice, 3.99 -- Steamed vegetables over brown rice Pasta, 3.89 -- Spaghetti with Marinara Sauce, and a slice of sourdough bread % you are here 4 329 Download at WoweBook.Com iterator advantages What have we done so far? Woohoo! No code changes other than adding the For starters, we’ve made our Objectville cooks createIterator() method. very happy. They settled their differences and kept their own implementations. Once we gave them a PancakeHouseMenuIterator and a DinerMenuIterator, all they had to do was add a createIterator() method and they were finished. We’ve also helped ourselves in the process. The Waitress will be much easier to maintain and extend down the road. Let’s go through exactly what we did and think about the consequences: Veggie burger Hard to Maintain New, Hip Waitress Implementation Waitress Powered by Iterator The Menus are not well The Menu implementations are now encapsulated; we can see the Diner encapsulated. The Waitress has is using an Array and the Pancake no idea how the Menus hold their House an ArrayList. collection of menu items. We need two loops to iterate through All we need is a loop that the MenuItems. polymorphically handles any collection of items as long as it implements Iterator. The Waitress is bound to concrete The Waitress now uses an interface classes (MenuItem[] and ArrayList). (Iterator). The Waitress is bound to two different The Menu interfaces are now exactly concrete Menu classes, despite their the same and, uh oh, we still don’t interfaces being almost identical. have a common interface, which means the Waitress is still bound to two concrete Menu classes. We’d better fix that. 330 Chapter 9 Download at WoweBook.Com the iterator and composite patterns What we have so far... Before we clean things up, let’s get a bird’s eye view of our current design. We’re now ment the The Iterator allows the Waitress to be decoupled These two menus implethods, but from the actual implementation of the concrete using a common same exact set of me the same classes. She doesn’t need to know if a Menu is Iterator they aren’t implementingto fix this implemented with an Array, an ArrayList, or with interface Interface. We’re going from any PostIt™ notes. All she cares is that she can get an and we’ve and free the Waitress te Menus. Iterator to do her iterating. implemented dependencies on concre two concrete classes. PancakeHouseMenu Waitress Iterator menuItems printMenu() hasNext() createIterator() next() DinerMenu menuItems createIterator() PancakeHouseMenuIterator DinerMenuIterator hasNext() hasNext() next() next() ement Note that the iterator give us a way to step nc ak eH ou se M en u and DinerMenu impl are Pa ator() method; they through the elements of an aggregate with out the new createIter ting the iterator for their forcing the aggregate to clutter its own inte responsible for crea s implementations. with a bunch of methods to support traversa rface respective menu item elements. It also allows the implementation l of its iterator to live outside of the aggregate; of the words, we’ve encapsulated the interation. in other you are here 4 331 Download at WoweBook.Com improve the iterator Making some improvements... Okay, we know the interfaces of PancakeHouseMenu and DinerMenu are exactly the same and yet we haven’t defined a common interface for them. So, we’re going to do that and clean up the Waitress a little more. You may be wondering why we’re not using the Java Iterator interface – we did that so you could see how to build an iterator from scratch. Now that we’ve done that, we’re going to switch to using the Java Iterator interface, because we’ll get a lot of leverage by implementing that instead of our home grown Iterator interface. What kind of leverage? You’ll soon see. First, let’s check out the java.util.Iterator interface: This looks just like our previous definition. Iterator hasNext() next() remove() Except we have an additional method that allows us to remove the last item returned by the next() method from the aggregate. This is going to be a piece of cake: We just need to change the interface that both PancakeHouseMenuIterator and DinerMenuIterator extend, right? Almost... actually, it’s even easier than that. Not only does java.util have its own Iterator interface, but ArrayList has an iterator() method that returns an iterator. In other words, we never needed to implement our own iterator for ArrayList. However, we’ll still need our implementation for the DinerMenu because it relies on an Array, which doesn’t support the iterator() method (or any other way to create an array iterator). there are no Dumb Questions Q: What if I don’t want to provide Q: How does remove() behave the ability to remove something from the under multiple threads that may be underlying collection of objects? using different iterators over the same collection of objects? A: The remove() method is considered optional. You don’t have to provide remove the runtime exception java.lang.UnsupportedOperationException. A: The behavior of the remove() is The Iterator API documentation specifies that unspecified if the collection changes while functionality. But, obviously you do need to this exception may be thrown from remove() you are iterating over it. So you should be provide the method because it’s part of the and any client that is a good citizen will careful in designing your own multithreaded Iterator interface. If you’re not going to allow check for this exception when calling the code when accessing a collection remove() in your iterator you’llwant to throw remove() method. concurrently. 332 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Cleaning things up with java.util.Iterator Let’s start with the PancakeHouseMenu, changing it over to java.util.Iterator is going to be easy. We just delete the PancakeHouseMenuIterator class, add an import java.util.Iterator to the top of PancakeHouseMenu and change one line of the PancakeHouseMenu: public Iterator createIterator() { Instead of creating our own iterator return menuItems.iterator(); now, we just call the iterator() method } on the menuItems ArrayList. And that’s it, PancakeHouseMenu is done. Now we need to make the changes to allow the DinerMenu to work with java.util.Iterator. import java.util.Iterator; First we import java.util.Iterator, the interface we’re going to implement. public class DinerMenuIterator implements Iterator { MenuItem[] list; int position = 0; public DinerMenuIterator(MenuItem[] list) { this.list = list; } None of our current implementation changes... public Object next() { //implementation here }...but we do need to implement remove(). public boolean hasNext() { Here, because the chef is using a fixed //implementation here sized Array, we just shift all the } elements up one when remove() is called. public void remove() { if (position = items.length || items[position] == return false; } else { return true; } } 350 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Is the Waitress ready for prime time? The Waitress has come a long way, but you’ve gotta admit those three calls to printMenu() are looking kind of ugly. Let’s be real, every time we add a new menu we are going to have to open up the Waitress implementation and add more code. Can you say “violating the Open Closed Principle?” Three createIterator() calls. public void printMenu() { Iterator pancakeIterator = pancakeHouseMenu.createIterator(); Iterator dinerIterator = dinerMenu.createIterator(); Iterator cafeIterator = cafeMenu.createIterator(); System.out.println(“MENU\n----\nBREAKFAST”); printMenu(pancakeIterator); System.out.println(“\nLUNCH”); printMenu(dinerIterator); Three calls to printMenu. System.out.println(“\nDINNER”); printMenu(cafeIterator); } Everytime we add or remove a menu we’re going to have to open this code up for changes. It’s not the Waitress’ fault. We have done a great job of decoupling the menu implementation and extracting the iteration into an iterator. But we still are handling the menus with separate, independent objects – we need a way to manage them together. A brain power The Waitress still needs to make three calls to printMenu(), one for each menu. Can you think of a way to combine the menus so that only one call needs to be made? Or perhaps so that one Iterator is passed to the Waitress to iterate over all the menus? you are here 4 351 Download at WoweBook.Com a new design? This isn’t so bad, all we need to do is package the menus up into an ArrayList and then get its iterator to iterate through each Menu. The code in the Waitress is going to be simple and it will handle any number of menus. Sounds like the chef is on to something. Let’s give it a try: public class Waitress { Now we just take an ArrayList menus; ArrayList of menus. public Waitress(ArrayList menus) { this.menus = menus; } And we iterate public void printMenu() { through the Iterator menuIterator = menus.iterator(); menus, passing each while(menuIterator.hasNext()) { menu’s iterator Menu menu = (Menu)menuIterator.next(); to the overloaded printMenu(menu.createIterator()); printMenu() method. } } void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = (MenuItem)iterator.next(); No code System.out.print(menuItem.getName() + “, “); changes here. System.out.print(menuItem.getPrice() + “ -- “); System.out.println(menuItem.getDescription()); } } } This looks pretty good, although we’ve lost the names of the menus, but we could add the names to each menu. 352 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Just when we thought it was safe... Now they want to add a dessert submenu. I just heard the Okay, now what? Now we have to support not only multiple Diner is going to be menus, but menus within menus. creating a dessert menu that is going to be an insert into It would be nice if we could just make the dessert menu an their regular menu. element of the DinerMenu collection, but that won’t work as it is now implemented. What we want (something like this): All Menus nu nc Di e Ca Pa ake us ner nu Here’s our Arraylist eM Me feMenu Ho 1 2 3 that holds the menus of each restaurant. Café Menu Pancake Menu Diner Menu k ey Me nuItem Me nuItem Me nuItem Me nuItem Men uItem 1 Array k ey Me nuItem 1 2 3 4 Me nuItem 2 Me k ey Me nuItem Hashtable nuItem Dessert Menu k ey Men uItem ArrayList 3 Me nuItem 4 1 Men Me nuItem uItem 2 Me nuItem We need for Diner Menu to hold a submenu, but 3 we can’t actually assign a menu to a MenuItem Me nuItem array because the types are different, so this 4 isn’t going to work. Men uItem this k! We can’t assign a dessert menu to But ’t wor a MenuItem array. n wo Time for a change! you are here 4 353 Download at WoweBook.Com time to refactor What do we need? The time has come to make an executive decision to rework the chef ’s implementation into something that is general enough to work over all the menus (and now sub menus). That’s right, we’re going to tell the chefs that the time as come for us to reimplement their menus. The reality is that we’ve reached a level of complexity such that if we don’t rework the design now, we’re never going to have a design that can accommodate further acquisitions or submenus. So, what is it we really need out of our new design? ß We need some kind of a tree shaped structure that will accommodate menus, submenus and menu items. ß We need to make sure we maintain a way to traverse the items in each menu that is at least as convenient as what we are doing now with iterators. ß We may need to be able to traverse the items in a more flexible manner. For instance, we might need to iterate over only the Diner’s dessert menu, or we might need to iterate over the Diner’s entire There comes a time menu, including the dessert submenu. when we must refactor our code in order for it to grow. To not do so would leave us with rigid, inflexible code that has no hope of ever sprouting new life. 354 Chapter 9 Download at WoweBook.Com the iterator and composite patterns present Because we need to re s and menus, nested sub menuturally fit menu items, we can na ructure. All s them in a tree-like st Menu We need to accomodate Menus... e nu Din u er Men Pa ca M ke Hous Ca n fe Men... and sub menus... u e Me Me Me Me Me Me Me Me Me nuItem nuItem nuItem nuItem nuItem nuItem nuItem nuItem nuItem De nu ssert Me Me Me Me...and menu items. Me nuItem nuItem nuItem nuItem le We still need to be abems to traverse all th e it We also need to in the tree. traverse more f be able to instance over o lexibly, for All Menu s ne menu. e nu Din u er Men Pa ca De M nu ke Hous Ca n fe Men ssert Me u e Me Me Me Me Me Me Me Me Me nuItem nuItem nuItem nuItem nuItem nuItem nuItem nuItem nuItem De nu ssert Me Me Me Me Me nuItem nuItem nuItem nuItem Me Me Me Me nuItem nuItem nuItem nuItem A brain power How would you handle this new wrinkle to our design requirements? Think about it before turning the page. you are here 4 355 Download at WoweBook.Com composite pattern defined The Composite Pattern defined That’s right, we’re going to introduce another pattern Here’s a tree struct to solve this problem. We didn’t give up on Iterator – it ure will still be part of our solution – however, the problem of managing menus has taken on a new dimension that Elements with Iterator doesn’t solve. So, we’re going to step back and child elements solve it with the Composite Pattern. are called nodes. We’re not going to beat around the bush on this pattern, Node we’re going to go ahead and roll out the official definition now: L e af The Composite Pattern allows you to Leaf compose objects into tree structures to L eaf represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. Elements without children are called leaves. Let’s think about this in terms of our menus: this pattern gives us a way to create a tree structure that can handle a nested group of menus and menu items in the same structure. By putting menus and items in the same structure we create a part-whole hierarchy; that is, a tree of objects that is made of parts (menus and menu items) but that can be treated as a whole, like one big über menu. Once we have our über menu, we can use this pattern We can represent to treat “individual objects and compositions uniformly.” our Menu and What does that mean? It means if we have a tree structure MenuItems in a of menus, submenus, and perhaps subsubmenus along with tree structure. menu items, then any menu is a “composition” because Menu it can contain both other menus and menu items. The individual objects are just the menu items – they don’t hold other objects. As you’ll see, using a design that follows the Composite Pattern is going to allow us to write some simple Me nuIte m MenuIt em code that can apply the same operation (like printing!) over Me the entire menu structure. n u I te m Menus are nodes and MenuItems are leaves. 356 Chapter 9 Download at WoweBook.Com the iterator and composite patterns y We can create arbitraril complex trees. All Menu s Menus Submenu e nu Din u er Men Pa ca M ke Hous Ca n fe Men u e Me Me Me Me Me Me De Me nuItem Me nuItem Me nuItem The Composite Pattern allows us to build structures nuItem nuItem nuItem nuItem nuItem nuItem nu ssert Me MenuItems Me nuItem Me nuItem Me nuItem Me nuItem of objects in the form of trees that contain both ole... compositions of objects and And treat them as a wh individual objects as nodes. All Menu s Menus Submenu Using a composite structure, e nu we can apply the same Din u er Men Pa ca M ke Hous Ca n fe Men u e Me nuItem Me nuItem Me nuItem Me nuItem Me nuItem Me nuItem De Me nuItem Me nuItem Me nuItem operations over both nu ssert Me MenuItems composites and individual objects. In other words, in Me Me Me Me nuItem nuItem nuItem nuItem....or as parts. most cases we can ignore the differences between an be Operations che whole. print() compositions of objects and applied to t individual objects. All Menu s Menus Submenu e nu Din u er Men Pa ca M ke Hous Ca n fe Men u e Me Me Me Me Me Me Me Me Me nuItem nuItem nuItem nuItem nuItem nuItem nuItem nuItem nuItem De nu ssert Me MenuItems arts. print() Or the p Me Me Me Me nuItem nuItem nuItem nuItem you are here 4 357 Download at WoweBook.Com composite pattern class diagram fines an The Component de jects in interface for all obth the The Component may imple The Client uses the e to the composition: bo leaf nodes. default behavior for ad ment a Component interfaccts in the composite and the getChild() and its operatd(), remove(), ions. manipulate the obje composition. Client Component operation() add(Component) remove(Component) Note that the Leaf als inherits methods like ad o getChild(int) remove() and getChild(),d(), don’t necessarily make a which sense for a leaf node. Welot of going to come back to th ’re is issue. Leaf Composite operation() add(Component) site also remove(Component) A Leaf has no getChild(int) The Compo the Leaf- children. operation() implements erations. related op some of Note that not make A Leaf defines the behavior for the these may Composite, elements in the composition. It does is to defi ne sense on a case an this by implementing the operations The Composit e’s role so in that might be the com pone nts the Composite supports. behavior of stor e child exception having child ren and to generated. components. there are no Q: Component, Composite, Trees? Dumb Questions I’m confused. When you organize data in this way you end A: Remember, we’re taking a new approach. We’re going to re-implement the A: up with a tree structure (actually an upside down tree structure) with a composite at the menus with a new solution: the Composite A composite contains components. Pattern. So don’t look for some magical Components come in two flavors: root and branches of composites growing up to leaf nodes. transformation from an iterator to a composites and leaf elements. Sound composite. That said, the two work very recursive? It is. A composite holds a set of children, those children may be other composites or leaf elements. Q: How does this relate to iterators? nicely together. You’ll soon see that we can use iterators in a couple of ways in the composite implementation. 358 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Designing Menus with Composite So, how do we apply the Composite Pattern to our menus? To start with, we need to create a component interface; this acts as the common interface for both menus and menu items and allows us to treat them uniformly. In other words we can call the same method on menus or menu items. Now, it may not make sense to call some of the methods on a menu item or a menu, but we can deal with that, and we will in just a moment. But for now, let’s take a look at a sketch of how the menus are going to fit into a Composite Pattern structure: MenuComponent represents the interface for he both MenuItem and Menu. We’ve used an abstract a it r e ss is g oing to use t access class here because we want to provide default The W ent interfac e to MenuCompon and MenuItems. implementations for these methods. both Menus Waitress MenuComponent getName() getDescription() We have some of the getPrice() same methods you’ll isVegetarian() remember from our print() previous versions of add(Component) MenuItem and Menu, and we’ve added print(), remove(Component) Here are the methods for getChild(int) add(), remove() and manipulating the components. getChild(). We’ll describe The components are these soon, when we MenuItem and Menu. implement our new Menu and MenuItem classes. Both MenuItem and Men MenuItem Menu override print(). us getName() menuComponents getDescription() getName() getPrice() getDescription() isVegetarian() print() print() add(Component) remove(Component) getChild(int) MenuItem overrides the me sense, and uses the default thods that make ds that make Menu also overrides the methoremove menu items MenuComponent for those implementations in sense, like a way to add and sense (like add() - it doesnthat don’t make nuComponents. (or other menus!) from its meName() and add a component to a M ’t make sense to In addition, we’ll use the get add components to a Men enuItem... we can only return the name u). getDescription() methods to and description of the menu. you are here 4 359 Download at WoweBook.Com implementing composite menus Implementing the Menu Component All components must implement Okay, we’re going to start with the the MenuComponent interface; MenuComponent abstract class; remember, the however, because leaves and role of the menu component is to provide an nodes have different roles we interface for the leaf nodes and the composite can’t always define a default nodes. Now you might be asking, “Isn’t the implementation for each MenuComponent playing two roles?” It might method that makes sense. well be and we’ll come back to that point. Sometimes the best you can do However, for now we’re going to provide a default is throw a runtime exception. implementation of the methods so that if the MenuItem (the leaf) or the Menu (the composite) doesn’t want to implement some of the methods (like getChild() for a leaf node) they can fall back on some basic behavior: Because some of these methods only make sense for MenuItems, and some only make sense for ault MenuComponent provides def thod. Menus, the default implementation is implementations fo r eve ry me UnsupportedOperationException. That way, if MenuItem or Menu doesn’t support an operation, they don’t have to do anything, public abstract class MenuComponent { they can just inherit the public void add(MenuComponent menuComponent) { default implementation. throw new UnsupportedOperationException(); } public void remove(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } We’ve grouped together the public MenuComponent getChild(int i) { “composite” methods - that is, throw new UnsupportedOperationException(); methods to add, remove and get } MenuComponents. public String getName() { ds; Here are the “operation” metho s. throw new UnsupportedOperationException(); } public String getDescription() { these are used by the MenuI a tem throw new UnsupportedOperationException(); It turns out we can also use as } couple of them in Menu too, when public double getPrice() { you’ll see in a couple of pages throw new UnsupportedOperationException(); we show the Menu code. } public boolean isVegetarian() { throw new UnsupportedOperationException(); } print() is an “operation” method public void print() { that both our Menus and MenuItems throw new UnsupportedOperationException(); will implement, but we provide a } default operation here. } 360 Chapter 9 Download at WoweBook.Com the iterator and composite patterns Implementing the Menu Item I’m glad we’re going in this direction, I’m thinking this is going to give me the flexibility I need to implement that crêpe menu I’ve Okay, let’s give the MenuItem class a shot. Remember, always wanted. this is the leaf class in the Composite diagram and it implements the behavior of the elements of the composite. public class MenuItem extends MenuComponent { First we need to extend String name; String description; boolean vegetarian; the MenuComponent double price; interface. public MenuItem(String name, The constructor just takes String description, boolean vegetarian, the name, description, etc. and double price) keeps a reference to them all. { This is pretty much like our old this.name = name; menu item implementation. this.description = description; this.vegetarian = vegetarian; this.price = price; } public String getName() { return name; } Here’s our getter methods - just public String getDescription() { like our previous implementation. return description; } public double getPrice() { return price; } This is different from the previous implementation. Here we’re overriding the print() method in the public boolean isVegetarian() { return vegetarian; } MenuComponent class. For MenuItem this method prints the complete menu entry: name, description, public void print() { price and whether or not it’s veggie. System.out.print(“ “ + getName()); if (isVegetarian()) { System.out.print(“(v)”); } System.out.println(“, “ + getPrice()); System.out.println(“ -- “ + getDescription()); } } you are here 4 361 Download at WoweBook.Com composite structure Implementing the Composite Menu Now that we have the MenuItem, we just need the composite class, which we’re calling Menu. Remember, the composite class can hold MenuItems or other Menus. There’s a couple of methods from MenuComponent this class doesn’t implement: getPrice() and isVegetarian(), because those don’t make a lot of sense for a Menu. Menu is also a MenuComponent, children just like MenuItem. Menu can have any number of use an of type MenuComponent, we’ll se. internal ArrayList to hold the public class Menu extends MenuComponent { ArrayList menuComponents = new ArrayList(); String name; String description; This is different than our old implementation: we’re going to give each Menu a name and a public Menu(String name, String description) { this.name = name; description. Before, we just relied on having this.description = description; different classes for each menu. } public void add(MenuComponent menuComponent) { Here’

Use Quizgecko on...
Browser
Browser