Friday, February 28, 2014

Structural Design Patterns: Flyweight Design Pattern



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: