Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 16 Factory Method Summary prepared by Kirk Scott 1.

Similar presentations


Presentation on theme: "Chapter 16 Factory Method Summary prepared by Kirk Scott 1."— Presentation transcript:

1 Chapter 16 Factory Method Summary prepared by Kirk Scott 1

2 Groyne 2

3 Weir 3

4 Fascine 4

5 Gabion 5

6 Design Patterns in Java Chapter 16 Factory Method Summary prepared by Kirk Scott 6

7 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 7

8 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 8

9 A base class on the service side of an application 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 9

10 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. 10

11 A Classic Example: Iterators Iterators were introduced earlier as an independent design pattern Iterators illustrate the idea behind the factory method The iterator() method returns a reference typed to Iterator In fact, the object returned will be an instance of the specific class that implements iteration over the kind of collection you’re dealing with 11

12 A Review of Iteration 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 12

13 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 13

14 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 14

15 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 15

16 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()); } 16

17 Challenge 16.1 “What is the actual class of the Iterator object in this code?” 17

18 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()); 18

19 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.] 19

20 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. 20

21 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.] 21

22 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. 22

23 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.] 23

24 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 24

25 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.” 25

26 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 26

27 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. 27

28 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.] 28

29 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 There will be two cases: – An online credit check – An offline credit check 29

30 If a credit agency is online, then the credit limit is generated with an instance of a class named CreditCheckOnline If the credit agency is offline, then the credit check is generated with an instance of a class named CreditCheckOffline 30

31 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 It can call this method on an instance of either class 31

32 Notice how similar this sounds to the previous pattern, strategy You call the same method on one of several classes that implement the interface that includes that method The added difference now will be how to create the objects you call the method on 32

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

34 34

35 Putting the Interface in the Design 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 35

36 Putting the Factory Method in the Design 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 36

37 UML for the Proposed Solution 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.” 37

38 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.” 38

39 Solution 16.4 39

40 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 40

41 On the other hand, notice what the diagram emphasizes: It looks like the diagram for strategy, for example There is an interface and there is a set of classes that implement the interface The classes are related conceptually and also by virtue of the fact that they implement a common interface 41

42 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.] 42

43 Summary of the Idea 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 43

44 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 44

45 Implementing the createCreditCheck() Method 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().” 45

46 Comment mode on: It makes more sense to present this as a challenge than to just jump into the solution In order to understand the solution you have to know the premise given in the challenge When I look at the code on the following overhead, as usual, I could cry because they didn’t use an else 46

47 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(); } 47

48 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 48

49 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 This example illustrates this idea The createCreditCheck() method contains an if statement which depends on the isAgencyUp() method 49

50 Design Questions Step back and think about broad design questions You may have a set of related classes There may be superclass-subclass relationships There may also be sibling relationships 50

51 If classes share functionality, inheritance suggested a design plan that was mentioned in CS 202: Implement the shared functionality in a common superclass, as high in the hierarchy as possible 51

52 We also know that if functionality is sufficiently distinctive, it may be useful to put it into a separate class The term responsibility was introduced in this course as a shorthand for concepts like this 52

53 The concepts of implementing in a hierarchy and factoring functionality out into separate classes can be combined This leads to the idea of parallel hierarchies of classes 53

54 Parallel Hierarchies Summarized Suppose you have a hierarchy of related classes Supposes the classes share some aspects of functionality 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 54

55 The Machine and Machine Manager Example The factory method can arise in parallel hierarchies 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 55

56 56

57 getAvailable() 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 57

58 getAvailable() is supposed to forecast when a machine will finish its current work and become available Most machine types will have different logic, requiring different implementations of getAvailable() Incidentally, mixers and fusers can share the same logic for getAvailable() 58

59 getAvailable() and the Planner Classes In the redesign, getAvailable() will be implemented in planner classes that parallel the machine classes A UML diagram showing the parallel hierarchies is given on the next overhead The book does this as a challenge As usual, it’s just as well to just look at it 59

60 Solution 16.6 60

61 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. 61

62 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.” 62

63 getAvailable() is not the Factory Method getAvailable() motivates this presentation of the factory method design pattern However, getAvailable() is not the factory method The getAvailable() method is the functionality that’s factored out, causing a parallel hierarchy to be developed 63

64 createPlanner() is the Factory Method The UML diagram shows the Machine class with a createPlanner() method The createPlanner() method is the factory method An implementation of that method in the machine hierarchy has to return an instance of a planner There are several different concrete kinds of planners, matching the different kinds of machines 64

65 How createPlanner() works Literally speaking, the createPlanner() method, the factory method, doesn’t actually do creation/construction The implementation of createPlanner() contains calls to constructors for planners that exist in the planner hierarchy 65

66 How the Client Uses createPlanner() 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. 66

67 The client is not concerned with which actual type of planner object is returned It is necessary for the type of planner to be appropriate to whatever machine is under consideration From that point on, polymorphism and dynamic binding cause calls on the planner to execute the right version of getAvailable() 67

68 Implementing/Overriding createPlanner() The book gives some implementations as a challenge As usual, it makes sense to just look at the solutions provided 68

69 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. 69

70 For the StarPress class, the createPlanner() method might be: public MachinePlanner createPlanner() { return new StarPressPlanner(this); } 70

71 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.] 71

72 Putting the Book’s Example in Context If you think critically about the book’s example, you will reach this conclusion: It is a good example of the concept of parallel hierarchies These arise in practice and are worth knowing about This concept itself doesn’t happen to be a design pattern 72

73 This second book example is not a very pure illustration of the factory method concept The determination of what kind of object is needed happens on the client side, not the service side What kind of planner you need depends on the implementation of createPlanner() in a given Machine class 73

74 This is in direct contrast to the credit check example There, the client wanted a credit check It simply asked for one The service side determined which kind would be returned 74

75 In a sense, this example illustrates a more basic, general concept of object-oriented programming The client code can be written to make use of a superclass reference (in this case, abstract) Client code can also be written to make use of an interface 75

76 Comparison with iterator() It may be worth noting that the createPlanner() method is analogous to the iterator() method You call iterator() on an instance of a collection class The right kind of iterator is returned In the client code that iterator is only known by its interface reference 76

77 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 77

78 78

79 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 79

80 80

81 Code for the application is given on the following overheads for reference It will probably not be covered in class 81

82 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); } 82

83 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"); } 83

84 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."); 84

85 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); } 85

86 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."); } 86

87 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; } 87

88 import javax.swing.ImageIcon; public interface Fruit { public ImageIcon getImageIcon(); } 88

89 import javax.swing.ImageIcon; public class Apple implements Fruit { private static final ImageIcon appleImageIcon = new ImageIcon("apple.jpg"); public ImageIcon getImageIcon() { return appleImageIcon; } 89

90 import javax.swing.ImageIcon; public class Banana implements Fruit { private static final ImageIcon bananaImageIcon = new ImageIcon("banana.jpg"); public ImageIcon getImageIcon() { return bananaImageIcon; } 90

91 import javax.swing.ImageIcon; public class Cherry implements Fruit { private static final ImageIcon cherryImageIcon = new ImageIcon("cherry.jpg"); public ImageIcon getImageIcon() { return cherryImageIcon; } 91

92 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 92

93 93

94 You can compare that with the book’s credit check 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 94

95 95

96 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 96

97 97

98 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 98

99 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 99

100 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 100

101 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 101

102 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 102

103 The End 103

104 104

105 105


Download ppt "Chapter 16 Factory Method Summary prepared by Kirk Scott 1."

Similar presentations


Ads by Google