Compare commits

...

2 Commits

Author SHA1 Message Date
92ddbbbc92 Add explanation for factory kit 2022-01-03 21:18:37 +02:00
2679f7aa6f docs: add castleKing1997 as a contributor for code (#1939)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2022-01-01 20:48:21 +02:00
4 changed files with 123 additions and 11 deletions

View File

@ -1776,6 +1776,15 @@
"contributions": [
"code"
]
},
{
"login": "castleKing1997",
"name": "DragonDreamer",
"avatar_url": "https://avatars.githubusercontent.com/u/35420129?v=4",
"profile": "http://rosaecrucis.cn",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@ -10,7 +10,7 @@
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-195-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-196-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<br/>
@ -325,6 +325,7 @@ This project is licensed under the terms of the MIT license.
<td align="center"><a href="https://github.com/interactwithankush"><img src="https://avatars.githubusercontent.com/u/18613127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>interactwithankush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=interactwithankush" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/yuhangbin"><img src="https://avatars.githubusercontent.com/u/17566866?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CharlieYu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yuhangbin" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Leisterbecker"><img src="https://avatars.githubusercontent.com/u/20650323?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leisterbecker</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Leisterbecker" title="Code">💻</a></td>
<td align="center"><a href="http://rosaecrucis.cn"><img src="https://avatars.githubusercontent.com/u/35420129?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DragonDreamer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=castleKing1997" title="Code">💻</a></td>
</tr>
</table>

View File

@ -10,19 +10,115 @@ tags:
---
## Intent
Define a factory of immutable content with separated builder and factory interfaces.
## Explanation
Real-world example
> Imagine a magical weapon factory that can create any type of weapon wished for. When the factory
> is unboxed, the master recites the weapon types needed to prepare it. After that, any of those
> weapon types can be summoned in an instant.
In plain words
> Factory kit is a configurable object builder.
**Programmatic Example**
Let's first define the simple `Weapon` hierarchy.
```java
public interface Weapon {
}
public enum WeaponType {
SWORD,
AXE,
BOW,
SPEAR
}
public class Sword implements Weapon {
@Override
public String toString() {
return "Sword";
}
}
// Axe, Bow, and Spear are defined similarly
```
Next, we define a functional interface that allows adding a builder with a name to the factory.
```java
public interface Builder {
void add(WeaponType name, Supplier<Weapon> supplier);
}
```
The meat of the example is the `WeaponFactory` interface that effectively implements the factory
kit pattern. The method `#factory` is used to configure the factory with the classes it needs to
be able to construct. The method `#create` is then used to create object instances.
```java
public interface WeaponFactory {
static WeaponFactory factory(Consumer<Builder> consumer) {
var map = new HashMap<WeaponType, Supplier<Weapon>>();
consumer.accept(map::put);
return name -> map.get(name).get();
}
Weapon create(WeaponType name);
}
```
Now, we can show how `WeaponFactory` can be used.
```java
var factory = WeaponFactory.factory(builder -> {
builder.add(WeaponType.SWORD, Sword::new);
builder.add(WeaponType.AXE, Axe::new);
builder.add(WeaponType.SPEAR, Spear::new);
builder.add(WeaponType.BOW, Bow::new);
});
var list = new ArrayList<Weapon>();
list.add(factory.create(WeaponType.AXE));
list.add(factory.create(WeaponType.SPEAR));
list.add(factory.create(WeaponType.SWORD));
list.add(factory.create(WeaponType.BOW));
list.stream().forEach(weapon -> LOGGER.info("{}", weapon.toString()));
```
Here is the console output when the example is run.
```
21:15:49.709 [main] INFO com.iluwatar.factorykit.App - Axe
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Spear
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Sword
21:15:49.713 [main] INFO com.iluwatar.factorykit.App - Bow
```
## Class diagram
![alt text](./etc/factory-kit.png "Factory Kit")
## Applicability
Use the Factory Kit pattern when
* a class can't anticipate the class of objects it must create
* you just want a new instance of a custom builder instead of the global one
* you explicitly want to define types of objects, that factory can build
* you want a separated builder and creator interface
* The factory class can't anticipate the types of objects it must create
* A new instance of a custom builder is needed instead of a global one
* The types of objects that the factory can build need to be defined outside the class
* The builder and creator interfaces need to be separated
## Related patterns
* [Builder](https://java-design-patterns.com/patterns/builder/)
* [Factory](https://java-design-patterns.com/patterns/factory/)
## Credits
* [Design Pattern Reloaded by Remi Forax: ](https://www.youtube.com/watch?v=-k2X7guaArU)
* [Design Pattern Reloaded by Remi Forax](https://www.youtube.com/watch?v=-k2X7guaArU)

View File

@ -23,14 +23,16 @@
package com.iluwatar.factorykit;
import java.util.ArrayList;
import lombok.extern.slf4j.Slf4j;
/**
* Factory-kit is a creational pattern which defines a factory of immutable content with separated
* Factory kit is a creational pattern that defines a factory of immutable content with separated
* builder and factory interfaces to deal with the problem of creating one of the objects specified
* directly in the factory-kit instance.
* directly in the factory kit instance.
*
* <p>In the given example {@link WeaponFactory} represents the factory-kit, that contains four
* <p>In the given example {@link WeaponFactory} represents the factory kit, that contains four
* {@link Builder}s for creating new objects of the classes implementing {@link Weapon} interface.
*
* <p>Each of them can be called with {@link WeaponFactory#create(WeaponType)} method, with
@ -52,7 +54,11 @@ public class App {
builder.add(WeaponType.SPEAR, Spear::new);
builder.add(WeaponType.BOW, Bow::new);
});
var axe = factory.create(WeaponType.AXE);
LOGGER.info(axe.toString());
var list = new ArrayList<Weapon>();
list.add(factory.create(WeaponType.AXE));
list.add(factory.create(WeaponType.SPEAR));
list.add(factory.create(WeaponType.SWORD));
list.add(factory.create(WeaponType.BOW));
list.stream().forEach(weapon -> LOGGER.info("{}", weapon.toString()));
}
}