xxxxxxxxxx
We can use flyweight pattern in following scenarios:
When we need a large number of similar objects that are unique in terms of only a few parameters and most of the stuffs are common in general.
We need to control the memory consumption by large number of objects – by creating fewer objects and sharing them across.
xxxxxxxxxx
// A Java program to demonstrate working of
// FlyWeight Pattern with example of Counter
// Strike Game
import java.util.Random;
import java.util.HashMap;
// A common interface for all players
interface Player
{
public void assignWeapon(String weapon);
public void mission();
}
// Terrorist must have weapon and mission
class Terrorist implements Player
{
// Intrinsic Attribute
private final String TASK;
// Extrinsic Attribute
private String weapon;
public Terrorist()
{
TASK = "PLANT A BOMB";
}
public void assignWeapon(String weapon)
{
// Assign a weapon
this.weapon = weapon;
}
public void mission()
{
//Work on the Mission
System.out.println("Terrorist with weapon "
+ weapon + "|" + " Task is " + TASK);
}
}
// CounterTerrorist must have weapon and mission
class CounterTerrorist implements Player
{
// Intrinsic Attribute
private final String TASK;
// Extrinsic Attribute
private String weapon;
public CounterTerrorist()
{
TASK = "DIFFUSE BOMB";
}
public void assignWeapon(String weapon)
{
this.weapon = weapon;
}
public void mission()
{
System.out.println("Counter Terrorist with weapon "
+ weapon + "|" + " Task is " + TASK);
}
}
// Class used to get a player using HashMap (Returns
// an existing player if a player of given type exists.
// Else creates a new player and returns it.
class PlayerFactory
{
/* HashMap stores the reference to the object
of Terrorist(TS) or CounterTerrorist(CT). */
private static HashMap <String, Player> hm =
new HashMap<String, Player>();
// Method to get a player
public static Player getPlayer(String type)
{
Player p = null;
/* If an object for TS or CT has already been
created simply return its reference */
if (hm.containsKey(type))
p = hm.get(type);
else
{
/* create an object of TS/CT */
switch(type)
{
case "Terrorist":
System.out.println("Terrorist Created");
p = new Terrorist();
break;
case "CounterTerrorist":
System.out.println("Counter Terrorist Created");
p = new CounterTerrorist();
break;
default :
System.out.println("Unreachable code!");
}
// Once created insert it into the HashMap
hm.put(type, p);
}
return p;
}
}
// Driver class
public class CounterStrike
{
// All player types and weapon (used by getRandPlayerType()
// and getRandWeapon()
private static String[] playerType =
{"Terrorist", "CounterTerrorist"};
private static String[] weapons =
{"AK-47", "Maverick", "Gut Knife", "Desert Eagle"};
// Driver code
public static void main(String args[])
{
/* Assume that we have a total of 10 players
in the game. */
for (int i = 0; i < 10; i++)
{
/* getPlayer() is called simply using the class
name since the method is a static one */
Player p = PlayerFactory.getPlayer(getRandPlayerType());
/* Assign a weapon chosen randomly uniformly
from the weapon array */
p.assignWeapon(getRandWeapon());
// Send this player on a mission
p.mission();
}
}
// Utility methods to get a random player type and
// weapon
public static String getRandPlayerType()
{
Random r = new Random();
// Will return an integer between [0,2)
int randInt = r.nextInt(playerType.length);
// return the player stored at index 'randInt'
return playerType[randInt];
}
public static String getRandWeapon()
{
Random r = new Random();
// Will return an integer between [0,5)
int randInt = r.nextInt(weapons.length);
// Return the weapon stored at index 'randInt'
return weapons[randInt];
}
}
xxxxxxxxxx
flyweight design pattern enables use sharing of objects to support large numbers of fine-grained objects efficiently.
A flyweight is a shared object that can be used in multiple contexts simultaneously.
The flyweight acts as an independent object in each context.
xxxxxxxxxx
using System;
using System.Collections.Generic;
// Flyweight interface
public interface IShape
{
void Draw(int x, int y);
}
// ConcreteFlyweight
public class Circle : IShape
{
private readonly string color;
public Circle(string color)
{
this.color = color;
}
public void Draw(int x, int y)
{
Console.WriteLine($"Drawing a {color} circle at ({x}, {y})");
}
}
// FlyweightFactory
public class ShapeFactory
{
private readonly Dictionary<string, IShape> flyweights = new Dictionary<string, IShape>();
public IShape GetShape(string color)
{
if (flyweights.TryGetValue(color, out var shape))
{
return shape;
}
shape = new Circle(color);
flyweights[color] = shape;
return shape;
}
}
class Program
{
static void Main()
{
// Client code
ShapeFactory shapeFactory = new ShapeFactory();
IShape redCircle = shapeFactory.GetShape("Red");
redCircle.Draw(100, 200);
IShape blueCircle = shapeFactory.GetShape("Blue");
blueCircle.Draw(300, 150);
IShape greenCircle = shapeFactory.GetShape("Green");
greenCircle.Draw(50, 50);
/*
* Sample Output:
* Drawing a Red circle at (100, 200)
* Drawing a Blue circle at (300, 150)
* Drawing a Green circle at (50, 50)
*/
}
}
xxxxxxxxxx
6. Flyweight:
The Flyweight pattern minimizes memory usage or computational expenses by sharing as much as possible with related objects.
Example in ReactJS:
Suppose you're rendering a large list of items with some common properties.
// Flyweight Component
const ListItem = ({ text }) => <li>{text}</li>;
// Usage
const App = () => {
const commonText = "This is a common text shared by multiple items.";
const items = Array.from({ length: 1000 }, (_, index) => (
<ListItem key={index} text={commonText} />
));
return (
<ul>
{items}
</ul>
);
};
xxxxxxxxxx
# Flyweight interface
class Font:
def render(self, text):
pass
# Concrete flyweight
class ConcreteFont(Font):
def __init__(self, font_name):
self.font_name = font_name
def render(self, text):
return f"Rendered '{text}' in '{self.font_name}' font."
# Flyweight factory
class FontFactory:
_fonts = {}
@staticmethod
def get_font(font_name):
if font_name not in FontFactory._fonts:
FontFactory._fonts[font_name] = ConcreteFont(font_name)
return FontFactory._fonts[font_name]
# Client
class TextEditor:
def __init__(self):
self.characters = []
self.font_factory = FontFactory()
def insert_character(self, char, font_name):
font = self.font_factory.get_font(font_name)
self.characters.append((char, font))
def display(self):
for char, font in self.characters:
print(font.render(char))
# Example usage
editor = TextEditor()
editor.insert_character('H', 'Arial')
editor.insert_character('i', 'Times New Roman')
editor.insert_character('!', 'Arial')
editor.display()