TDDB84 Design Patterns Lecture 04 More on Iterators, Composite, - - PowerPoint PPT Presentation

tddb84 design patterns lecture 04 more on iterators
SMART_READER_LITE
LIVE PREVIEW

TDDB84 Design Patterns Lecture 04 More on Iterators, Composite, - - PowerPoint PPT Presentation

TDDB84 Design Patterns Lecture 04 More on Iterators, Composite, Abstract Factory Peter Bunus Department of Computer and Information Science Linkping University, Sweden peter.bunus@liu.se The Constitution of Software Architects


slide-1
SLIDE 1

Peter Bunus Department of Computer and Information Science Linköping University, Sweden peter.bunus@liu.se

TDDB84 Design Patterns Lecture 04 More on Iterators, Composite, Abstract Factory

slide-2
SLIDE 2

2

The Constitution of Software Architects

Encapsulate what varies Program through an interface not to an implementation Favor Composition over Inheritance Classes should be open for extension but closed for modification Don’t call us, we’ll call you ????????? ????????? ????????? ?????????

slide-3
SLIDE 3

3

Iterating through menus

printMenu()

  • prints every item on the

menu printBreakfastMenu()

  • print just breakfast items

printLunchMenu()

  • print just lunch items

printVegetarianMenu()

  • print all vegetarian menu

items isItemVegetarian()

  • given the name of an item,

returns true is the item is vegetarian, otherwise returns false

slide-4
SLIDE 4

4

What did we do?

We wanted to give to the Waiter an easy way to iterate over more items ... and we didn’t want him to know about how the menu items are implemented 1 2 3 4 ArrayList of MenuItems 1 2 3 4 An Array

  • f

MenuItems Our menu item had two different implementations and two different interfaces for interacting

slide-5
SLIDE 5

5 TDDB84 Design Patterns HT1 2009 LECTURE 04

We decoupled the Waiter

1 2 3 4 1 2 3 4

Iterator Iterator next() next()

So we gave the waiter an iterator for each group of

  • bjects he needed to

iterate over... Now he doesn’t have to worry about which implementation we used; he always uses the same

  • interface. He has been

decoupled from the implementation

slide-6
SLIDE 6

6 TDDB84 Design Patterns HT1 2009 LECTURE 04

We Can Embrace Change

Iterator next() HashTable Iterator next() Vector Iterator next() LinkedList

Java collections that already have an Iterator implemented By giving him an Iterator we have decoupled him from the implementation

  • f the menu items so we

can easily add new menus if we want.

slide-7
SLIDE 7

7 TDDB84 Design Patterns HT1 2009 LECTURE 04

The Waitress Code

public class Waitress { Menu pancakeHouseMenu; Menu dinerMenu; Menu cafeMenu; public Waitress(Menu pancakeHouseMenu, Menu dinerMenu, Menu cafeMenu) { this.pancakeHouseMenu = pancakeHouseMenu; this.dinerMenu = dinerMenu; this.cafeMenu = cafeMenu; } 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); System.out.println("\nDINNER"); printMenu(cafeIterator); } private void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = (MenuItem)iterator.next(); System.out.print(menuItem.getName() + ", "); System.out.print(menuItem.getPrice() + " -- "); System.out.println(menuItem.getDescription()); } }

slide-8
SLIDE 8

8

The Constitution of Software Architects

Encapsulate what varies Program through an interface not to an implementation Favor Composition over Inheritance Classes should be open for extension but closed for modification Don’t call us, we’ll call you ????????? ????????? ????????? ?????????

slide-9
SLIDE 9

9

The Waitress Code Revised

public class Waitress { ArrayList menus; public Waitress(ArrayList menus) { this.menus = menus; } public void printMenu() { Iterator menuIterator = menus.iterator(); while(menuIterator.hasNext()) { Menu menu = (Menu)menuIterator.next(); printMenu(menu.createIterator()); } } void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = (MenuItem)iterator.next(); System.out.print(menuItem.getName() + ", "); System.out.print(menuItem.getPrice() + " -- "); System.out.println(menuItem.getDescription()); } } } public class MenuTestDrive { public static void main(String args[]) { PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); DinerMenu dinerMenu = new DinerMenu(); Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu); waitress.printMenu(); waitress.printVegetarianMenu(); ... } ... }

slide-10
SLIDE 10

10

Design Principle Ahead

Joe you could allow your aggregates to implement their internal collections and related

  • peration AND the iteration
  • methods. You could save some

classes here Joe don’t do that. I feel that bad things will happen in the future if you do that

slide-11
SLIDE 11

11

Diner Menu Iterator

public class DinerMenuIterator implements Iterator { MenuItem[] items; int position = 0; public DinerMenuIterator(MenuItem[] items) { this.items = items; } public Object next() { MenuItem menuItem = items[position]; position = position + 1; return menuItem; } public boolean hasNext() { if (position >= items.length || items[position] == null) { return false; } else { return true; } } }

slide-12
SLIDE 12

12 TDDB84 Design Patterns HT1 2009 LECTURE 04

The Diner Menu Implementation

public class DinerMenu { static final int MAX_ITEMS = 6; int numberOfItems = 0; MenuItem[] menuItems; int position=0; public DinerMenu() { menuItems = new MenuItem[MAX_ITEMS]; .... addItem("BLT","Bacon with lettuce & tomato on whole wheat", false, 2.99); ...... } public void addItem(String name, String description, boolean vegetarian, double price) { .... } } public Iterator createIterator() return new DinerMenuIterator(menuItems) public Object next() { MenuItem menuItem = menuItems[position]; position = position + 1; return menuItem; } public boolean hasNext() if (position >= menuItems.length || menuItems[position] == null) { return false; } else { return true; } } }

slide-13
SLIDE 13

13 TDDB84 Design Patterns HT1 2009 LECTURE 04

The Star Trek Convention is in Town

Joe there is a Stat Trek Convention in Town and the Klingonians would like to visit our

  • restaurant. According to the

Klingonian customs our waitress need to print them the menu backwards The Romulans are also coming in the evening. We need to give them some galactic snails, I sent you a new menu with galactic snail

  • dishes. Print the menu as usual.
slide-14
SLIDE 14

14

Design Principle

A class should have only one reason to change

slide-15
SLIDE 15

15

The Constitution of Software Architects

Encapsulate what varies Program through an interface not to an implementation Favor Composition over Inheritance Classes should be open for extension but closed for modification

  • Don’t call us, we’ll call you
  • A Class should have only one reason to change

????????? ????????? ?????????

slide-16
SLIDE 16

16

Violating the Single Responsability Principle

High Low reliability reusability testability understandability maintainability

slide-17
SLIDE 17

Just when we thought it was safe...

Joe, we need to insert a dessert menu into the Dinner menu. The kids will love that. Could you please fix that?

slide-18
SLIDE 18

18

The Desired Menu Structure

HashTable Coffee Menu 1 2 3 4 ArrayList Pancake Menu 1 2 3 4 Array Dinner Menu

1 2

3

ArrayList All Menus 1 2 3 4 Dessert Menu

slide-19
SLIDE 19

All menus Pancake House Menu Dinner Menu Coffee Menu

MenuItem MenuItem MenuItem MenuItem MenuItem MenuItem

Dessert Menu

MenuItem MenuItem MenuItem MenuItem MenuItem MenuItem MenuItem

What we need

  • A tree structure to accomodate menus
  • A way of traversing the tree
  • Traversing in a flexible manner (e.g.

Traverse only the Diner’s dessert menu)

slide-20
SLIDE 20

Peter Bunus Department of Computer and Information Science Linköping University, Sweden peter.bunus@liu.se

Composite

slide-21
SLIDE 21

21

The Composite Pattern

  • The Composite Pattern allows us to build structures of objects in the

form of tree that contains both composition of objects and individual

  • bjects as nodes
slide-22
SLIDE 22

22

The Composite Explained

The Client uses the Component interface to manipulate the objects in the commposition The Component defines an interface for all objects in the composition both the composite and the leaf node The Component may implement a default behavior for Add(), Remove(), GetChild() and its operations Note that Leaf will inherit Add(), Remove(), GetChild() which don’t make a lot of sense for a Leaf node A Leaf has no children A Leaf defines the behavior for the elements in the composition. It does this by implementing the the

  • perations that the Composite

supports The Composite’s role is to define behavior

  • f the components having children and to

store child components. It also implements Leaf related operations. Some of them might not make sense in Composite and exceptions might be generated

slide-23
SLIDE 23

23

The Menu Composite

The Waitress is going to use the MenuComponent interface to access both Menus and MenuItems MenuComponent represents the interface for both MenuItem and Menu. Methods for manipulating the

  • components. The

components are MenuItem and Menu MenuItem overrides the methods that make sense, an uses the default implementation in MenuComponent for those that don’t make sense Menu also overrides the methods that make sense, like a way to add and remove menu items.

slide-24
SLIDE 24

24

The Menu Component

public abstract class MenuComponent { public void add(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } public void remove(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } public MenuComponent getChild(int i) { throw new UnsupportedOperationException(); } public String getName() { throw new UnsupportedOperationException(); } public String getDescription() { throw new UnsupportedOperationException(); } public double getPrice() { throw new UnsupportedOperationException(); } public boolean isVegetarian() { throw new UnsupportedOperationException(); } public void print() { throw new UnsupportedOperationException(); } }

Operations used by MenuItems The composite methods

slide-25
SLIDE 25

25

The MenuItem

public class MenuItem extends MenuComponent { String name; String description; boolean vegetarian; double price; public MenuItem(String name, String description, boolean vegetarian, double price) { this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public String getName() { return name; } public String getDescription() { return description; } public double getPrice() { return price; } public boolean isVegetarian() { return vegetarian; } public void print() { System.out.print(" " + getName()); if (isVegetarian()) { System.out.print("(v)");} System.out.println(", " + getPrice()); System.out.println(" -- " + getDescription());

} }

slide-26
SLIDE 26

26 TDDB84 Design Patterns HT1 2009 LECTURE 04

The Menu

public class Menu extends MenuComponent { ArrayList menuComponents = new ArrayList(); String name; String description; public Menu(String name, String description) { this.name = name; this.description = description; } public void add(MenuComponent menuComponent) { menuComponents.add(menuComponent); } public void remove(MenuComponent menuComponent) { menuComponents.remove(menuComponent); } public MenuComponent getChild(int i) { return (MenuComponent)menuComponents.get(i);} public String getName() { return name;} public String getDescription() { return description;} public void print() { System.out.print("\n" + getName()); System.out.println(", " + getDescription()); Iterator iterator = menuComponents.iterator(); while (iterator.hasNext()) { MenuComponent menuComponent = (MenuComponent)iterator.next(); menuComponent.print(); } } }

slide-27
SLIDE 27

27 TDDB84 Design Patterns HT1 2009 LECTURE 04

The Waitress Code

public class Waitress { ArrayList menus; public Waitress(ArrayList menus) { this.menus = menus; } public void printMenu() { Iterator menuIterator = menus.iterator(); while(menuIterator.hasNext()) { Menu menu = (Menu)menuIterator.next(); printMenu(menu.createIterator()); } } void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = (MenuItem)iterator.next(); System.out.print(menuItem.getName() + ", "); System.out.print(menuItem.getPrice() + " -- "); System.out.println(menuItem.getDescription()); } } }

Before

public class Waitress { MenuComponent allMenus; public Waitress(MenuComponent allMenus) { this.allMenus = allMenus; } public void printMenu() { allMenus.print(); } }

After

slide-28
SLIDE 28

28 TDDB84 Design Patterns HT1 2009 LECTURE 04

Runing the Restaurant

public class MenuTestDrive { public static void main(String args[]) { MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast"); MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch"); MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner"); MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course!"); MenuComponent coffeeMenu = new Menu("COFFEE MENU", "Stuff for the afternoon coffee"); MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined"); allMenus.add(pancakeHouseMenu); allMenus.add(dinerMenu); allMenus.add(cafeMenu); pancakeHouseMenu.add(new MenuItem( "K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99)); .... dinerMenu.add(new MenuItem( "Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99)); ..... dinerMenu.add(dessertMenu); dessertMenu.add(new MenuItem( "Apple Pie", "Apple pie with a flakey crust, topped with vanilla icecream", true, 1.59)); ..... cafeMenu.add(new MenuItem( "Veggie Burger and Air Fries", "Veggie burger on a whole wheat bun, lettuce, tomato, and fries", true, 3.99)); .... cafeMenu.add(coffeeMenu); coffeeMenu.add(new MenuItem( "Coffee Cake", "Crumbly cake topped with cinnamon and walnuts",true,1.59)); Waitress waitress = new Waitress(allMenus); waitress.printMenu(); } }

slide-29
SLIDE 29

29

Runing the Restaurant

The Dessert Menu please The Pancake Menu please The Coffe Menu please

slide-30
SLIDE 30

Peter, you said that I should respect the SINGLE RESPONSIBILITY PRINCIPLE. Now you are proposing me a Composite Pattern with classes with double responsibilities

SRP?

Yes indeed we are intentionally violating the SRP. Actually I’m not violating it; I’m trading it for transparency

  • By allowing the Component Interface to

contain the child management operations and leaf operations, a client can treat both composite and leaf nodes uniformly

slide-31
SLIDE 31

31

The Constitution of Software Architects

Encapsulate what varies Program through an interface not to an implementation Favor Composition over Inheritance Classes should be open for extension but closed for modification

  • Don’t call us, we’ll call you
  • A Class should have only one reason to change

????????? ????????? ?????????

slide-32
SLIDE 32

32

Composite Pattern - Example

slide-33
SLIDE 33

The Composite Design Pattern

slide-34
SLIDE 34

34

The Abstract Factory

slide-35
SLIDE 35

35 TDDB84 Design Patterns HT1 2009 LECTURE 04

Meanwhile at the Pizza Restaurant...

slide-36
SLIDE 36

36

Baking Pizzas with the Factory Method

+prepare() +bake() +cut() +box() Pizza CheesePizza PepperoniPizza ClamPizza VeggiePizza

slide-37
SLIDE 37

What we have learned from the Factory Mehod?

  • First of all let’s take a look on what we tried to

avoid

public class PizzaStore { public Pizza createPizza(String style, String type){ Pizza pizza = null; if (style.equals(”Paris”)){ if (type.equals(”cheese”)){ pizza = new ParisStyleCheezePizza; } if (type.equals(”clam”)){ pizza = new ParisStyleClamPizza; } ..... } else if (style.equals(”Rome”)){ if (type.equals(”cheese”)){ pizza = new RomeStyleCheezePizza; } if (type.equals(”clam”)){ pizza = new RomeStyleClamPizza; } ..... } else { .... } } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza;

}

When you instantiate a class you are depending on the on its concrete class: if the implementation of the concrete classes changes we need to modify the pizza store

slide-38
SLIDE 38

38 TDDB84 Design Patterns HT1 2009 LECTURE 04

Design Principle

Depend upon abstractions. Do not depend upon concrete classes.

slide-39
SLIDE 39

39

The Constitution of Software Architects

Encapsulate what varies Program through an interface not to an implementation Favor Composition over Inheritance Classes should be open for extension but closed for modification

  • Don’t call us, we’ll call you
  • A Class should have only one reason to change
  • Depend upon abstractions. Do not depend upon

concrete classes.

????????? ?????????

slide-40
SLIDE 40

40

DIP explained

Depend upon abstractions. Do not depend upon concrete classes.

Peter could you please translate me the dependency Inversion Principle to English

High-level components should not depend on low level components; they should both depend on abstractions PizzaStore is ”high level component” Pizzas are ”low level components”

slide-41
SLIDE 41

41

Guidlines to follow the DIP

  • No variable should hold a reference to a concrete class
  • If you use new you are holding a reference to a concrete class. Use a factory to get

around that

  • No class should derive from a concrete class
  • If you derive from a concrete class, you’re depending on a concrete class. Derive

from an abstraction like an interface or an abstract class.

  • No method should override an implemented method of any of its base

classes

  • If you override an implemented method, then you base class wasn’t really an

abstraction to start with. Those methods implemented in the base class are meant to be shared by all your subclasses

slide-42
SLIDE 42

Pizza Ingredients

slide-43
SLIDE 43

Building Ingredient Factories

public interface PizzaIngredientFactory { public Dough createDough(); public Sauce createSauce(); public Cheese createCheese(); public Veggies[] createVeggies(); public Pepperoni createPepperoni(); public Clams createClam(); }

slide-44
SLIDE 44

TDDB84 Design Patterns HT1 2009 LECTURE 04

Building the NY Ingredient Factory

public class NYPizzaIngredientFactory implements PizzaIngredientFactory { public Dough createDough() { return new ThinCrustDough(); } public Sauce createSauce() { return new MarinaraSauce(); } public Cheese createCheese() { return new ReggianoCheese(); } public Veggies[] createVeggies() { Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() }; return veggies; } public Pepperoni createPepperoni() { return new SlicedPepperoni(); } public Clams createClam() { return new FreshClams(); } }

slide-45
SLIDE 45

45 TDDB84 Design Patterns HT1 2009 LECTURE 04

Now it is time for Pizza

public abstract class Pizza { String name; Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Pepperoni pepperoni; Clams clam; abstract void prepare(); void bake() { System.out.println("Bake for 25 minutes at 350");} void cut() { System.out.println("Cutting the pizza into diagonal slices");} void box() { System.out.println("Place pizza in official PizzaStore box");} void setName(String name) { this.name = name; } String getName() { return name; } } public class CheesePizza extends Pizza { PizzaIngredientFactory ingredientFactory; public CheesePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; } void prepare() { System.out.println("Preparing " + name); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); cheese = ingredientFactory.createCheese(); } }

slide-46
SLIDE 46

46

The Pizza Store

public class NYPizzaStore extends PizzaStore { protected Pizza createPizza(String item) { Pizza pizza = null; PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory(); if (item.equals("cheese")) { pizza = new CheesePizza(ingredientFactory); pizza.setName("New York Style Cheese Pizza"); } else if (item.equals("veggie")) { pizza = new VeggiePizza(ingredientFactory); pizza.setName("New York Style Veggie Pizza"); } else if (item.equals("clam")) { pizza = new ClamPizza(ingredientFactory); pizza.setName("New York Style Clam Pizza"); } else if (item.equals("pepperoni")) { pizza = new PepperoniPizza(ingredientFactory); pizza.setName("New York Style Pepperoni Pizza"); } return pizza; } }

slide-47
SLIDE 47

47 TDDB84 Design Patterns HT1 2009 LECTURE 04

Running the Pizzeria

public class PizzaTestDrive { public static void main(String[] args) { PizzaStore nyStore = new NYPizzaStore(); PizzaStore chicagoStore = new ChicagoPizzaStore(); Pizza pizza = nyStore.orderPizza("cheese"); System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagoStore.orderPizza("cheese"); System.out.println("Joel ordered a " + pizza + "\n"); }

slide-48
SLIDE 48

The Pizza Abstract Factory

The AbstractPizzaIngredientFactory is the interface that defines how to make a family of related products: everything we need to make a pizza The Clients of the AbstractFactory are the two instances of

  • ur PizzaStore

NYPizzaStore and ChicagoStylePizza Store Each factory produces a different implementation for the family of products The job of the concrete pizza factories is to make pizza ingredients. Each factory knows how to create the right

  • bject for their region
slide-49
SLIDE 49

49

The Abstract Factory Template

  • Provide an interface for creating families of related or dependent
  • bjects without specifying their concrete classes.
slide-50
SLIDE 50

50

Abstract Factory Example

  • Interface toolkit to support multiple look-and-feel standards
slide-51
SLIDE 51

51

The Abstract Factory – Non Software Example