diff --git a/factory-kit/README.md b/factory-kit/README.md index 346012c07e8d680753576beab29d35b7161348f4..861ddb862c96320f4d9aa8311fd5a53196fe06c0 100644 --- a/factory-kit/README.md +++ b/factory-kit/README.md @@ -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 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 consumer) { + var map = new HashMap>(); + 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(); +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) diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/App.java b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java index e5f0b428573c0d5ab4a0b4f03e7829e574b6baaa..7c636609af2c465b10aca17499babd1263655d8b 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/App.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java @@ -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. * - *

In the given example {@link WeaponFactory} represents the factory-kit, that contains four + *

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. * *

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(); + 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())); } }