unit 12 flyweight

62
Unit 12 Flyweight Summary prepared by Kirk Scott 1

Upload: donkor

Post on 24-Feb-2016

46 views

Category:

Documents


0 download

DESCRIPTION

Unit 12 Flyweight. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 13 Flyweight. Summary prepared by Kirk Scott. The book states that most typically just one object will hold a single reference to another object - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Unit 12 Flyweight

1

Unit 12Flyweight

Summary prepared by Kirk Scott

Page 2: Unit 12 Flyweight

2

Design Patterns in JavaChapter 13Flyweight

Summary prepared by Kirk Scott

Page 3: Unit 12 Flyweight

3

• The book states that most typically just one object will hold a single reference to another object

• As a result, any change to the “held” object will be a result of a call made in the holding object

• If this is the case, the holding object knows what’s been done

• There is no need to inform any other objects

Page 4: Unit 12 Flyweight

4

• On the other hand, some objects may be referred to by many other objects

• Alternatively, a single object may be referred to many times by one other object

• Put another way, one or more clients will want to share access to the object

• This is a responsibility pattern because now many references/many clients are potentially responsible for making changes to the object

• This is shared responsibility• Also, potentially many client reference/many clients have to be

informed of a change

Page 5: Unit 12 Flyweight

5

• The authors offer this scenario for sharing• Suppose that in a text management system there

is a single object for each printable character• Then a book may contain thousands of references

to individual instances of the character class• Also, there may be many books overall, each

containing multiple references to instances of the character class

Page 6: Unit 12 Flyweight

6

• In this scenario it is the individual character objects that are the flyweights

• They are shared among different books and each book will have multiple references to them

• What characteristics the flyweights have and how to manage them are at the heart of the design pattern

Page 7: Unit 12 Flyweight

7

• Book definition:• The intent of the Flyweight pattern is to use

sharing to support large numbers of fine-grained objects efficiently.

• Comment mode on:• I believe that it would be preferable to say “large

numbers of references to fine-grained objects”, although there may also be a large number of objects

Page 8: Unit 12 Flyweight

8

Immutability

• Part of the introductory discussion mentioned the idea that if a shared object is changed, then potentially all clients should be notified

• Stated another way, a single action by one client can potentially affect many other clients

• This kind of dependence among the clients can be an undesirable kind of coupling

• Also, trying to notify many clients of changes can be onerous

Page 9: Unit 12 Flyweight

9

• Although it may diminish the usefulness of flyweights in certain applications, the problem can be solved by making the flyweights immutable

• This means that their implementation contains no method that allows them to be changed by a client

• References to them may be dropped• New instances with new values may be created• But an existing object cannot be changed• You are familiar with immutability through the Java

String class

Page 10: Unit 12 Flyweight

10

• Challenge 13.1• Provide a justification of why the creators of

Java made String objects immutable, or argue that this was an unwise restriction.

Page 11: Unit 12 Flyweight

11

• An argument for the immutability of strings:• In short, this is the book’s answer:• Strings are frequently shared• In other words, they are sort of like system

supplied flyweights• Therefore, to solve the flyweight problem, it

was a good thing to make them immutable

Page 12: Unit 12 Flyweight

12

• Comment mode on:• The book also touches on this argument, but not very

clearly• When you have objects with String instance variables,

how should you write the get methods for them?• In reality, you should return a clone• It violates encapsulation to return a reference• However, this problem is solved if the reference

returned is immutable

Page 13: Unit 12 Flyweight

13

• An argument against the immutability of strings:• In short, this is the book’s answer:• By definition, making strings immutable makes it impossible to

change them• This is an artificial limitation on strings that doesn’t apply to most

other objects• This means Java is less flexible and contains special cases that you

have to learn• The authors observe that no language can completely protect the

programmer from programming difficulties or making mistakes• If that’s the purpose of immutability, it’s a fool’s errand

Page 14: Unit 12 Flyweight

14

Extracting the Immutable Part of a Flyweight

• The starting point for this discussion is that we’re going to assume that if we use the Flyweight design pattern, the flyweights are going to be immutable

• The previous discussion explained why that is a desirable design choice

• The point of this section is that you have a design with lots of shared references which are not flyweights

• You want to refactor to a design that uses flyweights

Page 15: Unit 12 Flyweight

15

• Along with any other changes to the code, this will require redesigning the class with many references to it as a(n immutable) flyweight

• The goal is to extract out the immutable part of the class

• That will be the flyweight which has many references to it

• The rest of the class will have to be handled in a different way

Page 16: Unit 12 Flyweight

16

• The book bases its example on chemicals• In a fireworks factory, the ingredients are

chemical in nature• In the non-flyweight design, the ingredients

are referred to as substances• The following UML diagram shows the

substance class

Page 17: Unit 12 Flyweight

17

Page 18: Unit 12 Flyweight

18

• The Substance class has instance variables for name, symbol, atomicWeight, and grams

• A digression on terminology:• The instance variables symbol and

atomicWeight suggest that we’re talking about chemical elements

• An element has a symbol and an atomic weight

Page 19: Unit 12 Flyweight

19

• For what it’s worth, the following information is given by Wikipedia:

• The IUPAC definition[1] of atomic weight is:• An atomic weight (relative atomic mass) of an

element from a specified source is the ratio of the average mass per atom of the element to 1/12 of the mass of an atom of 12C.

Page 20: Unit 12 Flyweight

20

• It becomes apparent that the authors want to refer to chemical compounds as well as elements

• When they refer to a symbol, they don’t just mean a single symbol for an element

• They also mean the chemical formula for a compound

• Technically, they might also have referred to molecular weight, which is the equivalent for compounds of atomic weight for elements

Page 21: Unit 12 Flyweight

21

• In any case, some of the instance variables identify and give characteristics of chemical elements and compounds

• The instance variable gram is different• Grams are a measurement of mass (what we

poor benighted users of the English system think of as weight)

• In other words, grams are a measurement of a quantity of something

Page 22: Unit 12 Flyweight

22

• In short, the Substance class tells both what something is and how much of it there is

• Such a class invites decomposition into two parts

• The “what it is” part could be immutable• The “how much of it is there” part would be

mutable

Page 23: Unit 12 Flyweight

23

• The Substance class has get and set methods for its instance variables

• It also has a computed getMoles() method that returns the number of moles (6.02 x 1023 molecules (Avogadro’s number of molecules) in a given mass of an element or compound

• The next overhead shows how an instance of the Mixture class is based on having references to instances of the Substance class

Page 24: Unit 12 Flyweight

24

Page 25: Unit 12 Flyweight

25

• In the fireworks setting there could be many different mixtures that have to be modeled or represented

• This means that there would be many references to instances of the Substance class

• The instances of the substance class would differ according to the number of grams

• The information about a particular chemical element or compound would not differ

Page 26: Unit 12 Flyweight

26

• Challenge 13.2• Complete the class diagram in Figure 13.3 to

show a refactored Substance2 class and a new, immutable Chemical class.

Page 27: Unit 12 Flyweight

27

Page 28: Unit 12 Flyweight

28

• Solution 13.2• You can move the immutable aspects of

Substance—including its name, symbol, and atomic weight—into the Chemical class, as Figure B.17 shows.

Page 29: Unit 12 Flyweight

29

Page 30: Unit 12 Flyweight

30

• Solution 13.2, continued• The Substance2 class now maintains a reference

to a Chemical object.• As a result, the Substance2 class can still offer the

same accessors as the earlier Substance class.• Internally, these accessors rely on the Chemical

class, as the following Substance2 methods demonstrate.

• [See the next overhead.]

Page 31: Unit 12 Flyweight

31

• public double getAtomicWeight()• {• return chemical.getAtomicWeight();• }• public double getGrams()• {• return grams;• }• public double getMoles()• {• return grams / getAtomicWeight();• }

Page 32: Unit 12 Flyweight

32

Sharing Flyweights

• Extracting the immutable part of a class in order to create flyweights is just part of the task involved in applying the Flyweight pattern

• The book refers to creating a “flyweight factory”

• This is a foreshadowing of future chapters

Page 33: Unit 12 Flyweight

33

• The underlying idea is that there should be only one instance of a flyweight containing a certain set of values

• If this is the case, then applications can’t just create instances of the flyweight class willy-nilly

• The flyweight factory class controls the creation of flyweights and making them available for sharing by clients

Page 34: Unit 12 Flyweight

34

• For the chemical example the book proposes a ChemicalFactory class

• It will contain a static method that will return a reference to a chemical given its name

• Internally the factory class can store the different chemicals in a hash table, for example

Page 35: Unit 12 Flyweight

35

• Notice two things about this scenario• First• The flyweight isn’t a singleton—there are

multiple instances of it• However, there can be no duplicate instances• In other words, no two instances of a

flyweight should test equal for contents

Page 36: Unit 12 Flyweight

36

• Second• There is an implementation similarity between

the flyweight and the mediator• Recall that one of the example of the use of the

Mediator design pattern was maintaining relational integrity

• This was accomplished in part by wrapping a hash table in a class and then storing individual items as entities in the hash table

Page 37: Unit 12 Flyweight

37

• Not only is the similarity structural• In a real sense the flyweight factory is a specific

example of the mediator pattern• It maintains the list of chemicals• It is responsible for making the chemicals

available for sharing by client code• The UML diagram on the next overhead

illustrates the relationships between the ChemicalFactory class and the Chemical class

Page 38: Unit 12 Flyweight

38

Page 39: Unit 12 Flyweight

39

• Next the book shows code for the ChemicalFactory class

• The book makes use of what it calls a static initializer

• Basically this can be summarized as a block of code that is used to initialize an instance variable

• In this example there is an instance of HashMap and it is filled with instances of the chemical class

Page 40: Unit 12 Flyweight

40

• It would be possible to put the static initialization code into a constructor for a class that had instances

• Since the one method of interest in the ChemicalFactory class is static, its methods are not called on an instance

Page 41: Unit 12 Flyweight

41

• Another side note is this: An alternative to a class containing only static items would be a singleton class

• You would have to create the one instance of the singleton and then call real methods on that instance

• Partial code for the ChemicalFactory class is shown on the following overheads

Page 42: Unit 12 Flyweight

42

• import java.util.*;• public class ChemicalFactory• {• private static Map chemicals = new HashMap();• static • {• chemicals.put("carbon", new Chemical("Carbon", "C",

12));• chemicals.put("sulfur", new Chemical("Sulfur", "S",

32));• chemicals.put("saltpeter", new Chemical("Saltpeter",

"KN03", 101));• //...• }• public static Chemical getChemical(String name)• {• return (Chemical) chemicals.get(name.toLowerCase());• }• }

Page 43: Unit 12 Flyweight

43

• Developers should not create their instances of the chemical class

• They should only use the chemicals in the ChemicalFactory class

• Enforcing this discipline can be accomplished by controlling access to the Chemical class

Page 44: Unit 12 Flyweight

44

• Challenge 13.3• How can you use the accessibility of the

Chemical class to discourage other developers from instantiating Chemical objects?

Page 45: Unit 12 Flyweight

45

• Solution 13.3• 1. One way that won’t work is to make the

Chemical constructor private.• That would prevent the ChemicalFactory class

from instantiating the Chemical class• Comment mode on:• This is not a solution

Page 46: Unit 12 Flyweight

46

• 2. To help prevent developers from instantiating the Chemical class themselves, you could place Chemical and ChemicalFactory classes in the same package and give the Chemical class’s constructor default (“package”) access.

• Comment mode on:• To be charitable, this is a weak solution.• Lame might be a better word

Page 47: Unit 12 Flyweight

47

• You can prevent client code from creating instances of the Chemical class by making it an inner class of the ChemicalFactory class

• Note that client code would have to use the qualified class name when referring to an instance of the inner class

• You are familiar with this notation• An example is shown on the next overhead

Page 48: Unit 12 Flyweight

48

• ChemicalFactory.Chemical c = ChemicalFactory.getChemical(“saltpeter”);

Page 49: Unit 12 Flyweight

49

• The book suggests a refinement on this plan• Let the inner class be named ChemicalImpl,

short for ChemicalImplementation• Let there be an interface named Chemical• Let the inner class implement the interface• Then internal to the factory, instances of

ChemicalImpl are created

Page 50: Unit 12 Flyweight

50

• The getChemical() method of the factory is defined to return a reference of type Chemical

• Client code works with references of type Chemical

• In this way, the client never has to refer to the actual ChemicalImpl class

• The client never has to use a qualified name

Page 51: Unit 12 Flyweight

51

• As far as the client knows, it is simply dealing with chemicals

• It doesn’t have to know that chemicals are created as instances of a separate, inner class known as ChemicalImpl

• The Chemical interface is shown on the next overhead

• It simply has in it the accessor methods associated with chemicals all along

Page 52: Unit 12 Flyweight

52

• public interface Chemical• {• String getName();• String getSymbol();• double getAtomicWeight();• }

Page 53: Unit 12 Flyweight

53

• Challenge 13.4• Complete the following code for

ChemicalFactory2.java• Comment mode on:• The given incomplete code is kind of long• Since I always just show the answer anyway, I’m

skipping the incomplete code and just going to the answer, which is on the following overheads

Page 54: Unit 12 Flyweight

54

Note: If you’re making ChemicalImpl an Inner Class, Why Not Make it Private?

• import java.util.*;• public class ChemicalFactory2 • {• private static Map chemicals = new HashMap();

• class ChemicalImpl implements Chemical • {• private String name;• private String symbol;• private double atomicWeight;

• ChemicalImpl(String name, String symbol, double atomicWeight) • {• this.name = name;• this.symbol = symbol;• this.atomicWeight = atomicWeight;• }

Page 55: Unit 12 Flyweight

55

• public String getName() • {• return name;• }

• public String getSymbol()• {• return symbol;• }

• public double getAtomicWeight() • {• return atomicWeight;• }

• public String toString() • {• return name + "(" + symbol + ")[" + atomicWeight +

"]";• }• }

Page 56: Unit 12 Flyweight

56

• static • {• ChemicalFactory2 factory = new ChemicalFactory2();• chemicals.put("carbon", factory.new

ChemicalImpl("Carbon", "C", 12));• chemicals.put("sulfur", factory.new

ChemicalImpl("Sulfur", "S", 32));• chemicals.put("saltpeter", factory.new

ChemicalImpl("Saltpeter", "KN03", 101));• //...• }

• public static Chemical getChemical(String name) • {• return (Chemical) chemicals.get(name.toLowerCase());• }• }

Page 57: Unit 12 Flyweight

57

Summary

• The Flyweight pattern supports the sharing of one instance by many clients

• In the early discussion the book made it sound like immutability was a good idea

• The example illustrated immutability• The book now states clearly that a flyweight class

should be immutable• When refactoring, part of the process is

extracting the immutable part

Page 58: Unit 12 Flyweight

58

• The creation of instances of the flyweight should be created in a factory class

• The factory class should also manage the sharing of the flyweights

• An inner class (possibly with an interface) gives the factory a suitable level of control over the creation of instances of the flyweight

• A static method can be used to return references to the (immutable) flyweight objects

Page 59: Unit 12 Flyweight

59

• If the flyweight and the factory are correctly set up, you achieve these goals:

• Concretely, shared access is enabled• This shared access is safe and foolproof• Clients can’t create instances of their own

Page 60: Unit 12 Flyweight

60

• In a broader sense, the refactoring accomplishes this:

• You avoid a proliferation of many instances of a class

• More specifically, you avoid having many references to instances of a class

• More specifically yet, you avoid having shared references to mutable classes

Page 61: Unit 12 Flyweight

61

• By not having shared references to mutable classes, you avoid the problem that many clients would be coupled

• A change to the shared object by one of the clients would affect all of them

• Without the flyweight solution you would be confronted with the problem of how to notify/update all of the clients

Page 62: Unit 12 Flyweight

62

The End