Flyweight
pattern
must, “Use sharing to support large numbers of fine-grained objects
efficiently.”
Flyweight pattern is primarily used
to reduce the number of objects created, to decrease memory footprint and
increase performance.
As per GOF design patterns, Facilitates the reuse of many fine grained objects,
making the utilization of large numbers of objects more efficient.
A flyweight is an object that minimizes memory
use by sharing
as much data as possible with other similar objects;
Flyweight pattern try to reuse
already existing similar kind objects by storing them and creates new object
when no matching object is found. It used to share large number of objects in
an efficient way.
The
intent of this pattern is to use sharing to support a large number of objects
that have part of their internal state in common where the other part of state
can vary.
The
object which we are going to create in high number should be analyzed before
going for flyweight. Idea is to create lesser number of objects by reusing the
same objects. Create smaller groups of objects and they should be reused by
sharing. Closely look at objects properties and they can be segregated as two
types intrinsic and extrinsic. Sharing is judged with respect to a context.
Flyweight
Implementation
The object with intrinsic state is called
flyweight object. When we implement flyweight we create concrete objects and
have the intrinsic state stored in that. To create those concrete objects we
will have factory and that is called Flyweight factory. This factory is to
ensure that the objects are shared and we don’t end up creating duplicate
objects.
The
Flyweight pattern describes how to share objects to allow their use at fine granularity without prohibitive cost. Each "flyweight" object is
divided into two pieces: the state-dependent (extrinsic) part, and the
state-independent (intrinsic) part. Intrinsic state is stored (shared) in the
Flyweight object. Extrinsic state is stored or computed by client objects, and
passed to the Flyweight when its operations are invoked.
Example
1: The classic example
of the Flyweight pattern is the representation of a character in a word
processor. Rather than each character having separate glyph objects that
represent the font and formatting data, each character could have a reference to
a flyweight glyph object shared by every instance of the same character in the
document. In this case, the character need only store it's position in the
document, rather than it's entire formatting information.
Example
2: The
Flyweight uses sharing to support large numbers of objects efficiently. The
public switched telephone network is an example of a Flyweight. There are
several resources such as dial tone generators, ringing generators, and digit
receivers that must be shared between all subscribers. A subscriber is unaware
of how many resources are in the pool when he or she lifts the handset to make
a call. All that matters to subscribers is that a dial tone is provided, digits
are received, and the call is completed.
Example
3:
To simplify the student-tracking
code, you decide to have one configurable Flyweight object named Student. This
object has to be configurable to look like as many students as needed, so you
have to add getter/setter methods to get and set data, such as the student’s
name, ID, and test score.
1: public class Student {
2: String name;
3: int id;
4: int score;
5: double averageScore;
6: public Student(double averageScore) {
7: this.averageScore = averageScore;
8: }
9: /* Note the getStanding method at the very end of this code, which returns the percentage by which the student’s score differs from the average score. */
10: public double getStanding() {
11: return (((double) score) / averageScore - 1.0) * 100.0;
12: }
13: public String getName() {
14: return name;
15: }
16: public void setName(String name) {
17: this.name = name;
18: }
19: public int getId() {
20: return id;
21: }
22: public void setId(int id) {
23: this.id = id;
24: }
25: public int getScore() {
26: return score;
27: }
28: public void setScore(int score) {
29: this.score = score;
30: }
31: public double getAverageScore() {
32: return averageScore;
33: }
34: public void setAverageScore(double averageScore) {
35: this.averageScore = averageScore;
36: }
37: }
1: public class TestFlyweight {
2: public static void main(String[] args) {
3: String names[] = {"Ralph", "Alice", "Sam"};
4: int ids[] = {1001, 1002, 1003};
5: int scores[] = {45, 55, 65};
6: double total = 0;
7: for (int loopIndex = 0; loopIndex < scores.length; loopIndex++){
8: total += scores[loopIndex];
9: }
10: double averageScore = total / scores.length;
11: Student student = new Student(averageScore);
12: for (int loopIndex = 0; loopIndex < scores.length; loopIndex++){
13: student.setName(names[loopIndex]);
14: student.setId(ids[loopIndex]);
15: student.setScore(scores[loopIndex]);
16: System.out.println("Name: " + student.getName());
17: System.out.println("Standing: " +
18: Math.round(student.getStanding()));
19: System.out.println(" ");
20: }
21: }
22: }
Running this code gives you the
desired results — the flyweight object is configured for each student
on-the-fly, and his or her standing, expressed as a percentage offset from the
average score, is displayed.
Output as below :
Name: Ralph
Standing: -18
Name: Alice
Standing: 0
Name: Sam
Standing: 18
So
instead of three full objects, you need only one configurable object. Much like
the Singleton pattern, the idea behind the Flyweight pattern is to control object
creation and limit the number of objects you need.
Example
4:
We're going to create a Shape
interface and concrete class Circle implementing the Shape
interface. A factory class ShapeFactory is defined as a next step. ShapeFactory
have a HashMap of Circle having key as color of the Circle
object. Whenever a request comes to create a circle of particular color to ShapeFactory.
ShapeFactory checks the circle object in its HashMap, if object
of Circle found, that object is returned otherwise a new object is
created, stored in hashmap for future use and returned to client.
1: public interface Shape {
2: public void draw();
3: }
Create concrete class implementing
the same interface.
1: public class Circle implements Shape {
2: private String color;
3: private int x;
4: private int y;
5: private int radius;
6: public Circle(String color){
7: this.color = color;
8: }
9: @Override
10: public void draw() {
11: System.out.println("Circle: Draw() [Color : " + color
12: +", x : " + x +", y :" + y +", radius :" + radius);
13: }
14: public void setX(int x) {
15: this.x = x;
16: }
17: public void setY(int y) {
18: this.y = y;
19: }
20: public void setRadius(int radius) {
21: this.radius = radius;
22: }
23: }
Create a Factory to generate object
of concrete class based on given information.
1: public class ShapeFactory {
2: private static final HashMap<String, Shape> circleMap = new HashMap<String, Shape>();
3: public static Shape getCircle(String color) {
4: Circle circle = (Circle)circleMap.get(color);
5: if(circle == null) {
6: circle = new Circle(color);
7: circleMap.put(color, circle);
8: System.out.println("Creating circle of color : " + color);
9: }
10: return circle;
11: }
12: }
Use the Factory to get object of
concrete class by passing an information such as color.
1: public class FlyweightPatternDemo {
2: private static final String colors[] =
3: { "Red", "Green", "Blue", "White", "Black" };
4: public static void main(String[] args) {
5: for(int i=0; i < 20; ++i) {
6: Circle circle =
7: (Circle)ShapeFactory.getCircle(getRandomColor());
8: circle.setX(getRandomX());
9: circle.setY(getRandomY());
10: circle.setRadius(100);
11: circle.draw();
12: }
13: }
14: private static String getRandomColor() {
15: return colors[(int)(Math.random()*colors.length)];
16: }
17: private static int getRandomX() {
18: return (int)(Math.random()*100 );
19: }
20: private static int getRandomY() {
21: return (int)(Math.random()*100);
22: }
23: }
Creating
circle of color : Green
Circle: Draw() [Color : Green, x
: 49, y :92, radius :100
Creating
circle of color : Red
Circle: Draw() [Color : Red, x :
91, y :42, radius :100
Circle: Draw() [Color : Red, x :
77, y :16, radius :100
Creating
circle of color : Blue
Circle: Draw() [Color : Blue, x :
81, y :69, radius :100
Circle: Draw() [Color : Green, x
: 23, y :70, radius :100
Circle: Draw() [Color : Red, x :
34, y :31, radius :100
Creating
circle of color : Black
Circle: Draw() [Color : Black, x
: 9, y :16, radius :100
Circle: Draw() [Color : Red, x :
27, y :92, radius :100
Circle: Draw() [Color : Black, x
: 3, y :66, radius :100
Circle: Draw() [Color : Blue, x :
47, y :5, radius :100
Circle: Draw() [Color : Green, x
: 69, y :26, radius :100
Circle: Draw() [Color : Green, x
: 74, y :52, radius :100
Creating
circle of color : White
Circle: Draw() [Color : White, x
: 71, y :98, radius :100
Circle: Draw() [Color : Blue, x :
20, y :82, radius :100
Circle: Draw() [Color : Black, x
: 62, y :92, radius :100
Circle: Draw() [Color : Red, x :
48, y :17, radius :100
Circle: Draw() [Color : Green, x
: 31, y :86, radius :100
Circle: Draw() [Color : Green, x
: 87, y :5, radius :100
Circle: Draw() [Color : Black, x
: 82, y :25, radius :100
Circle: Draw() [Color : Red, x :
17, y :84, radius :100
Only 4 objects are created if the object already present with the
same color then here we avoided to create new object with same type.
Notes :
1) The Singleton pattern
lets you make sure that no matter how many times your code tries to create an
object from a specific class, only one such object is created. That’s important
in case you’ve got an object that is so sensitive that conflicts The Flyweight pattern is similar to the
Singleton pattern. Here, however, the idea is that if your code uses many large
objects using up system resources — you can fix things by using a smaller set
of template objects that can be configured on-the-fly to look like those larger
objects. The configurable objects — the flyweights — are smaller and reusable
(so there are fewer of them), but after being configured, they will appear to
the rest of your code as though you still have many large objects.
2)
Would I Use
This Pattern?
1) Many similar
objects are used and the storage cost is high
2) The majority of
each object's state data can be made extrinsic
3) A few shared
objects would easily replace many unshared objects
4) The identity of
each object does not matter
3) Flyweight
shows how to make lots of little objects, Facade shows how to make a single
object represent an entire subsystem.
4) Flyweight
is often combined with Composite to implement shared leaf nodes.
5) The only way I can
see flyweight pattern can be beneficial in this setting is when shareable
representational aspects are made intrinsic, and almost everything belonging to
an article data/metadata is extrinsic. This means, category, being article
metadata (if I understood correctly) should not be intrinsic. But it is
probably bad thing to combine representation and core object in one class
anyway, so breaking into "view class" and "content class"
is naturally there (not even sure it can be considered as applying flyweight
pattern).
No comments:
Post a Comment