Skip to content

Flyweight

Last updated on March 14, 2023

he Flyweight Design Pattern is a structural pattern that allows efficient sharing of objects that are used repeatedly in an application. This pattern helps to reduce memory usage by creating a pool of objects and reusing them instead of creating new objects every time they are needed. In this article, we will explore the Flyweight Design Pattern and how it can be implemented in Swift.

Overview of Flyweight Design Pattern

The Flyweight Design Pattern is used when an application needs to create a large number of objects that have similar characteristics. The pattern aims to reduce the memory footprint of the application by sharing objects that have the same intrinsic properties. The intrinsic properties are the properties that are common among objects, and they can be stored in a shared object known as the flyweight object.

The flyweight object contains the intrinsic properties of the objects, and it is shared among the objects that have the same intrinsic properties. The non-intrinsic properties of the objects are stored in the context object, which is unique to each object.

Implementation of Flyweight Design Pattern in Swift

To implement the Flyweight Design Pattern in Swift, we can create a Flyweight protocol that defines the intrinsic properties of the objects, and a FlyweightFactory class that creates and manages the flyweight objects. We can also create a Context class that contains the non-intrinsic properties of the objects.

Here’s an example of how the Flyweight Design Pattern can be implemented in Swift:

protocol Flyweight {
    func operation(extrinsicState: String)
}

class ConcreteFlyweight: Flyweight {
    private var intrinsicState: String
    
    init(intrinsicState: String) {
        self.intrinsicState = intrinsicState
    }
    
    func operation(extrinsicState: String) {
        print("Intrinsic state: \(intrinsicState), Extrinsic state: \(extrinsicState)")
    }
}

class FlyweightFactory {
    private var flyweights = [String: Flyweight]()
    
    func getFlyweight(intrinsicState: String) -> Flyweight {
        if let flyweight = flyweights[intrinsicState] {
            return flyweight
        } else {
            let flyweight = ConcreteFlyweight(intrinsicState: intrinsicState)
            flyweights[intrinsicState] = flyweight
            return flyweight
        }
    }
}

class Client {
    private var flyweightFactory = FlyweightFactory()
    
    func doOperation(intrinsicState: String, extrinsicState: String) {
        let flyweight = flyweightFactory.getFlyweight(intrinsicState: intrinsicState)
        flyweight.operation(extrinsicState: extrinsicState)
    }
}

The code defines three main classes: Flyweight, ConcreteFlyweight, and FlyweightFactory. The Flyweight protocol defines the interface for the flyweight objects, which in this case only includes the operation method that takes an extrinsic state parameter. The ConcreteFlyweight class is a concrete implementation of the Flyweight protocol and includes an intrinsic state property that is set during initialization. The operation method implementation prints out both the intrinsic and extrinsic states of the object.

The FlyweightFactory class is responsible for creating and managing the flyweight objects. It maintains a dictionary of flyweights with their intrinsic states as keys. When a client requests a flyweight with a certain intrinsic state, the factory checks if a flyweight with that intrinsic state already exists in the dictionary. If it does, the factory returns that flyweight. If not, the factory creates a new ConcreteFlyweight object with the given intrinsic state, adds it to the dictionary, and returns it.

Finally, the Client class represents the client code that uses the flyweight objects. It has a reference to the FlyweightFactory and uses it to get flyweight objects with the appropriate intrinsic states. The doOperation method takes both intrinsic and extrinsic states as parameters, gets a flyweight with the given intrinsic state from the factory, and calls the operation method on that flyweight object, passing in the extrinsic state.

This implementation of the Flyweight Design Pattern in Swift demonstrates how flyweight objects can be shared and reused to reduce memory usage and improve performance, especially in situations where a large number of objects with similar intrinsic properties need to be created.

Advantages:

  1. Memory optimization: The Flyweight Design Pattern can significantly reduce the memory usage of an application by sharing objects that have the same intrinsic properties.
  2. Performance optimization: By reusing the flyweight objects, the Flyweight Design Pattern can improve the performance of an application.
  3. Simplifies complex systems: The Flyweight Design Pattern can simplify complex systems by reducing the number of objects that need to be managed.
  4. Encourages good coding practices: The Flyweight Design Pattern encourages good coding practices by promoting separation of concerns and reducing code duplication.

Disadvantages:

  1. Increased complexity: The Flyweight Design Pattern can increase the complexity of an application by introducing additional objects and layers of abstraction.
  2. Reduced flexibility: The Flyweight Design Pattern can reduce the flexibility of an application by requiring that the objects share certain properties.
  3. Limited applicability: The Flyweight Design Pattern is only applicable in situations where a large number of objects with similar intrinsic properties need to be created.

Best practises

  1. Identify the intrinsic and extrinsic properties of the objects: The first step in implementing the Flyweight Design Pattern is to identify the intrinsic properties of the objects that can be shared among multiple instances.
  2. Implement the Flyweight object: The Flyweight object should contain the intrinsic properties of the objects and should be shared among instances that have the same intrinsic properties.
  3. Implement the Context object: The Context object should contain the non-intrinsic properties of the objects and should be unique to each instance.
  4. Use a FlyweightFactory to manage the Flyweight objects: The FlyweightFactory should create and manage the Flyweight objects and should be responsible for sharing the objects among instances.
  5. Use the Flyweight Design Pattern in situations where a large number of objects with similar intrinsic properties need to be created: The Flyweight Design Pattern is most effective when used in situations where a large number of objects with similar intrinsic properties need to be created.
Published inDesign Pattern