Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update flyweight
  • Loading branch information
iluwatar committed Jun 13, 2021
commit 3b1f82a2a4378d48058af840417b63d9c6ead211
2 changes: 1 addition & 1 deletion factory-method/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ categories: Creational
language: en
tags:
- Extensibility
- Gang Of Four
- Gang of Four
---

## Also known as
Expand Down
100 changes: 77 additions & 23 deletions flyweight/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ permalink: /patterns/flyweight/
categories: Structural
language: en
tags:
- Gang Of Four
- Gang of Four
- Performance
---

Expand All @@ -16,11 +16,11 @@ Use sharing to support large numbers of fine-grained objects efficiently.

## Explanation

Real world example
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 new object for each of them. Instead one object instance can represent multiple
> shelf items so memory footprint remains small.
> 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

Expand All @@ -36,7 +36,7 @@ Wikipedia says

**Programmatic example**

Translating our alchemist shop example from above. First of all we have different potion types:
Translating our alchemist shop example from above. First of all, we have different potion types:

```java
public interface Potion {
Expand Down Expand Up @@ -104,27 +104,81 @@ public class PotionFactory {
}
```

And it can be used as below:
`AlchemistShop` contains two shelves of magic potions. The potions are created using the
aforementioned `PotionFactory`.

```java
var factory = new PotionFactory();
factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818)
factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364)
factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818)
factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489)
factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489)
factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364)
@Slf4j
public class AlchemistShop {

private final List<Potion> topShelf;
private final List<Potion> bottomShelf;

public AlchemistShop() {
var factory = new PotionFactory();
topShelf = List.of(
factory.createPotion(PotionType.INVISIBILITY),
factory.createPotion(PotionType.INVISIBILITY),
factory.createPotion(PotionType.STRENGTH),
factory.createPotion(PotionType.HEALING),
factory.createPotion(PotionType.INVISIBILITY),
factory.createPotion(PotionType.STRENGTH),
factory.createPotion(PotionType.HEALING),
factory.createPotion(PotionType.HEALING)
);
bottomShelf = List.of(
factory.createPotion(PotionType.POISON),
factory.createPotion(PotionType.POISON),
factory.createPotion(PotionType.POISON),
factory.createPotion(PotionType.HOLY_WATER),
factory.createPotion(PotionType.HOLY_WATER)
);
}

public final List<Potion> getTopShelf() {
return List.copyOf(this.topShelf);
}

public final List<Potion> getBottomShelf() {
return List.copyOf(this.bottomShelf);
}

public void drinkPotions() {
LOGGER.info("Drinking top shelf potions\n");
topShelf.forEach(Potion::drink);
LOGGER.info("Drinking bottom shelf potions\n");
bottomShelf.forEach(Potion::drink);
}
}
```

In our scenario, a brave visitor enters the alchemist shop and drinks all the potions.

```java
// create the alchemist shop with the potions
var alchemistShop = new AlchemistShop();
// a brave visitor enters the alchemist shop and drinks all the potions
alchemistShop.drinkPotions();
```

Program output:

```java
You become invisible. (Potion=6566818)
You feel healed. (Potion=648129364)
You become invisible. (Potion=6566818)
You feel blessed. (Potion=1104106489)
You feel blessed. (Potion=1104106489)
You feel healed. (Potion=648129364)
Drinking top shelf potions
You become invisible. (Potion=1509514333)
You become invisible. (Potion=1509514333)
You feel strong. (Potion=739498517)
You feel healed. (Potion=125130493)
You become invisible. (Potion=1509514333)
You feel strong. (Potion=739498517)
You feel healed. (Potion=125130493)
You feel healed. (Potion=125130493)
Drinking bottom shelf potions
Urgh! This is poisonous. (Potion=166239592)
Urgh! This is poisonous. (Potion=166239592)
Urgh! This is poisonous. (Potion=166239592)
You feel blessed. (Potion=991505714)
You feel blessed. (Potion=991505714)
```

## Class diagram
Expand All @@ -138,13 +192,13 @@ Flyweight pattern when all of the following are true:

* An application uses a large number of objects.
* Storage costs are high because of the sheer quantity of objects.
* Most object state can be made extrinsic.
* Many groups of objects may be replaced by relatively few shared objects once extrinsic state is
removed.
* Most of the object state can be made extrinsic.
* Many groups of objects may be replaced by relatively few shared objects once the extrinsic state
is removed.
* The application doesn't depend on object identity. Since flyweight objects may be shared, identity
tests will return true for conceptually distinct objects.

## Real world examples
## Known uses

* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29) and similarly for Byte, Character and other wrapped types.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ public final List<Potion> getBottomShelf() {
}

/**
* Enumerate potions.
* Drink all the potions.
*/
public void enumerate() {
LOGGER.info("Enumerating top shelf potions\n");
public void drinkPotions() {
LOGGER.info("Drinking top shelf potions");
topShelf.forEach(Potion::drink);
LOGGER.info("Enumerating bottom shelf potions\n");
LOGGER.info("Drinking bottom shelf potions");
bottomShelf.forEach(Potion::drink);
}
}
4 changes: 3 additions & 1 deletion flyweight/src/main/java/com/iluwatar/flyweight/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
// create the alchemist shop with the potions
var alchemistShop = new AlchemistShop();
alchemistShop.enumerate();
// a brave visitor enters the alchemist shop and drinks all the potions
alchemistShop.drinkPotions();
}
}