Share This Article
The Flyweight pattern in Ruby is a software design pattern used to minimize memory usage by sharing as much data as possible. It is often used with other data structures, such as hash tables and trees.
The idea behind the flyweight pattern is to store data in a way that minimizes the amount of memory required. The data is stored in a way that allows data to be shared between different objects.
For example, consider a word processor that has a document with the following text:
“The quick brown fox jumps over the lazy dog”.
If we were to store this text traditionally, we would create a separate object for each character. This would require us to store each character in a particular object, using more memory than necessary.
Instead, we can store each character in a shared data structure with the flyweight pattern.
We can create a flyweight object for each unique personality and store this object in a hash table. When we need to display the text, we can look up each character in the hash table and say it.
This will use less memory because we are only storing each character once.
The downside of this approach is that it is more complex and can be slower because we need to look up each character in the hash table.
Flyweight Implementation in Ruby
Let’s try to implement the flyweight pattern in Ruby.
We will create a flyweight object for each unique character in a given string.
The flyweight object will store the character and a count of how many times it appears in the string.
We will store the flyweight objects in a hash table.
require "ostruct"
class Flyweight
def initialize
@store = Hash.new { |h, k| h[k] = OpenStruct.new(char: k, count: 0) }
end
def get_object(char)
@store[char].tap { |o| o.count += 1 }
end
def print
@store.values.each do |o|
puts "#{o.char}: #{o.count}"
end
end
end
# usage
text = "The quick brown fox jumps over the lazy dog"
flyweight = Flyweight.new
text.each_char { |c| flyweight.get_object(c) }
flyweight.print
# outputs
# T: 1
# h: 2
# e: 3
# : 4
# q: 1
# u: 2
# i: 1
#...
# memory usage
puts flyweight.instance_variable_get(:@store).size
# 26 (one object for each unique character in the text)
As you can see, this code is pretty simple.
The Flyweight
class has a get_object
method to get a flyweight object for a given character.
The get_object
method will look up the character in a hash table, and if it doesn’t exist, it will create a new flyweight object and store it in the hash table.
The print
method is used to print the flyweight objects.
This code will use less memory than storing each character in a separate object. But it is more complex and can be slower because of the hash table lookup.
Flyweight Pros
The main pro for using flyweight is the reduction of memory usage.
We use less memory because our flyweight objects store only the essential data.
Flyweight Cons
The main negative of using a flyweight pattern is the access to the data.
Remember that our flyweight class only stores the data, not the methods.
This data must be stored only in the flyweight’s essentials
data (state).
Your interface to the outside world will either use getters and setters or expose the raw data.
Another negative of using a flyweight is that it only makes sense to use it if you have a large number of objects.
If you have a small number of objects, it won’t make much difference in terms of memory usage.