Skip to content

Instantly share code, notes, and snippets.

@robson-koji
Last active July 11, 2023 20:48
Show Gist options
  • Save robson-koji/351489d437a5966de5bae7b53b2e444c to your computer and use it in GitHub Desktop.
Save robson-koji/351489d437a5966de5bae7b53b2e444c to your computer and use it in GitHub Desktop.
Design Pattern - Flyweight

Flyweight

The Flyweight design pattern is a structural design pattern that focuses on optimizing memory usage by sharing data between multiple objects. It is useful when you need to create a large number of similar objects that share common properties.

The main idea behind the Flyweight pattern is to separate the intrinsic (shared) and extrinsic (unique) parts of an object. The intrinsic part is immutable and can be shared among multiple objects, while the extrinsic part varies and is stored externally.

A basic example

class Character:
    def __init__(self, char):
        self.char = char

    def display(self, font_size):
        print(f"Character: {self.char}, Font Size: {font_size}")


class CharacterFactory:
    def __init__(self):
        self.characters = {}

    def get_character(self, char):
        if char not in self.characters:
            self.characters[char] = Character(char)
        return self.characters[char]


# Client code
if __name__ == "__main__":
    character_factory = CharacterFactory()

    # Display characters using Flyweight pattern
    text = "Hello, World!"
    font_size = 12

    for char in text:
        character = character_factory.get_character(char)
        character.display(font_size)

Flyweight and Factory Pattern

While it is common to see the Flyweight pattern implemented together with the Factory pattern, it is not a strict requirement for Flyweight to always use a factory pattern. The primary goal of the Flyweight pattern is to share common, immutable parts of objects to conserve memory.

It is possible to implement Flyweight without a factory, especially in simpler scenarios where the creation and management of flyweight objects can be handled directly within the client code.

Flyweight in Real Scenario

A more complex example of the Flyweight pattern where the flyweight object receives an object and performs an operation that involves another complex object.

class Car:
    def __init__(self, make, model, color):
        self.make = make
        self.model = model
        self.color = color

    def display_details(self, owner, extra_object):
        print(f"Car: {self.make} {self.model} ({self.color}), Owned by: {owner}, Extra Object: {extra_object}")


class CarFlyweight:
    def __init__(self, car):
        self.car = car

    def display_details(self, owner, extra_object):
        self.car.display_details(owner, extra_object)


class CarFactory:
    def __init__(self):
        self.flyweights = {}

    def get_flyweight(self, make, model, color):
        key = (make, model, color)
        if key not in self.flyweights:
            car = Car(make, model, color)
            self.flyweights[key] = CarFlyweight(car)
        return self.flyweights[key]


# Client code
if __name__ == "__main__":
    car_factory = CarFactory()

    # Create flyweight objects with shared car state
    flyweight1 = car_factory.get_flyweight("Toyota", "Camry", "Blue")
    flyweight2 = car_factory.get_flyweight("Toyota", "Camry", "Blue")

    # Use the flyweight objects with additional objects
    owner1 = "John"
    extra_object1 = "Object A"
    flyweight1.display_details(owner1, extra_object1)

    owner2 = "Alice"
    extra_object2 = "Object B"
    flyweight2.display_details(owner2, extra_object2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment