CHAPTER 16

image

Flyweight Patterns

GoF Definition: Use sharing to support large numbers of fine-grained objects efficiently.

Concept

A flyweight is an object through which we try to minimize memory usage by sharing data as much as possible. Two common terms are used here—intrinsic state and extrinsic state. The first category (intrinsic) can be stored in the flyweight and is shareable. The other one depends on the flyweight’s context and is non-shareable. Client objects need to pass the extrinsic state to the flyweight.

Real-Life Example

In all real-world business applications, we want to avoid storing similar objects. The concept of this pattern is applicable in those places. I’ll also share a story with you: a few years ago, two of my friends were each searching for an apartment to stay nearby their office. However, neither of them was satisfied with the available options. Then, one day, they found a place with all kind of facilities that they both desired. But there were two constraints—first of all, there was only one apartment, and second, the rent was high. So, to avail themselves of all those facilities, they decided to stay together and share the rent. This can be considered a real-life example of the flyweight pattern.

Computer World Example

The graphical representation of characters in word processors is a common example of this pattern. Also, we can think of a computer game where we have a large number of participants whose looks are same but who differ from each other in their performances (or color, dresses, weapons, etc.). We can use the flyweight pattern in all those scenarios.

Illustration

Please go through the code with the comments for your ready reference for an implementation of this pattern. Note that, we’ll not create any new object (here, small or large robots) if we have created such a type already. If we have at least one instance of our desired object, we’ll reuse that object from this point onward.

UML Class Diagram

9781484218013_unFig16-01.jpg

Package Explorer view

High-level structure of the parts of the program is as follows:

9781484218013_unFig16-02.jpg

Implementation

package flyweight.pattern.demo;
import java.util.HashMap;
import java.util.Map;

/**
 * @author sarcarv
 * Our interface
 *
 */
interface IRobot
{
        void Print();
}

/**
 * @author sarcarv
 * A ’ConcreteFlyweight’ class-SmallRobot
 *
 */
class SmallRobot implements IRobot
{
        @Override
        public void Print()
        {
                System.out.println(" This is a Small Robot");
        }
}

/**
 * @author sarcarv
 * A ’ConcreteFlyweight’ class-LargeRobot
 *
 */
class LargeRobot implements IRobot
{
        @Override
        public void Print()
        {
                System.out.println(" I am a Large Robot");
        }
}

/**
 * @author sarcarv
 * The ’FlyweightFactory’ class
 *
 */
class RobotFactory
{
        Map<String, IRobot> shapes = new HashMap<String, IRobot>();

        public int TotalObjectsCreated()
        {
                return shapes.size();
        }

        public IRobot GetRobotFromFactory(String RobotCategory) throws Exception
        {
                IRobot robotCategory = null;
                if (shapes.containsKey(RobotCategory))
                {
                        robotCategory = shapes.get(RobotCategory);
                }
                else
                {
                        switch (RobotCategory)
                        {
                        case "small":
                                System.out.println("We do not have Small Robot. So we are creating a Small Robot now.");
                                robotCategory = new SmallRobot();
                                shapes.put("small", robotCategory);
                                break;
                        case "large":
                                System.out.println("We do not have Large Robot. So we are creating a Large Robot now .");
                                robotCategory = new LargeRobot();
                                shapes.put("large", robotCategory);
                                break;
                        default:
                                throw new Exception(" Robot Factory can create only small and large shapes");
                        }
                }
                return robotCategory;
        }

}
/**
 * @author sarcarv
 *FlyweightPattern is in action.
 */

class FlyweightPatternEx
{
        public static void main(String[] args) throws Exception
        {
                RobotFactory myfactory = new RobotFactory();
                System.out.println(" ***Flyweight Pattern Example*** ");

                IRobot shape = myfactory.GetRobotFromFactory("small");
                shape.Print();
                /*Here we are trying to get the objects additional 2 times. Note that from now onward we do not need to create additional small robots as we have already created this category*/
                for (int i = 0; i < 2; i++)
                {
                        shape = myfactory.GetRobotFromFactory("small");
                        shape.Print();
                }
                int NumOfDistinctRobots = myfactory.TotalObjectsCreated();
                System.out.println(" Distinct Robot objects created till now= "+ NumOfDistinctRobots);

                /*Here we are trying to get the objects 5 times. Note that the second time onward we do not need to create additional large robots as we have already created this category in the first attempt(at i=0)*/
                for (int i = 0; i < 5; i++)
                {
                        shape = myfactory.GetRobotFromFactory("large");
                        shape.Print();
                }

                NumOfDistinctRobots = myfactory.TotalObjectsCreated();
                System.out.println(" Finally no of Distinct Robot objects created: "+ NumOfDistinctRobots);
        }
}

Output

9781484218013_unFig16-03.jpg

Improvement to the program

Now take a closer look to our program. Here it seems that this pattern is behaving similar to a singleton pattern because we cannot create two distinct types of small (or large) robots. But there may be situations where we want different types of small (or large) robots in which the basic structure should be same but it will differ only with some special characteristics. So, we are going to present another example here. This illustration will clear your doubt and you can make the distinction between the flyweight and the singleton patterns.

To make the program simple, we are dealing with robots which can be either king type or queen type. Each of these types can be either green or red. Before making any robot, we’ll consult with our factory. If we already have king or queen types of robots, we’ll not create them again. We will collect the basic structure from our factory and after that we’ll color them. Note that color is extrinsic data here, but the category of robot (king or queen) is intrinsic.

UML Class Diagram

9781484218013_unFig16-04.jpg

Package Explorer view

9781484218013_unFig16-05.jpg

Implementation

package flyweight.pattern.modified.demo;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author sarcarv
 * Our interface
 *
 */
interface IRobot
{
        void Print();
}

/**
 * @author sarcarv
 * A ’ConcreteFlyweight’ class-SmallRobot
 *
 */
class Robot implements IRobot
{
        String robotType;
        public String colorOfRobot;
        public Robot(String robotType)
        {
                this.robotType=robotType;
        }
        public void setColor(String colorOfRobot)
        {
                this.colorOfRobot=colorOfRobot;
        }
        @Override
        public void Print()
        {
                System.out.println(" This is a " +robotType+ " type robot with "+colorOfRobot+ "color");
        }
}

/**
 * @author sarcarv
 * The ’FlyweightFactory’ class
 *
 */
class RobotFactory
{
        Map<String, IRobot> shapes = new HashMap<String, IRobot>();

        public int TotalObjectsCreated()
        {
                return shapes.size();
        }

        public IRobot GetRobotFromFactory(String robotType) throws Exception
        {
                IRobot robotCategory= null;
                if (shapes.containsKey(robotType))
                {
                        robotCategory = shapes.get(robotType);
                }
                else
                {
                        switch (robotType)
                        {
                        case "King":
                                System.out.println("We do not have King Robot. So we are creating a King Robot now.");
                                robotCategory = new Robot("King");
                                shapes.put("King",robotCategory);
                                break;
                        case "Queen":
                                System.out.println("We do not have Queen Robot. So we are creating a Queen Robot now.");
                                robotCategory = new Robot("Queen");
                                shapes.put("Queen",robotCategory);
                                break;
                        default:
                                throw new Exception(" Robot Factory can create only king and queen type robots");
                        }
                }
                return robotCategory;
        }

}
/**
 * @author sarcarv
 *FlyweightPattern is in action.
 */

class FlyweightPatternModifiedEx
{
        public static void main(String[] args) throws Exception
        {
                RobotFactory myfactory = new RobotFactory();
                System.out.println(" ***Flyweight Pattern Example Modified*** ");
        Robot shape;
                /*Here we are trying to get 3 king type robots*/
                for (int i = 0; i < 3; i++)
                {
                        shape =(Robot) myfactory.GetRobotFromFactory("King");
                        shape.setColor(getRandomColor());
                        shape.Print();
                }
                /*Here we are trying to get 3 queen type robots*/
                for (int i = 0; i < 3; i++)
                {
                        shape =(Robot) myfactory.GetRobotFromFactory("Queen");
                        shape.setColor(getRandomColor());
                        shape.Print();
                }
                int NumOfDistinctRobots = myfactory.TotalObjectsCreated();
                //System.out.println(" Distinct Robot objects created till now = "+ NumOfDistinctRobots);
                System.out.println(" Finally no of Distinct Robot objects created: "+ NumOfDistinctRobots);
        }
        static String getRandomColor()
        {
                Random r=new Random();
                /*You can supply any number of your choice in nextInt argument.
                 * we are simply checking the random number generated is an even number
                 * or an odd number. And based on that we are choosing the color. For simplicity, we’ll use only two colors—red and green
                 */
                int random=r.nextInt(20);
                if(random%2==0)
                {
                        return "red";
                }
                else
                {
                        return "green";
                }
        }
}

Output

9781484218013_unFig16-06.jpg

Note

  1. Minimization of storage is one of the key concerns here. If we can have more flyweights to share, we can save more memory.
  2. If we can compute extrinsic states rather than storing them, we can save a significant amount of memory.
  3. Sometimes in a tree structure, to share leaf nodes, we combine this pattern with composite pattern.
  4. A flyweight interface may or may not enable sharing. In some cases, we may have unshared flyweight objects, which in turn may have concrete flyweight objects as children.
  5. In simple terms: intrinsic data make the instance unique, whereas extrinsic data are passed as arguments.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.122.244