knowledge/technology/programming/patterns/structural/Flyweight Pattern.md
2023-12-04 11:02:23 +01:00

4.2 KiB

obj
concept

Flyweight Pattern

Description:

The Flyweight Pattern is a structural design pattern that is used to minimize memory usage or computational expenses by sharing as much as possible with related objects. It is particularly useful when you need to create a large number of similar objects efficiently and the objects have common, intrinsic (shared) properties and extrinsic (unique) properties that can be separated.

How it's Used:

  1. Identify Shared and Non-Shared Parts: Identify the parts of objects that can be shared among multiple instances (intrinsic state) and the parts that must remain unique to each instance (extrinsic state).
  2. Flyweight Factory: Create a flyweight factory that manages a pool of shared flyweight objects. The factory is responsible for creating and maintaining the flyweight objects.
  3. Flyweight Interface: Define a flyweight interface that declares methods for accessing and manipulating the intrinsic state.
  4. Concrete Flyweight Classes: Create concrete flyweight classes that implement the flyweight interface and represent the shared intrinsic state.
  5. Client Code: In your client code, use the flyweight factory to obtain flyweight objects. For the extrinsic state (unique to each object), pass it as a parameter when requesting a flyweight object.

Example:

Consider a text editor where you want to efficiently represent and display a large number of characters. Most characters share common properties like font, size, and color, while their positions and content are unique. Here's how the Flyweight Pattern can be applied:

  • Flyweight Interface: Define a Character interface that represents the common properties of characters.
public interface Character {
    void display(int positionX, int positionY);
}
  • Concrete Flyweight Class: Create a concrete flyweight class SharedCharacter that implements the Character interface and represents the shared intrinsic state (font, size, color).
public class SharedCharacter implements Character {
    private char symbol;
    private Font font;
    private int size;
    private Color color;

    public SharedCharacter(char symbol, Font font, int size, Color color) {
        this.symbol = symbol;
        this.font = font;
        this.size = size;
        this.color = color;
    }

    @Override
    public void display(int positionX, int positionY) {
        System.out.println("Symbol: " + symbol +
                           ", Font: " + font.getName() +
                           ", Size: " + size +
                           ", Color: " + color +
                           ", Position: (" + positionX + ", " + positionY + ")");
    }
}
  • Flyweight Factory: Create a flyweight factory CharacterFactory that manages a pool of shared flyweight objects.
import java.util.HashMap;
import java.util.Map;

public class CharacterFactory {
    private Map<Character, Character> characterPool = new HashMap<>();

    public Character getCharacter(char symbol, Font font, int size, Color color) {
        Character sharedCharacter = new SharedCharacter(symbol, font, size, color);
        characterPool.put(symbol, sharedCharacter);
        return sharedCharacter;
    }
}
  • Client Code: In your client code, use the CharacterFactory to obtain flyweight objects and pass the unique extrinsic state (position) as a parameter when displaying characters.
public class Client {
    public static void main(String[] args) {
        CharacterFactory characterFactory = new CharacterFactory();

        // Display characters at different positions with shared properties
        Character charA = characterFactory.getCharacter('A', Font.BOLD, 12, Color.BLACK);
        charA.display(10, 20);

        Character charB = characterFactory.getCharacter('B', Font.ITALIC, 14, Color.RED);
        charB.display(30, 40);
    }
}

By using the Flyweight Pattern, you efficiently represent a large number of characters while sharing common properties, thus reducing memory usage. The extrinsic state (position) remains unique to each character instance, and the pattern helps manage shared and non-shared aspects effectively. This pattern is especially valuable in scenarios where many objects have a significant amount of shared state.