0% found this document useful (0 votes)
21 views

CS202 Seminar Report Flyweight

This document is a seminar report on the flyweight design pattern presented by a group of students from Vietnam National University. It begins with an introduction that provides an example problem of building a game where limited memory is an issue. It then defines the flyweight pattern, explaining that it allows for sharing of common object data to reduce memory usage. The structure of the pattern is described using UML diagrams. An example implementation is also provided to illustrate how intrinsic and extrinsic state are handled.

Uploaded by

ndt280504
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

CS202 Seminar Report Flyweight

This document is a seminar report on the flyweight design pattern presented by a group of students from Vietnam National University. It begins with an introduction that provides an example problem of building a game where limited memory is an issue. It then defines the flyweight pattern, explaining that it allows for sharing of common object data to reduce memory usage. The structure of the pattern is described using UML diagrams. An example implementation is also provided to illustrate how intrinsic and extrinsic state are handled.

Uploaded by

ndt280504
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

VIETNAM NATIONAL UNIVERSITY HO CHI MINH CITY

UNIVERSITY OF SCIENCE

SEMINAR REPORT
FLYWEIGHT
DESIGN PATTERN

Members of Group 05: Nguyễn Hữu Quốc Thắng


Nguyễn Chính Thông
Phạm Trung Nghĩa
Nguyễn Đức Thọ

Ho Chi Minh City, 16/12/2023


Contents
1 Introduction 2
1.1 Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Definition 4
2.1 Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Example 6

4 Real World Problems 11

5 Pros/Cons of State 12

1
1 Introduction
1.1 Problem
Imagine you’re building a game, where the purpose is to answer the age old question: “Why
does the chicken cross the road?”
Yes, we’re building a crossing game. Like Crossy Road [1]. Or Frogger [2].
When we start a new game, a new World should be created. Where there are trees, rocks,
and, of course, obstacles, like water blocks, trains, and the like.
Let’s start with creating a game world. The world should have many lanes, like normal
land, train tracks, river blocks, and roads. We call these “blocks”. These blocks have some
properties, such as its sprite, its position, its type, what kind of obstacle it contains, and so on.
On code, a block would look like this [3]:

1 class Block
2 {
3 protected:
4 sf::Sprite m_sprite;
5 sf::Texture m_texture;
6

7 sf::Vector2f m_position;
8 sf::Vector2f m_scale = {1, 1};
9

10 ObstacleType m_obstacleType;
11 Obstacle *obstacle;
12 bool m_isContainObs = 0;
13

14 BlockType m_type;
15

16 bool m_direcion; //1-left, 0-right


17 }

And a single lane would look like this [4]:

1 class Lane
2 {
3 private:
4 sf::Vector2f m_startingPosition;
5 vector<Block *> blocks;
6 float v = 0;
7

8 public:
9 Lane();
10 ~Lane();

2
11 void addBlock(Block *block);
12 void draw(sf::RenderWindow &window);
13 void setStartingPosition(sf::Vector2f startingPosition);
14 sf::Vector2f getStartingPosition();
15

16 Block* getBlock(int index);


17

18 void Update(const sf::Time& l_time);


19 bool isAbleToStepOn(int index);
20

21 vector<Obstacle*> getObstacles();\
22

23 int getV();
24 };

Figure 1: Diagram of the naive solution

After compiling the code and running it, suddenly, the computer’s fans begin to speed up
to maximum. When you open Task Manager, you noticed the GPU usage spiked up to 100%,
and you have no idea why.

3
Figure 2: GPU maxed out on running the CS202 Project

The problem is the design of the lanes itself. Because the data of each block is stored on a
single object, it begins to fill up the available memory. This becomes especially alarming when
we develop a level progression system, where the number of levels begin to increase, and so
is the lane count for each level. And that’s not accounting for each of the obstacles that are
present on each lane, such as the cars on the road, the small logs on the rivers, the trains,...
On many limited-spec machines, it would crash immediately, while on stronger machines,
it would hamper the system’s performance massively.

2 Definition
The Flyweight pattern is a structural pattern, which uses “sharing to support large numbers
of fine-grained objects efficiently.”
In simpler terms, it allows sharing common parts of each objects instead of keeping all the
data in one single object, greatly reducing RAM usage.

2.1 Structure
The Flyweight pattern is merely an optimization. Before applying it, make sure your
program does have the RAM consumption problem related to having a massive number of
similar objects in memory at the same time. Make sure that this problem can’t be solved in
any other meaningful way.
Let have a look at the structure of Flyweight pattern:

4
Figure 3: Structure of FlyWeight Pattern

The Flyweight class contains the portion of the original object’s state that can be shared
between multiple objects. The same flyweight object can be used in many different contexts.
The state stored inside a flyweight is called intrinsic. The state passed to the flyweight’s
methods is called extrinsic.
The Context class contains the extrinsic state, unique across all original objects. When a
context is paired with one of the flyweight objects, it represents the full state of the original
object.
Usually, the behavior of the original object remains in the flyweight class. In this case,
whoever calls a flyweight’s method must also pass appropriate bits of the extrinsic state into
the method’s parameters. On the other hand, the behavior can be moved to the context class,
which would use the linked flyweight merely as a data object.
The Client calculates or stores the extrinsic state of flyweights. From the client’s per-
spective, a flyweight is a template object which can be configured at runtime by passing some
contextual data into parameters of its methods.
The Flyweight Factory manages a pool of existing flyweights. With the factory, clients
don’t create flyweights directly. Instead, they call the factory, passing it bits of the intrinsic
state of the desired flyweight. The factory looks over previously created flyweights and either
returns an existing one that matches search criteria or creates a new one if nothing is found.

2.2 Implementation
1. Divide fields of a class that will become a flyweight into two parts:

• the intrinsic state: the fields that contain unchanging data duplicated across
many objects
• the extrinsic state: the fields that contain contextual data unique to each object

2. Leave the fields that represent the intrinsic state in the class, but make sure they’re
immutable. They should take their initial values only inside the constructor.

3. Go over methods that use fields of the extrinsic state. For each field used in the method,
introduce a new parameter and use it instead of the field.

5
4. Optionally, create a factory class to manage the pool of flyweights. It should check for
an existing flyweight before creating a new one. Once the factory is in place, clients must
only request flyweights through it. They should describe the desired flyweight by passing
its intrinsic state to the factory.

5. The client must store or calculate values of the extrinsic state (context) to be able to call
methods of flyweight objects. For the sake of convenience, the extrinsic state along with
the flyweight-referencing field may be moved to a separate context class.

3 Example
To better understand how to implement the Flyweight design pattern, let’s look at a sim-
ple example about the management of information about cars and the sharing of common
information about them to reduce memory usage.
This example illustrates the structure of the Flyweight design pattern [5]. It focuses on
answering these questions:
• What classes does it consist of?

• What roles do these classes play?

• In what way the elements of the pattern are related?

1 /**
2 * Flyweight Design Pattern
3 *
4 * Intent: Lets you fit more objects into the available amount of RAM
5 * by sharing common parts of state between multiple objects,
6 * instead of keeping all of the data in each object.
7 */
8

9 struct SharedState
10 {
11 std::string brand_;
12 std::string model_;
13 std::string color_;
14

15 SharedState(const std::string &brand, const std::string &model,


16 const std::string &color)
17 : brand_(brand), model_(model), color_(color)
18 {
19 }
20

21 friend std::ostream &operator<<(std::ostream &os, const SharedState &ss)


22 {
23 return os << "[ " << ss.brand_ << " , " << ss.model_

6
24 << " , " << ss.color_ << " ]";
25 }
26 };
27

28 struct UniqueState
29 {
30 std::string owner_;
31 std::string plates_;
32

33 UniqueState(const std::string &owner, const std::string &plates)


34 : owner_(owner), plates_(plates)
35 {
36 }
37

38 friend std::ostream &operator<<(std::ostream &os, const UniqueState &us)


39 {
40 return os << "[ " << us.owner_ << " , " << us.plates_ << " ]";
41 }
42 };
43

Next, we implement the FlyWeight Class:

1 /**
2 * The Flyweight stores a common portion of the state (also called intrinsic
3 * state) that belongs to multiple real business entities. The Flyweight accepts
4 * the rest of the state (extrinsic state, unique for each entity) via its
5 * method parameters.
6 */
7 class Flyweight
8 {
9 private:
10 SharedState *shared_state_;
11

12 public:
13 Flyweight(const SharedState *shared_state) : shared_state_(new
14 SharedState(*shared_state))
15 {
16 }
17 Flyweight(const Flyweight &other) : shared_state_(new
18 SharedState(*other.shared_state_))
19 {

7
20 }
21 ~Flyweight()
22 {
23 delete shared_state_;
24 }
25 SharedState *shared_state() const
26 {
27 return shared_state_;
28 }
29 void Operation(const UniqueState &unique_state) const
30 {
31 std::cout << "Flyweight: Displaying shared (" << *shared_state_ << ")
32 and unique (" << unique_state << ") state.";
33 }
34 };

Finally, we implement the FlyWeight Factory class:

1 /**
2 * The Flyweight Factory creates and manages the Flyweight objects.
3 * It ensures that flyweights are shared correctly. When the client
4 * requests a flyweight, the factory either returns an existing
5 * instance or creates a new one, if it doesn't exist yet.
6 */
7 class FlyweightFactory
8 {
9 /**
10 * @var Flyweight[]
11 */
12 private:
13 std::unordered_map<std::string, Flyweight> flyweights_;
14 /**
15 * Returns a Flyweight's string hash for a given state.
16 */
17 std::string GetKey(const SharedState &ss) const
18 {
19 return ss.brand_ + "_" + ss.model_ + "_" + ss.color_;
20 }
21

22 public:
23 FlyweightFactory(std::initializer_list<SharedState> share_states)
24 {

8
25 for (const SharedState &ss : share_states)
26 {
27 this->flyweights_.insert(std::make_pair<std::string, Flyweight>
28 (this->GetKey(ss), Flyweight(&ss)));
29 }
30 }
31

32 /**
33 * Returns an existing Flyweight with a given state or creates a new one.
34 */
35 Flyweight GetFlyweight(const SharedState &shared_state)
36 {
37 std::string key = this->GetKey(shared_state);
38 if (this->flyweights_.find(key) == this->flyweights_.end())
39 {
40 std::cout << "FlyweightFactory: Can't find a flyweight,
41 creating new one.";
42 this->flyweights_.insert(std::make_pair(key,
43 Flyweight(&shared_state)));
44 }
45 else
46 {
47 std::cout << "FlyweightFactory: Reusing existing flyweight.\n";
48 }
49 return this->flyweights_.at(key);
50 }
51 void ListFlyweights() const
52 {
53 size_t count = this->flyweights_.size();
54 std::cout << "\nFlyweightFactory: I have " << count << " flyweights:";
55 for (std::pair<std::string, Flyweight> pair : this->flyweights_)
56 {
57 std::cout << pair.first << "\n";
58 }
59 }
60 };
61

62 // ...
63 void AddCarToPoliceDatabase(
64 FlyweightFactory &ff, const std::string &plates, const std::string &owner,
65 const std::string &brand, const std::string &model, const std::string &color)
66 {

9
67 std::cout << "\nClient: Adding a car to database.\n";
68 const Flyweight &flyweight = ff.GetFlyweight({brand, model, color});
69 // The client code either stores or calculates extrinsic state and
70 // passes it to the flyweight's methods.
71 flyweight.Operation({owner, plates});
72 }

So we have used the flyweight pattern to solve this problem, let see how it work:

1 /**
2 * The client code usually creates a bunch of pre-populated flyweights in the
3 * initialization stage of the application.
4 */
5

6 int main()
7 {
8 FlyweightFactory *factory = new FlyweightFactory({{"Chevrolet", "Camaro2018",
9 "pink"}, {"Mercedes Benz", "C300", "black"}, {"Mercedes Benz", "C500", "red"},
10 {"BMW", "M5", "red"}, {"BMW", "X6", "white"}});
11 factory->ListFlyweights();
12

13 AddCarToPoliceDatabase(*factory,
14 "CL234IR",
15 "James Doe",
16 "BMW",
17 "M5",
18 "red");
19

20 AddCarToPoliceDatabase(*factory,
21 "CL234IR",
22 "James Doe",
23 "BMW",
24 "X1",
25 "red");
26 factory->ListFlyweights();
27 delete factory;
28

29 return 0;
30 }

Here is the output of the above code:

10
FlyweightFactory: I have 5 flyweights:
BMW_X6_white
Mercedes Benz_C500_red
Mercedes Benz_C300_black
BMW_M5_red
Chevrolet_Camaro2018_pink

Client: Adding a car to database.


FlyweightFactory: Reusing existing flyweight.
Flyweight: Displaying shared ([ BMW , M5 , red ]) and unique ([ CL234IR , James Doe ])
state.

Client: Adding a car to database.


FlyweightFactory: Can't find a flyweight, creating new one.
Flyweight: Displaying shared ([ BMW , X1 , red ]) and unique ([ CL234IR , James Doe ])
state.

FlyweightFactory: I have 6 flyweights:


BMW_X1_red
Mercedes Benz_C300_black
BMW_X6_white
Mercedes Benz_C500_red
BMW_M5_red
Chevrolet_Camaro2018_pink

4 Real World Problems


Here are some popular application of flyweight pattern in real world:

• Text Processing - A text editor or word processor has to deal with a large number of
similar objects like characters. The Flyweight pattern allows storing each unique character
once and sharing instances of duplicate characters.

• File Systems - File systems have to store and retrieve a large number of similar small
files like images, audio/video clips. Flyweight reduces memory overhead of duplicate files.

• Operating System Interfaces - In computer, OS (Operating System) have to display


the same icons in different addresses. Flyweight pattern helps OS display those by sharing
resources with the root files.

• Graphics Rendering - Computer games have to render large numbers of similar graph-
ical objects like trees, buildings etc. Flyweight stores unique graphic objects and shares
instances of duplicates for rendering multiple objects in different positions, situations with
only one unique object loaded on memory.

• Cache Systems - Systems with large in-memory caches like databases use Flyweight to
store cached objects more efficiently by sharing duplicates.

• Web data managing - Many platforms such as YouTube, Facebook, etc... have to store
a large number of data such as images, audio/videos, text, etc... Flyweight pattern helps
users access their resources in their data pool instead of downloading them to use.

11
5 Pros/Cons of State
• Pros:

1. Memory Efficiency:
– Reduces Memory Usage: The main advantage of the Flyweight pattern is
that it reduces the overall memory or storage footprint by sharing common data
among multiple objects.
– Efficient for Large Datasets: Particularly beneficial when dealing with a
large number of similar objects, as it allows for significant memory savings.
2. Performance Improvement:
– Improves Performance: By sharing common data, the Flyweight pattern can
lead to performance improvements, as the overhead of creating and managing
numerous similar objects is reduced.
3. Resource Conservation:
– Conserves Resources: Helps conserve system resources, especially in resource-
constrained environments, by minimizing the duplication of data.
4. Flexibility:
– Separates Intrinsic and Extrinsic State: It separates the intrinsic (shared)
and extrinsic (unique) states of an object, making it easier to manage and update
them independently.

• Cons:

1. Complexity:
– Introduces Complexity: The pattern may introduce additional complexity,
especially if not implemented carefully. The separation of intrinsic and extrinsic
state can lead to more complex code and potential maintenance challenges.
2. Potential for Overhead:
– Runtime Overhead: There might be a slight runtime overhead associated
with managing and retrieving shared flyweight objects, which could impact
performance in certain scenarios.
3. Not Always Applicable:
– Limited Applicability: The Flyweight pattern is most beneficial when dealing
with a large number of similar objects. In situations where objects are signifi-
cantly different or the number of objects is small, the overhead of implementing
the pattern may outweigh the benefits.
4. Security Concerns:
– Shared State Concerns: If not managed properly, sharing state among ob-
jects can lead to security concerns, especially if the shared state is mutable.
5. Increased Complexity for Clients:
– Client Complexity: Clients need to be aware of both intrinsic and extrinsic
state, which can increase the complexity for clients using the flyweight objects.

12
References
[1] “Wikipedia entry for Crossy Road.” (), [Online]. Available: https://en.wikipedia.org/wiki/
Frogger?useskin=vector.
[2] “Wikipedia entry for Frogger.” (), [Online]. Available: https : / / en . wikipedia . org / wiki /
Frogger.
[3] Group 05 22TT2 - CS202, “Header file of a Block class, CS202 Project - Crossing Game,”
Code for this Repo is currently private as of writing. [Online]. Available: https://github.
com/Rookie001MC/CS202-Frogger/blob/develop/src/Lane/Block.hpp.
[4] Group 05 22TT2 - CS202, “Header file of a Lane class, CS202 Project - Crossing Game,”
Code for this Repo is currently private as of writing. [Online]. Available: https://github.
com/Rookie001MC/CS202-Frogger/blob/develop/src/Lane/Lane.hpp.
[5] Authors of Refactoring.Guru. “Flyweight.” (), [Online]. Available: https : / / refactoring .
guru/design-patterns/flyweight/cpp/example#lang-features.

13

You might also like