Why should anyone use flyweight design pattern?
The Flyweight design pattern is a structural pattern that allows you to reduce the memory footprint of your application by minimizing the number of required objects. It’s useful when you have a large number of similar objects that share some common properties. In this article, we’ll explore the Flyweight pattern in detail and provide a Python example to illustrate its implementation.
What is the Flyweight Pattern?
The Flyweight pattern is a design pattern that aims to reduce the memory usage of an application by sharing common properties among multiple objects. It does this by separating the intrinsic and extrinsic properties of an object.
- Intrinsic Properties: These are the properties that define the object’s identity and are shared among multiple objects.
- Extrinsic Properties: These are the properties that are unique to each object and are not shared.
Components of the Flyweight Pattern
The Flyweight pattern consists of the following components:
- Flyweight: This is the interface or abstract class that defines the intrinsic properties of the object.
- Concrete Flyweight: This is the concrete implementation of the Flyweight interface.
- Unshared Concrete Flyweight: This is the concrete implementation of the Flyweight interface that has unique extrinsic properties.
- Flyweight Factory: This is the factory class that creates and manages the Flyweight objects.
Example
Let’s consider a simple example of a smartphone factory that produces smartphones with different properties like brand, model, color, and storage capacity. We can use the Flyweight pattern to optimize the memory usage of our application.
Python
from typing import List, Dict
class SmartPhone:
"""
Smartphone(Flyweight)
"""
def __init__(self, properties: List) -> None:
self._properties = properties
def sell(self, owner: str, price: int) -> None:
"""
Selling operation on smartphone(flyweight object)
which takes unique values per smartphone
"""
common = self._properties
print(f"Smartphone {common} is sold to {owner} for price {price}")
def __repr__(self) -> str:
return f'SmartPhone(properties={self._properties})'
class SmartPhoneFactory:
"""
Smartphone(flyweight) factory
"""
_smartphones: Dict[str, SmartPhone] = {}
def get_smartphone(self, properties: List) -> SmartPhone:
"""
Return smartphone(flyweight) object
This method creates new object and cache it if doesn't exist
"""
key = '-'.join(properties)
if key in self._smartphones:
print(f"Returning already existing Smartphone object for {properties}")
else:
print(f"New Smartphone object created for {properties}")
self._smartphones[key] = SmartPhone(properties)
return self._smartphones[key]
def list_smartphones(self) -> List[SmartPhone]:
"""
List down all the smartphones
"""
smartphones = self._smartphones.values()
for item in smartphones:
print(item)
if __name__ == '__main__':
fact = SmartPhoneFactory()
smartphone = fact.get_smartphone(['Apple', 'iPhone 14', 'Black', '128 GB'])
smartphone.sell('Hardik', 59000)
smartphone = fact.get_smartphone(['Apple', 'iPhone 13', 'Black', '128 GB'])
smartphone.sell('Aarav', 49000)
smartphone = fact.get_smartphone(['Samsung', 'Galaxy S23', 'White', '128 GB'])
smartphone.sell('Shailaja', 63000)
smartphone = fact.get_smartphone(['Apple', 'iPhone 14', 'Black', '128 GB'])
smartphone.sell('Aarav', 59000)
fact.list_smartphones()
In this example, we have a SmartPhone
class that represents the flyweight object, and a SmartPhoneFactory
class that acts as the factory to create and manage these objects. The SmartPhone
class has intrinsic properties like brand, model, color, and storage capacity, which are shared among multiple objects. The SmartPhoneFactory
class creates and caches the SmartPhone
objects to minimize memory usage.
Benefits of the Flyweight Pattern
The Flyweight pattern offers several benefits, including:
- Memory Optimization: By sharing common properties among multiple objects, the Flyweight pattern reduces the memory footprint of an application.
- Improved Performance: With fewer objects to manage, the application can perform better and faster.
- Simplified Object Management: The Flyweight pattern makes it easier to manage a large number of objects, as you only need to worry about the shared properties.
When to Use Flyweight
The Flyweight pattern is particularly useful in scenarios where:
- You have a large number of objects with similar properties.
- Memory usage is a concern.
- Objects have both intrinsic and extrinsic properties.
Conclusion
In conclusion, the Flyweight design pattern is a useful technique for optimizing memory usage in applications with a large number of similar objects. By separating intrinsic and extrinsic properties, Flyweight allows you to share common properties among multiple objects, reducing memory usage and improving performance.