88
Unit 20 Factory Method Summary prepared by Kirk Scott 1

Unit 20 Factory Method

  • Upload
    zelda

  • View
    39

  • Download
    0

Embed Size (px)

DESCRIPTION

Unit 20 Factory Method. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 16 Factory Method. Summary prepared by Kirk Scott. Ordinary construction relies on the existence of constructors in a base class - PowerPoint PPT Presentation

Citation preview

Page 1: Unit 20 Factory Method

1

Unit 20Factory Method

Summary prepared by Kirk Scott

Page 2: Unit 20 Factory Method

2

Design Patterns in JavaChapter 16

Factory Method

Summary prepared by Kirk Scott

Page 3: Unit 20 Factory Method

3

• Ordinary construction relies on the existence of constructors in a base class

• The Factory Method design pattern still relies on these ordinary constructors

• However, it protects the client from using the constructors directly

Page 4: Unit 20 Factory Method

4

• The client code can be written so that all it cares about is that the objects it works with implement a given interface

• The client code may work with several different base classes

• The client code may not know or care specifically which kind of object it is working with

• Dynamic binding makes this practical

Page 5: Unit 20 Factory Method

5

• A base class will implement a factory method which returns an object of a given interface

• The actual type of the underlying object returned to the client will depend on the logic internal to the factory method

• The client will not be in control of the actual type of object that it receives

Page 6: Unit 20 Factory Method

6

• Book definition:• The intent of the Factory Method is to let a

class developer define the interface for creating an object while retaining control of which class to instantiate.

Page 7: Unit 20 Factory Method

7

A Classic Example: Iterators

• Iterators were introduced earlier as an independent design pattern

• I observed that in a sense, they were simple examples of the template pattern

• Iterators also illustrate the idea behind the factory method

• The later example will be structured somewhat differently, but by intent, the iterator() method serves as a kind of factory for iterator objects

Page 8: Unit 20 Factory Method

8

• Iteration is built on top of the idea of a collection class

• There is a Collection interface• Every class that implements the Collection

interface has to implement the method iterator()

• The iterator() method returns an instance of an iterator over elements of the given collection

Page 9: Unit 20 Factory Method

9

• The iterator() method returns something that implements the Iterator interface

• When you call iterator() on an object of a given collection class, an iterator for that class is returned

• When you call iterator() on an instance of another collection class, an iterator for that class is returned

• The iterator() method is the factory method

Page 10: Unit 20 Factory Method

10

• The client doesn’t have to “know” specifically what kind of iterator is being returned

• The returned object simply has to implement the Iterator interface

• That allows the client to call the methods defined in that interface on the returned object

Page 11: Unit 20 Factory Method

11

Code with an Iterator

• The book pursues this idea with an example• The code on the following overhead illustrates

the creation and use of an iterator for a collection of type List

• The instance of List is constructed by hard coding a simple array of strings and passing it in to the List object

Page 12: Unit 20 Factory Method

12

• import java.util.*;• public class ShowIterator • {• public static void main(String[] args) • {• List list = Arrays.asList(• new String[] { "fountain", "rocket", "sparkler" });• • Iterator iter = list.iterator();• • while (iter.hasNext()) • System.out.println(iter.next());• • // Uncomment the next line • // to see the iterator's actual class:• // System.out.println(iter.getClass().getName());• }• }

Page 13: Unit 20 Factory Method

13

• Challenge 16.1• What is the actual class of the Iterator object

in this code?

Page 14: Unit 20 Factory Method

14

• Solution 16.1• A good answer, perhaps, is that you do not need to

know what class of object an iterator() method returns.

• What is important is that you know the interface that the iterator supports, which lets you walk through the elements of a collection.

• However, if you must know the class, you can print out its name with a line like:

• System.out.println(iter.getClass().getName());

Page 15: Unit 20 Factory Method

15

• This statement prints out:• java.util.AbstractList$Itr• The class Itr is an inner class of AbstractList.

You should probably never see this class in your work with Java.

• [End of Solution 16.1.]

Page 16: Unit 20 Factory Method

16

Recognizing Factory Method

• There are many methods floating around object-oriented code which return references to newly created objects of one class or another

• Just because a method returns such a reference doesn’t mean that it implements the Factory Method design pattern.

Page 17: Unit 20 Factory Method

17

• Challenge 16.2• Name two commonly used methods in the

Java class libraries that return a new object.• [And don’t implement the Factory Method

design pattern.]

Page 18: Unit 20 Factory Method

18

• Solution 16.2• There are many possible answers, but toString()

is probably the most commonly used method that creates a new object.

• For example, the following code creates a new String object:

• String s = new Date().toString();

• The creation of strings often happens behind the scenes.

Page 19: Unit 20 Factory Method

19

• Consider:• System.out.println(new Date());• This code creates a String object from the Date

object, ultimately by calling the toString() method of the Date object.

• Another frequently used method that creates a new object is clone(), a method that usually returns a copy of the receiving object.

• [End of Solution 16.2.]

Page 20: Unit 20 Factory Method

20

• The point of the answers to the previous challenge is this:

• toString() and clone() don’t exhibit the Factory Method design pattern

• They don’t protect the client (the calling code) from knowing what kind of object is being constructed and returned

• There is no set of classes under the covers that implement a common interface which is the type returned by the calls to those methods

Page 21: Unit 20 Factory Method

21

• Challenge 16.3• The class javax.swing.BorderFactory sounds

like it ought to be an example of the Factory Method pattern.

• Explain how the intent of the Factory Method pattern is different from the intent of the BorderFactory class.

Page 22: Unit 20 Factory Method

22

• Comment mode on:• This challenge basically boils down to a red herring• It’s like asking whether the so-called Adapter

classes in Java implement the Adapter design pattern

• The answer is no, it’s just the use of the same word to mean a different thing

• You have no way of knowing this unless you’re already familiar with the BorderFactory class

Page 23: Unit 20 Factory Method

23

• Solution 16.3• The intent of the Factory Method pattern is to let

an object provider determine which class to instantiate when creating an object.

• By comparison, clients of BorderFactory know exactly what object types they’re getting.

• The pattern at play in BorderFactory is Flyweight, in that BorderFactory uses sharing to efficiently support large numbers of borders.

Page 24: Unit 20 Factory Method

24

• The BorderFactory class isolates clients from managing the reuse of objects, whereas Factory Method isolates clients from knowing which class to instantiate.

• [End of Solution 16.3.]

Page 25: Unit 20 Factory Method

25

Taking Control of Which Class to Instantiate

• The book now moves on from examples like iterator(), which already exist in Java

• It paints a scenario where client code needs to obtain a credit limit for a customer

• If a credit agency is online, then the credit limit is generated with an instance of a class named CreditCheckOnline

Page 26: Unit 20 Factory Method

26

• If the credit agency is offline, then the credit check is generated with an instance of a class named CreditCheckOffline

• The method that the client code is going to call is creditLimit()

• The client code doesn’t care exactly what kind of object is returned

• The UML diagram on the following overhead illustrates the situation so far

Page 27: Unit 20 Factory Method

27

Page 28: Unit 20 Factory Method

28

• The book outlines these elements of an application of the Factory Method design pattern to this situation:

• 1. Make a CreditCheck interface that includes a creditLimit() method

• 2. Have the classes CreditCheckOnline and CreditCheckOffline implement this interface

Page 29: Unit 20 Factory Method

29

• 3. Make a CreditCheckFactory class with a createCreditCheck() method that returns an object of type CreditCheck

• In this example the question is, what kind of credit limit is it, an online or offline one?

• The createCreditCheck() method will return a reference to one kind of object or another

• createCreditCheck() is the factory method

Page 30: Unit 20 Factory Method

30

• Challenge 16.4• Draw a class diagram that establishes a way

for this new scheme to create a credit-checking object while retaining control of which class to instantiate.

Page 31: Unit 20 Factory Method

31

• Solution 16.4• Figure B.18 shows that the two credit check

classes implement the CreditCheck interface.• The factory class provides a method that

returns a CreditCheck object.• The client that calls createCreditCheck() does

not know the precise class of the object it receives.

Page 32: Unit 20 Factory Method

32

Page 33: Unit 20 Factory Method

33

• Comment mode on:• I’m not overwhelmed by the UML diagram.• It would be more helpful if it showed a link

between the factory and the interface, indicating that the factory makes use of the interface

• It would also be more helpful if it showed a client which used the factory to obtain a reference to an object that implemented the interface

Page 34: Unit 20 Factory Method

34

• The Builder UML is repeated on the next overhead

• What I have in mind is that the client is the client• The builder is roughly equivalent to the class

containing the factory method• The base class is roughly equivalent to the

factory interface• The implementing classes aren’t shown, but they

would descend from the base class/interface

Page 35: Unit 20 Factory Method

35

Page 36: Unit 20 Factory Method

36

• Solution 16.4, continued• The createCreditCheck() method is a static

method, so clients need not instantiate the CreditCheckFactory class in order to get a CreditCheck object.

• You can make this class abstract or give it a private constructor if you want to actively prevent other developers from instantiating it.

• [End of Solution 16.4.]

Page 37: Unit 20 Factory Method

37

• Once again, this is the basic idea of the example:

• Client code doesn’t know whether credit checking is available online or offline

• It simply wants a credit check generated

Page 38: Unit 20 Factory Method

38

• It does this by calling createCreditCheck()• The logic of the code for that method

determines which kind of actual credit check object is returned

• However, whatever is returned, it will implement the CreditCheck interface

Page 39: Unit 20 Factory Method

39

• Challenge 16.5• Assume that the CreditCheckFactory class has

an isAgencyUp() method that tells whether the credit agency is available, and write the code for createCreditCheck().

Page 40: Unit 20 Factory Method

40

• Solution 16.5• If you take a leap of faith that the static method

isAgencyUp() accurately reflects reality, the code for createCreditCheck() is simple:

• public static CreditCheck createCreditCheck()• {• if(isAgencyUp())• return new CreditCheckOnline();• return new CreditCheckOffline();• }

Page 41: Unit 20 Factory Method

41

Comparing the Factory Method and Strategy Patterns

• Compare the factory method pattern with the previous pattern, strategy

• In strategy, the client code included the logic to decide which kind of strategy object to use

• In factory method, it is the service code that contains the (if) logic to decide which kind of object to return

• The decision is made based on conditions unknown to or extraneous to the client

Page 42: Unit 20 Factory Method

42

Factory Method in Parallel Hierarchies

• Given a hierarchy of classes, you may decide to move a subset of behavior out of the classes and implement it in separate classes

• The result is a parallel hierarchy of classes• The Factory Method design pattern can arise

in such a situation

Page 43: Unit 20 Factory Method

43

• The book illustrates this with machines and machine managers in a fireworks factory

• The UML diagram on the next overhead gives the starting point for the example

• There are various concrete types of machine that extend the abstract Machine class

Page 44: Unit 20 Factory Method

44

Page 45: Unit 20 Factory Method

45

• The scenario is that you would like to have a getAvailable() method for machines for planning purposes

• However, the logic for implementing getAvailable() is relatively complex

• A parallel hierarchy arises when you decide to factor out the functionality for managing availability

Page 46: Unit 20 Factory Method

46

• More background information includes the following:• getAvailable() is supposed to forecast when a machine

will finish its current work and become available• getAvailable() will be implemented in planner classes

that parallel the machine classes• Most machine types will have different logic, requiring

different kinds of planner (classes)• Mixers and fusers can share the same kind of planner

(class)

Page 47: Unit 20 Factory Method

47

• Challenge 16.6• Fill in the diagram of a

Machine/MachinePlanner parallel hierarchy in Figure 16.3.

Page 48: Unit 20 Factory Method

48

Page 49: Unit 20 Factory Method

49

• Solution 16.6• Figure B.19 shows a reasonable diagram for

the Machine/MachinePlanner parallel hierarchy.

Page 50: Unit 20 Factory Method

50

Page 51: Unit 20 Factory Method

51

• Solution 16.6 continued• This diagram indicates that subclasses of

MachinePlanner must implement the getAvailable() method.

• The diagram also indicates that classes in the MachinePlanner hierarchy accept a Machine object in their constructors.

Page 52: Unit 20 Factory Method

52

• In practice, this will mean that when a planner is constructed for a machine from within the machine’s code, the parameter “this” will be passed

• This allows the planner to interrogate the object it is planning for, regarding such criteria as the machine’s location and the amount of material it is currently processing.

Page 53: Unit 20 Factory Method

53

• Although the getAvailable() method motivates the parallel hierarchy, it is not the factory method

• In this example the createPlanner() method is the factory method

• An implementation of that method in the machine hierarchy has to return an instance of a planner, of which there are several concrete kinds

Page 54: Unit 20 Factory Method

54

• The createPlanner() method, the factory method, doesn’t actually do creation

• The implementation of createPlanner() depends on the constructors for planners that exist in the planner hierarchy

• createPlanner() is to machines what iterator() is to collection classes

Page 55: Unit 20 Factory Method

55

• Client code makes calls of the form someMachine.createPlanner()

• All the client code cares about is that the return value is an instance of a subclass of the MachinePlanner abstract class

• (This abstract class is a replacement for an interface in this example.)

• The client is not concerned with which actual type of planner object is returned—as long as it’s appropriate to whatever machine is under consideration

Page 56: Unit 20 Factory Method

56

• Challenge 16.7• Write a createPlanner() method for the

Machine class to return a BasicPlanner object, and write a createPlanner() method for the StarPress class

Page 57: Unit 20 Factory Method

57

• Solution 16.7• A [generic] createPlanner() method for the Machine class

might look like:• public MachinePlanner createPlanner()• {• return new BasicPlanner(this);• }• The Fuser and Mixer classes can rely on inheriting this

method, whereas the ShellAssembler and StarPress class will need to override it.

Page 58: Unit 20 Factory Method

58

• For the StarPress class, the createPlanner() method might be:

• public MachinePlanner createPlanner()• {• return new StarPressPlanner(this);• }

Page 59: Unit 20 Factory Method

59

• These methods show the Factory Method pattern at work.

• When we need a planner object, we call the createPlanner() method on the machine we want a planner for.

• The specific planner that we receive depends on the machine.

• [End of solution.]

Page 60: Unit 20 Factory Method

60

Another Example

• The other example is based on the idea of a one armed bandit

• With every pull of the arm, three images of fruits appear in a row

• If all three fruits are the same, it’s a win• A screen shot of the application is shown on

the following overhead

Page 61: Unit 20 Factory Method

61

Page 62: Unit 20 Factory Method

62

• Inside the code, fruits have to be randomly generated

• The application doesn’t care which of the three fruits is created for each of the three slots, as long as whatever is generated is of the Fruit interface

• This is accomplished with a FruitFactory class• A UML diagram of the application is given on the

next overhead

Page 63: Unit 20 Factory Method

63

Page 64: Unit 20 Factory Method

64

• Code for the application is given on the following overheads for reference

• It will not be covered in class

Page 65: Unit 20 Factory Method

65

• import java.awt.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class OneArmedBandit• {• public static void main(String[] args)• {• BanditFrame myframe = new BanditFrame();• myframe.setVisible(true);• }• }

Page 66: Unit 20 Factory Method

66

• class BanditFrame extends JFrame• {• private BanditPanel myPanel;• private final int FRAMEW = 700;• private final int FRAMEH = 215;

• public BanditFrame()• {• setTitle("Bandit Frame");• setSize(FRAMEW, FRAMEH);• setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

• myPanel = new BanditPanel();• Container contentPane = getContentPane();• contentPane.add(myPanel, "Center");• }• }

Page 67: Unit 20 Factory Method

67

• class BanditPanel extends JPanel• {• private JPanel northPanel = new JPanel();• private JPanel centerPanel = new JPanel();• private JButton armButton;• private Fruit[] fruit = new Fruit[3];• private JLabel[] fruitLabel = new JLabel[3];• private JLabel centerLabel = new JLabel("You

haven't played yet.");

Page 68: Unit 20 Factory Method

68

• public BanditPanel()• {• setLayout(new BorderLayout());

• JPanel[] subPanel = new JPanel[4];

• for(int i = 0; i < 3; i++)• {• fruit[i] = new Start();• fruitLabel[i] = new JLabel(fruit[i].getImageIcon());• subPanel[i] = new JPanel();• subPanel[i].add(fruitLabel[i]);• northPanel.add(subPanel[i]);• }

• armButton = new JButton("Play the Game");• ArmListener myButtonListener = new ArmListener();• armButton.addActionListener(myButtonListener);• subPanel[3] = new JPanel();• subPanel[3].add(armButton);• northPanel.add(subPanel[3]);

• centerPanel.add(centerLabel);

• add(northPanel, BorderLayout.NORTH);• add(centerPanel, BorderLayout.CENTER);• }

Page 69: Unit 20 Factory Method

69

• public void paintComponent(Graphics g)• {• Graphics2D g2 = (Graphics2D) g;• super.paintComponent(g2);

• }

• private class ArmListener implements ActionListener• {• public void actionPerformed(ActionEvent event)• {• int kindOfFruit;

• for(int i = 0; i < 3; i++)• {• fruit[i] = FruitFactory.makeAFruit();• fruitLabel[i].setIcon(fruit[i].getImageIcon());• }

• Class classRef = fruit[0].getClass();

• if(fruit[0].getClass().equals(fruit[1].getClass())• && fruit[1].getClass().equals(fruit[2].getClass()))• {• centerLabel.setText("You won.");• }• else• {• centerLabel.setText("You didn't win.");• }• }• }• }

Page 70: Unit 20 Factory Method

70

• import java.util.*;

• public class FruitFactory• {• public static Fruit makeAFruit()• {• Random mygenerator = new Random();• int kindOfFruit;• Fruit returnFruit;

• kindOfFruit = mygenerator.nextInt(3);• System.out.println(kindOfFruit);

• if(kindOfFruit == 0)• {• returnFruit = new Apple();• }• else if(kindOfFruit == 1)• {• returnFruit = new Banana();• }• else if(kindOfFruit == 2)• {• returnFruit = new Cherry();• }• else• {• returnFruit = null;• }

• return returnFruit;• }• }

Page 71: Unit 20 Factory Method

71

• import javax.swing.ImageIcon;

• public interface Fruit• {• public ImageIcon getImageIcon();• }

Page 72: Unit 20 Factory Method

72

• import javax.swing.ImageIcon;

• public class Apple implements Fruit• {• private static final ImageIcon

appleImageIcon =• new ImageIcon("apple.jpg");

• public ImageIcon getImageIcon()• {• return appleImageIcon;• }• }

Page 73: Unit 20 Factory Method

73

• import javax.swing.ImageIcon;

• public class Banana implements Fruit• {• private static final ImageIcon

bananaImageIcon =• new ImageIcon("banana.jpg");

• public ImageIcon getImageIcon()• {• return bananaImageIcon;• }• }

Page 74: Unit 20 Factory Method

74

• import javax.swing.ImageIcon;

• public class Cherry implements Fruit• {• private static final ImageIcon

cherryImageIcon =• new ImageIcon("cherry.jpg");

• public ImageIcon getImageIcon()• {• return cherryImageIcon;• }• }

Page 75: Unit 20 Factory Method

75

UML for the Pattern

• On the following overhead a subset of the previous UML diagram is given

• In effect it shows:• A client (the ArmListener)• A factory (the FruitFactory)• An interface (Fruit)• And classes that implement the interface (Apple,

Banana, Cherry)• The makeAFruit() method in the FruitFactory returns an

instance of one of the three fruit classes

Page 76: Unit 20 Factory Method

76

Page 77: Unit 20 Factory Method

77

• You can compare that with the book’s diagram, which is repeated on the following overhead

• In it, the client isn’t shown• The connection between the factory and the

interface also isn’t shown• But overall, the factory, the interface, and the

implementing classes are shown

Page 78: Unit 20 Factory Method

78

Page 79: Unit 20 Factory Method

79

Lasater’s UML for the Pattern

• Lasater’s diagram also doesn’t show a client• Note that for a change, Lasater uses italics to

indicate an abstract class• He shows an abstract class instead of an

interface• The arrowheads in the diagram aren’t reversed• The diagram is “upside down”• Also, he shows two variations on the theme

Page 80: Unit 20 Factory Method

80

Page 81: Unit 20 Factory Method

81

Summary

• The Factory Method design pattern allows client code not to know exactly what kind of object is going to be created

• On the factory side, each different kind of object has to implement the same interface

• Then the client is only concerned that the returned object be of the type of the interface

Page 82: Unit 20 Factory Method

82

• The book illustrated the idea by noting how the iterator() method works in the Java API

• It illustrated a case where the client code would not know which kind of object to construct with the credit example

• It also brought out that the design pattern can be useful with parallel hierarchies where the client only needs to know the one hierarchy and the interface for the other

Page 83: Unit 20 Factory Method

83

• Comment mode on for the last time in this chapter:

• It seems that in the given parallel hierarchies example, it was the slight mismatch between the hierarchies that motivated the use of the pattern

Page 84: Unit 20 Factory Method

84

• If the hierarchies matched exactly, the client, in theory at least, would know:

• If I want to construct a planner for and instance of MachineX

• Then I can expect back from construction, whether ordinary or through a factory method, an instance of PlannerX

Page 85: Unit 20 Factory Method

85

• However, the same observation is true of the iterator example

• If every different collection class has its own iterator type

• Then in theory, client code would know what kind of iterator it was getting

• But the point is that the client code shouldn’t have to worry about this

• And it doesn’t have to when the Factory Method design pattern is applied

Page 86: Unit 20 Factory Method

86

The End

Page 87: Unit 20 Factory Method

87

Page 88: Unit 20 Factory Method

88