Skip to content

Commit 2d2dec9

Browse files
iluwatarohbus
andauthored
enhancement: Add explanation for factory kit (#1941)
Co-authored-by: Subhrodip Mohanta <[email protected]>
1 parent 3cc9bc2 commit 2d2dec9

File tree

2 files changed

+112
-10
lines changed

2 files changed

+112
-10
lines changed

factory-kit/README.md

+101-5
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,115 @@ tags:
1010
---
1111

1212
## Intent
13+
1314
Define a factory of immutable content with separated builder and factory interfaces.
1415

16+
## Explanation
17+
18+
Real-world example
19+
20+
> Imagine a magical weapon factory that can create any type of weapon wished for. When the factory
21+
> is unboxed, the master recites the weapon types needed to prepare it. After that, any of those
22+
> weapon types can be summoned in an instant.
23+
24+
In plain words
25+
26+
> Factory kit is a configurable object builder.
27+
28+
**Programmatic Example**
29+
30+
Let's first define the simple `Weapon` hierarchy.
31+
32+
```java
33+
public interface Weapon {
34+
}
35+
36+
public enum WeaponType {
37+
SWORD,
38+
AXE,
39+
BOW,
40+
SPEAR
41+
}
42+
43+
public class Sword implements Weapon {
44+
@Override
45+
public String toString() {
46+
return "Sword";
47+
}
48+
}
49+
50+
// Axe, Bow, and Spear are defined similarly
51+
```
52+
53+
Next, we define a functional interface that allows adding a builder with a name to the factory.
54+
55+
```java
56+
public interface Builder {
57+
void add(WeaponType name, Supplier<Weapon> supplier);
58+
}
59+
```
60+
61+
The meat of the example is the `WeaponFactory` interface that effectively implements the factory
62+
kit pattern. The method `#factory` is used to configure the factory with the classes it needs to
63+
be able to construct. The method `#create` is then used to create object instances.
64+
65+
```java
66+
public interface WeaponFactory {
67+
68+
static WeaponFactory factory(Consumer<Builder> consumer) {
69+
var map = new HashMap<WeaponType, Supplier<Weapon>>();
70+
consumer.accept(map::put);
71+
return name -> map.get(name).get();
72+
}
73+
74+
Weapon create(WeaponType name);
75+
}
76+
```
77+
78+
Now, we can show how `WeaponFactory` can be used.
79+
80+
```java
81+
var factory = WeaponFactory.factory(builder -> {
82+
builder.add(WeaponType.SWORD, Sword::new);
83+
builder.add(WeaponType.AXE, Axe::new);
84+
builder.add(WeaponType.SPEAR, Spear::new);
85+
builder.add(WeaponType.BOW, Bow::new);
86+
});
87+
var list = new ArrayList<Weapon>();
88+
list.add(factory.create(WeaponType.AXE));
89+
list.add(factory.create(WeaponType.SPEAR));
90+
list.add(factory.create(WeaponType.SWORD));
91+
list.add(factory.create(WeaponType.BOW));
92+
list.stream().forEach(weapon -> LOGGER.info("{}", weapon.toString()));
93+
```
94+
95+
Here is the console output when the example is run.
96+
97+
```
98+
21:15:49.709 [main] INFO com.iluwatar.factorykit.App - Axe
99+
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Spear
100+
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Sword
101+
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Bow
102+
```
103+
15104
## Class diagram
105+
16106
![alt text](./etc/factory-kit.png "Factory Kit")
17107

18108
## Applicability
109+
19110
Use the Factory Kit pattern when
20111

21-
* a class can't anticipate the class of objects it must create
22-
* you just want a new instance of a custom builder instead of the global one
23-
* you explicitly want to define types of objects, that factory can build
24-
* you want a separated builder and creator interface
112+
* The factory class can't anticipate the types of objects it must create
113+
* A new instance of a custom builder is needed instead of a global one
114+
* The types of objects that the factory can build need to be defined outside the class
115+
* The builder and creator interfaces need to be separated
116+
117+
## Related patterns
118+
119+
* [Builder](https://java-design-patterns.com/patterns/builder/)
120+
* [Factory](https://java-design-patterns.com/patterns/factory/)
25121

26122
## Credits
27123

28-
* [Design Pattern Reloaded by Remi Forax: ](https://www.youtube.com/watch?v=-k2X7guaArU)
124+
* [Design Pattern Reloaded by Remi Forax](https://www.youtube.com/watch?v=-k2X7guaArU)

factory-kit/src/main/java/com/iluwatar/factorykit/App.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@
2323

2424
package com.iluwatar.factorykit;
2525

26+
import java.util.ArrayList;
27+
2628
import lombok.extern.slf4j.Slf4j;
2729

2830
/**
29-
* Factory-kit is a creational pattern which defines a factory of immutable content with separated
31+
* Factory kit is a creational pattern that defines a factory of immutable content with separated
3032
* builder and factory interfaces to deal with the problem of creating one of the objects specified
31-
* directly in the factory-kit instance.
33+
* directly in the factory kit instance.
3234
*
33-
* <p>In the given example {@link WeaponFactory} represents the factory-kit, that contains four
35+
* <p>In the given example {@link WeaponFactory} represents the factory kit, that contains four
3436
* {@link Builder}s for creating new objects of the classes implementing {@link Weapon} interface.
3537
*
3638
* <p>Each of them can be called with {@link WeaponFactory#create(WeaponType)} method, with
@@ -52,7 +54,11 @@ public static void main(String[] args) {
5254
builder.add(WeaponType.SPEAR, Spear::new);
5355
builder.add(WeaponType.BOW, Bow::new);
5456
});
55-
var axe = factory.create(WeaponType.AXE);
56-
LOGGER.info(axe.toString());
57+
var list = new ArrayList<Weapon>();
58+
list.add(factory.create(WeaponType.AXE));
59+
list.add(factory.create(WeaponType.SPEAR));
60+
list.add(factory.create(WeaponType.SWORD));
61+
list.add(factory.create(WeaponType.BOW));
62+
list.stream().forEach(weapon -> LOGGER.info("{}", weapon.toString()));
5763
}
5864
}

0 commit comments

Comments
 (0)