Use sharing to support large numbers of fine-grained objects efficiently.
Real-world example
Alchemist’s shop has shelves full of magic potions. Many of the potions are the same so there is no need to create a new object for each of them. Instead, one object instance can represent multiple shelf items so the memory footprint remains small.
In plain words
It is used to minimize memory usage or computational expenses by sharing as much as possible with similar objects.
Wikipedia says
In computer programming, flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory.
Programmatic example
Translating our alchemist shop example from above. First of all, we have different potion types:
1public interface Potion {
2 void drink();
3}
4
5@Slf4j
6public class HealingPotion implements Potion {
7 @Override
8 public void drink() {
9 LOGGER.info("You feel healed. (Potion={})", System.identityHashCode(this));
10 }
11}
12
13@Slf4j
14public class HolyWaterPotion implements Potion {
15 @Override
16 public void drink() {
17 LOGGER.info("You feel blessed. (Potion={})", System.identityHashCode(this));
18 }
19}
20
21@Slf4j
22public class InvisibilityPotion implements Potion {
23 @Override
24 public void drink() {
25 LOGGER.info("You become invisible. (Potion={})", System.identityHashCode(this));
26 }
27}
Then the actual Flyweight class PotionFactory
, which is the factory for creating potions.
1public class PotionFactory {
2
3 private final Map<PotionType, Potion> potions;
4
5 public PotionFactory() {
6 potions = new EnumMap<>(PotionType.class);
7 }
8
9 Potion createPotion(PotionType type) {
10 var potion = potions.get(type);
11 if (potion == null) {
12 switch (type) {
13 case HEALING -> {
14 potion = new HealingPotion();
15 potions.put(type, potion);
16 }
17 case HOLY_WATER -> {
18 potion = new HolyWaterPotion();
19 potions.put(type, potion);
20 }
21 case INVISIBILITY -> {
22 potion = new InvisibilityPotion();
23 potions.put(type, potion);
24 }
25 default -> {
26 }
27 }
28 }
29 return potion;
30 }
31}
AlchemistShop
contains two shelves of magic potions. The potions are created using the
aforementioned PotionFactory
.
1@Slf4j
2public class AlchemistShop {
3
4 private final List<Potion> topShelf;
5 private final List<Potion> bottomShelf;
6
7 public AlchemistShop() {
8 var factory = new PotionFactory();
9 topShelf = List.of(
10 factory.createPotion(PotionType.INVISIBILITY),
11 factory.createPotion(PotionType.INVISIBILITY),
12 factory.createPotion(PotionType.STRENGTH),
13 factory.createPotion(PotionType.HEALING),
14 factory.createPotion(PotionType.INVISIBILITY),
15 factory.createPotion(PotionType.STRENGTH),
16 factory.createPotion(PotionType.HEALING),
17 factory.createPotion(PotionType.HEALING)
18 );
19 bottomShelf = List.of(
20 factory.createPotion(PotionType.POISON),
21 factory.createPotion(PotionType.POISON),
22 factory.createPotion(PotionType.POISON),
23 factory.createPotion(PotionType.HOLY_WATER),
24 factory.createPotion(PotionType.HOLY_WATER)
25 );
26 }
27
28 public final List<Potion> getTopShelf() {
29 return List.copyOf(this.topShelf);
30 }
31
32 public final List<Potion> getBottomShelf() {
33 return List.copyOf(this.bottomShelf);
34 }
35
36 public void drinkPotions() {
37 LOGGER.info("Drinking top shelf potions\n");
38 topShelf.forEach(Potion::drink);
39 LOGGER.info("Drinking bottom shelf potions\n");
40 bottomShelf.forEach(Potion::drink);
41 }
42}
In our scenario, a brave visitor enters the alchemist shop and drinks all the potions.
1// create the alchemist shop with the potions
2var alchemistShop = new AlchemistShop();
3// a brave visitor enters the alchemist shop and drinks all the potions
4alchemistShop.drinkPotions();
Program output:
1Drinking top shelf potions
2You become invisible. (Potion=1509514333)
3You become invisible. (Potion=1509514333)
4You feel strong. (Potion=739498517)
5You feel healed. (Potion=125130493)
6You become invisible. (Potion=1509514333)
7You feel strong. (Potion=739498517)
8You feel healed. (Potion=125130493)
9You feel healed. (Potion=125130493)
10Drinking bottom shelf potions
11Urgh! This is poisonous. (Potion=166239592)
12Urgh! This is poisonous. (Potion=166239592)
13Urgh! This is poisonous. (Potion=166239592)
14You feel blessed. (Potion=991505714)
15You feel blessed. (Potion=991505714)
The Flyweight pattern’s effectiveness depends heavily on how and where it’s used. Apply the Flyweight pattern when all of the following are true: