Flyweight Design Pattern in R

1. Definition

The Flyweight Design Pattern aims to minimize memory usage by sharing as much data as possible with similar objects. It's a structural pattern that splits an object's state into intrinsic (shared) and extrinsic (unique) parts. Only the intrinsic data is shared.

2. Problem Statement

Suppose you're creating a simulation of a forest with millions of trees. Each tree would have attributes like type, age, height, and location. Storing every tree as a separate object would consume an immense amount of memory due to repeated data (e.g., type of tree).

3. Solution

Utilize the Flyweight Pattern. Instead of storing data like type (which would be similar for many trees) within the Tree object, store this shared data in a separate object and reuse it for all the trees of the same type. Only store unique data, like position, in the Tree object.

4. Real-World Use Cases

1. Text editors or word processors which store character formatting (like bold, italic) separately from the character itself.

2. Game environments where many objects, like soldiers or trees, have shared states and graphics.

3. Any application where performance optimization is critical, and objects have shared states.

5. Implementation Steps

1. Identify the common (intrinsic) and unique (extrinsic) parts of the class.

2. Create a factory that caches and reuses instances of the class based on intrinsic state.

6. Implementation in R Programming

# Flyweight object
TreeType <- function(name, color) {
  list(
    name = name,
    color = color,
    display = function(x, y, age) {
      return(paste("Tree of type", name, "and color", color, "at position", x, y, "of age", age))
    }
  )
}
# Flyweight factory
TreeFactory <- function() {
  types <- list()
  list(
    getTreeType = function(name, color) {
      if (!name %in% names(types)) {
        types[[name]] <- TreeType(name, color)
      }
      return(types[[name]])
    }
  )
}
# Client code
forest <- list()
factory <- TreeFactory()
pine <- factory$getTreeType("Pine", "Green")
forest[[1]] <- list(treeType = pine, x = 10, y = 20, age = 5)
oak <- factory$getTreeType("Oak", "DarkGreen")
forest[[2]] <- list(treeType = oak, x = 5, y = 15, age = 100)
output <- sapply(1:length(forest), function(i) {
  tree <- forest[[i]]
  tree$treeType$display(tree$x, tree$y, tree$age)
})

Output:

[1] "Tree of type Pine and color Green at position 10 20 of age 5"
[2] "Tree of type Oak and color DarkGreen at position 5 15 of age 100"

Explanation:

1. We began by creating a TreeType object, representing a type of tree with shared data (name and color).

2. The TreeFactory manages the creation and sharing of the TreeType objects. It uses a cache (the types list) to store and retrieve the shared objects.

3. In the client code, we used the factory to create and/or retrieve TreeType objects and then stored unique data like position and age separately.

4. When displaying, the shared data is combined with the unique data.

7. When to use?

Use the Flyweight Pattern when:

1. An application uses a large number of objects which makes a heavy use of memory.

2. Object's state can be externalized and shared among multiple objects.

3. Application doesn't rely on object identity. Shared flyweights should be immutable.

Flyweight is all about optimizing memory usage and performance by sharing data.


Comments