Title: Flyweight Pattern
1Flyweight Pattern
- David Brigada
- Matt LaPlante
2Flyweight Pattern
- All elements of an object consume memory.
- Objects themselves typically have memory
requirements. - When there are only a few objects, we can afford
to store each object independently. - When objects number in the thousands or more,
independent objects become extremely costly.
3Flyweight Pattern
- If many objects share common elements, we can use
Flyweight to reduce the burden. - By simultaneously sharing a common element, each
object can avoid storing independent copies of
the same data, saving large amounts of memory.
4Flyweight Pattern
- The Flyweight refers to a common element shared
between many objects. - Although only stored once, the flyweight is
treated by each object as being exclusive to that
object. - Flyweight is a structural design pattern.
5Flyweight Pattern
- A Few Rules
- The flyweight cannot be modified from its
original state (its static). - The flyweight should never assume information
about how it will be called (it should be context
independent).
6Flyweight Pattern
- A popular example involves a word processing
application. - The Problem
- Consider the amount of memory required to store a
page of text if each character stored its own
information regarding character, font, size, etc.
7Flyweight Pattern
- The Answer
- Instead, we make a flyweight element for each
character. Those elements are then referenced,
every time we need a given letter. - We store the entire alphabet only once, rather
than storing thousands of copies of the same
letters.
8Generic UML for Flyweight
9Code Example
- Here is an implementation of Conways Game of
Life in C - Life is a cellular automaton simulation that
occurs on a grid. - Each turn, the grid is recalculated.
- If a cell that is currently living is surrounded
by 2-3 living cells, it stays living. - If a dead cell is surrounded by exactly 3 living
cells, a new cell is born. - The grid can contain thousands or millions of
entries
10Life Example
- Blue cells are currently alive
- Number shows count of neighbors
11Implementation
- Flyweights are used to keep track of the state of
each cell in the grid. - Each turn, the program runs through each cell and
updates the cells next state. - Once the whole grid is updated, the program
propagates the next state value to the current
state value, and displays the result.
12Initialization Main Loop
- The code shown here is the relevant part to
flyweight, most of the code is omitted. Full
code will be on WebCT.
int main(int argc, char argv) / Initialize
grid with given size / ggrid(nr, nc) for
() / Ad infinitum ... / g.show_grid() /
Display grid / getchar() / Wait for key
press / g.do_round() / Simulate a round
/
13Cell Class
- The cell class is the flyweight class. It stores
the current and next states. All other data
related to the class is deduced based on context.
- class cell
- private
- bool current
- bool next
- int count(cellcontext c) const
- public
- cell(bool cur, bool nxt) current(cur),
next(nxt) - void update(context c)
- void flip(void)
- bool get_current_state(void) const return
current
14Cell Context
- class cell
- public
- struct context
- grid g
- int row
- int col
-
- The cellcontext subclass encapsulates the
context that the flyweight needs to perform the
rest of its operations. Namely, this is a
pointer to the grid holding the other cells, and
this cells row and column.
15Grid Class internals
- / The grid holds the pointers to the cell
objects (flyweights) / - class grid
- private
- int n_rows / Rows in grid /
- int n_cols / Columns in grid /
- / Array that points to the flyweight objects
/ - cell cells
- / Point to the concrete flyweights /
- cell flyweight_ff
- cell flyweight_ft
- cell flyweight_tf
- cell flyweight_tt
- / Get the array offset /
- int index(int row, int col) const return
n_colsrow col
16Grid Class public methods
- public
- / Constructor and destructor /
- grid(int rows, int cols)
- grid(void)
- / Lookup current cell's state /
- bool is_current(int row, int col) const
- / Update cell with new state /
- void update_cell(int row, int col, bool cur,
bool next) - / Calculate a round /
- void do_round(void)
- / Display the grid /
- void show_grid(void) const
- / Set a cell to a specific value /
- void set_cell(int row, int col, bool value)
17Example of Flyweight Context
- The cell refers to the grid and its current
location (passed in via its context) to count the
adjacent cells.
- / Count the number of adjacent cells that are
"alive" / - int cellcount(cellcontext c) const
- int n0
- nc.g-gtis_current(c.row-1, c.col-1)
- nc.g-gtis_current(c.row-1, c.col)
- nc.g-gtis_current(c.row-1, c.col1)
- nc.g-gtis_current(c.row, c.col-1)
- nc.g-gtis_current(c.row, c.col1)
- nc.g-gtis_current(c.row1, c.col-1)
- nc.g-gtis_current(c.row1, c.col)
- nc.g-gtis_current(c.row1, c.col1)
- return n
18Choosing the Right Flyweight
- This function sets the cells current and next
values. Instead of modifying the flyweight
object, it just modifies the pointer to point to
the correct flyweight.
void gridupdate_cell(int row, int col, bool
cur, bool next) cell flyweight / Pick the
right new flyweight / if (cur) flyweightnext?fl
yweight_ttflyweight_tf else flyweightnext?flyw
eight_ftflyweight_ff / Change the flyweight
pointed to in the grid / cellsindex(row,
col)flyweight
19Caveats
- This example differs slightly from the canonical
definition of flyweight - Its scaled back
- The factory and the client are the same class.
- The program modifies the values of the concrete
flyweights - In this case, all flyweights with the same value
change at the same time, so it works.
20Summary
- Use flyweight when you have a large number of
objects - Must be able to separate extrinsic state from
intrinsic state - Small number of variants of intrinsic state
- Compute extrinsic state from its context
- Questions?