#590 Add explanation for Flyweight
This commit is contained in:
parent
bd4247e864
commit
c13661810e
@ -16,7 +16,100 @@ tags:
|
|||||||
Use sharing to support large numbers of fine-grained objects
|
Use sharing to support large numbers of fine-grained objects
|
||||||
efficiently.
|
efficiently.
|
||||||
|
|
||||||

|
## Explanation
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
||||||
|
public interface Potion {
|
||||||
|
void drink();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HealingPotion implements Potion {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(HealingPotion.class);
|
||||||
|
@Override
|
||||||
|
public void drink() {
|
||||||
|
LOGGER.info("You feel healed. (Potion={})", System.identityHashCode(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HolyWaterPotion implements Potion {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(HolyWaterPotion.class);
|
||||||
|
@Override
|
||||||
|
public void drink() {
|
||||||
|
LOGGER.info("You feel blessed. (Potion={})", System.identityHashCode(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InvisibilityPotion implements Potion {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(InvisibilityPotion.class);
|
||||||
|
@Override
|
||||||
|
public void drink() {
|
||||||
|
LOGGER.info("You become invisible. (Potion={})", System.identityHashCode(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the actual Flyweight object which is the factory for creating potions
|
||||||
|
|
||||||
|
```
|
||||||
|
public class PotionFactory {
|
||||||
|
|
||||||
|
private final Map<PotionType, Potion> potions;
|
||||||
|
|
||||||
|
public PotionFactory() {
|
||||||
|
potions = new EnumMap<>(PotionType.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
Potion createPotion(PotionType type) {
|
||||||
|
Potion potion = potions.get(type);
|
||||||
|
if (potion == null) {
|
||||||
|
switch (type) {
|
||||||
|
case HEALING:
|
||||||
|
potion = new HealingPotion();
|
||||||
|
potions.put(type, potion);
|
||||||
|
break;
|
||||||
|
case HOLY_WATER:
|
||||||
|
potion = new HolyWaterPotion();
|
||||||
|
potions.put(type, potion);
|
||||||
|
break;
|
||||||
|
case INVISIBILITY:
|
||||||
|
potion = new InvisibilityPotion();
|
||||||
|
potions.put(type, potion);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return potion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And it can be used as below
|
||||||
|
|
||||||
|
```
|
||||||
|
PotionFactory 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)
|
||||||
|
```
|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
The Flyweight pattern's effectiveness depends heavily on how
|
The Flyweight pattern's effectiveness depends heavily on how
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 31 KiB |
@ -1,135 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
|
||||||
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
|
|
||||||
<class id="1" language="java" name="com.iluwatar.flyweight.PoisonPotion" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/PoisonPotion.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="106" width="129" x="297" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="2" language="java" name="com.iluwatar.flyweight.AlchemistShop" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="124" width="129" x="466" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="3" language="java" name="com.iluwatar.flyweight.HealingPotion" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/HealingPotion.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="106" width="129" x="635" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<enumeration id="4" language="java" name="com.iluwatar.flyweight.PotionType" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/PotionType.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="178" width="185" x="72" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</enumeration>
|
|
||||||
<class id="5" language="java" name="com.iluwatar.flyweight.PotionFactory" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/PotionFactory.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="106" width="212" x="804" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="6" language="java" name="com.iluwatar.flyweight.InvisibilityPotion" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/InvisibilityPotion.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="106" width="141" x="1056" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<interface id="7" language="java" name="com.iluwatar.flyweight.Potion" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/Potion.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="88" width="129" x="797" y="472"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<class id="8" language="java" name="com.iluwatar.flyweight.StrengthPotion" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/StrengthPotion.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="106" width="132" x="1237" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="9" language="java" name="com.iluwatar.flyweight.HolyWaterPotion" project="flyweight"
|
|
||||||
file="/flyweight/src/main/java/com/iluwatar/flyweight/HolyWaterPotion.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="106" width="141" x="1409" y="254"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<realization id="10">
|
|
||||||
<end type="SOURCE" refId="6"/>
|
|
||||||
<end type="TARGET" refId="7"/>
|
|
||||||
</realization>
|
|
||||||
<association id="11">
|
|
||||||
<end type="SOURCE" refId="2" navigable="false">
|
|
||||||
<attribute id="12" name="topShelf"/>
|
|
||||||
<multiplicity id="13" minimum="0" maximum="2147483647"/>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="7" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<realization id="14">
|
|
||||||
<end type="SOURCE" refId="8"/>
|
|
||||||
<end type="TARGET" refId="7"/>
|
|
||||||
</realization>
|
|
||||||
<association id="15">
|
|
||||||
<end type="SOURCE" refId="2" navigable="false">
|
|
||||||
<attribute id="16" name="bottomShelf"/>
|
|
||||||
<multiplicity id="17" minimum="0" maximum="2147483647"/>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="7" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<realization id="18">
|
|
||||||
<end type="SOURCE" refId="1"/>
|
|
||||||
<end type="TARGET" refId="7"/>
|
|
||||||
</realization>
|
|
||||||
<realization id="19">
|
|
||||||
<end type="SOURCE" refId="3"/>
|
|
||||||
<end type="TARGET" refId="7"/>
|
|
||||||
</realization>
|
|
||||||
<realization id="20">
|
|
||||||
<end type="SOURCE" refId="9"/>
|
|
||||||
<end type="TARGET" refId="7"/>
|
|
||||||
</realization>
|
|
||||||
<association id="21">
|
|
||||||
<end type="SOURCE" refId="5" navigable="false">
|
|
||||||
<attribute id="22" name="potions"/>
|
|
||||||
<multiplicity id="23" minimum="0" maximum="2147483647"/>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="7" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</classifier-display>
|
|
||||||
<association-display labels="true" multiplicity="true"/>
|
|
||||||
</class-diagram>
|
|
@ -1,66 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.flyweight {
|
|
||||||
class AlchemistShop {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
- bottomShelf : List<Potion>
|
|
||||||
- topShelf : List<Potion>
|
|
||||||
+ AlchemistShop()
|
|
||||||
+ enumerate()
|
|
||||||
- fillShelves()
|
|
||||||
+ getBottomShelf() : List<Potion>
|
|
||||||
+ getTopShelf() : List<Potion>
|
|
||||||
}
|
|
||||||
class App {
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class HealingPotion {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ HealingPotion()
|
|
||||||
+ drink()
|
|
||||||
}
|
|
||||||
class HolyWaterPotion {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ HolyWaterPotion()
|
|
||||||
+ drink()
|
|
||||||
}
|
|
||||||
class InvisibilityPotion {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ InvisibilityPotion()
|
|
||||||
+ drink()
|
|
||||||
}
|
|
||||||
class PoisonPotion {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ PoisonPotion()
|
|
||||||
+ drink()
|
|
||||||
}
|
|
||||||
interface Potion {
|
|
||||||
+ drink() {abstract}
|
|
||||||
}
|
|
||||||
class PotionFactory {
|
|
||||||
- potions : Map<PotionType, Potion>
|
|
||||||
+ PotionFactory()
|
|
||||||
~ createPotion(type : PotionType) : Potion
|
|
||||||
}
|
|
||||||
enum PotionType {
|
|
||||||
+ HEALING {static}
|
|
||||||
+ HOLY_WATER {static}
|
|
||||||
+ INVISIBILITY {static}
|
|
||||||
+ POISON {static}
|
|
||||||
+ STRENGTH {static}
|
|
||||||
+ valueOf(name : String) : PotionType {static}
|
|
||||||
+ values() : PotionType[] {static}
|
|
||||||
}
|
|
||||||
class StrengthPotion {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ StrengthPotion()
|
|
||||||
+ drink()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AlchemistShop --> "-topShelf" Potion
|
|
||||||
HealingPotion ..|> Potion
|
|
||||||
HolyWaterPotion ..|> Potion
|
|
||||||
InvisibilityPotion ..|> Potion
|
|
||||||
PoisonPotion ..|> Potion
|
|
||||||
StrengthPotion ..|> Potion
|
|
||||||
@enduml
|
|
Binary file not shown.
Before Width: | Height: | Size: 62 KiB |
Loading…
x
Reference in New Issue
Block a user