diff --git a/factory-kit/etc/factory-kit.png b/factory-kit/etc/factory-kit.png new file mode 100644 index 000000000..7093193cb Binary files /dev/null and b/factory-kit/etc/factory-kit.png differ diff --git a/factory-kit/etc/factory-kit.ucls b/factory-kit/etc/factory-kit.ucls new file mode 100644 index 000000000..403fb7e27 --- /dev/null +++ b/factory-kit/etc/factory-kit.ucls @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/factory-kit/index.md b/factory-kit/index.md new file mode 100644 index 000000000..c25701047 --- /dev/null +++ b/factory-kit/index.md @@ -0,0 +1,28 @@ +--- +layout: pattern +title: Factory Kit +folder: factory-kit +permalink: /patterns/factory-kit/ +categories: Creational +tags: + - Java + - Difficulty-Beginner + - Functional +--- + +## Intent +Define a factory of immutable content with separated builder and factory interfaces. + +![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 + +## Credits + +* [Design Pattern Reloaded by Remi Forax: ](https://www.youtube.com/watch?v=-k2X7guaArU) diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml new file mode 100644 index 000000000..c336c5f49 --- /dev/null +++ b/factory-kit/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.11.0-SNAPSHOT + + factory-kit + + + junit + junit + test + + + org.mockito + mockito-core + test + + + \ No newline at end of file diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/App.java b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java new file mode 100644 index 000000000..91d1eb061 --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java @@ -0,0 +1,32 @@ +package com.iluwatar.factorykit; + +/** + * Factory-kit is a creational pattern which 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. + * + *

+ * 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 + * an input representing an instance of {@link WeaponType} that needs to + * be mapped explicitly with desired class type in the factory instance. + */ +public class App { + /** + * Program entry point. + * + * @param args @param args command line args + */ + public static void main(String[] args) { + WeaponFactory 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); + }); + Weapon axe = factory.create(WeaponType.AXE); + System.out.println(axe); + } +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java new file mode 100644 index 000000000..4e1a5e554 --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java @@ -0,0 +1,8 @@ +package com.iluwatar.factorykit; + +public class Axe implements Weapon { + @Override + public String toString() { + return "Axe"; + } +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java new file mode 100644 index 000000000..a90f4cf2e --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java @@ -0,0 +1,8 @@ +package com.iluwatar.factorykit; + +public class Bow implements Weapon { + @Override + public String toString() { + return "Bow"; + } +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Builder.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Builder.java new file mode 100644 index 000000000..be74626f7 --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Builder.java @@ -0,0 +1,10 @@ +package com.iluwatar.factorykit; + +import java.util.function.Supplier; + +/** + * Functional interface that allows adding builder with name to the factory. + */ +public interface Builder { + void add(WeaponType name, Supplier supplier); +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java new file mode 100644 index 000000000..a50f54290 --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java @@ -0,0 +1,8 @@ +package com.iluwatar.factorykit; + +public class Spear implements Weapon { + @Override + public String toString() { + return "Spear"; + } +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java new file mode 100644 index 000000000..278febaf5 --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java @@ -0,0 +1,8 @@ +package com.iluwatar.factorykit; + +public class Sword implements Weapon { + @Override + public String toString() { + return "Sword"; + } +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Weapon.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Weapon.java new file mode 100644 index 000000000..980a2219f --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Weapon.java @@ -0,0 +1,7 @@ +package com.iluwatar.factorykit; + +/** + * Interface representing weapon. + */ +public interface Weapon { +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java new file mode 100644 index 000000000..e83a997c6 --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java @@ -0,0 +1,33 @@ +package com.iluwatar.factorykit; + +import java.util.HashMap; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * Functional interface, an example of the factory-kit design pattern. + *
Instance created locally gives an opportunity to strictly define + * which objects types the instance of a factory will be able to create. + *
Factory is a placeholder for {@link Builder}s + * with {@link WeaponFactory#create(WeaponType)} method to initialize new objects. + */ +public interface WeaponFactory { + + /** + * Creates an instance of the given type. + * @param name representing enum of an object type to be created. + * @return new instance of a requested class implementing {@link Weapon} interface. + */ + Weapon create(WeaponType name); + + /** + * Creates factory - placeholder for specified {@link Builder}s. + * @param consumer for the new builder to the factory. + * @return factory with specified {@link Builder}s + */ + static WeaponFactory factory(Consumer consumer) { + HashMap> map = new HashMap<>(); + consumer.accept(map::put); + return name -> map.get(name).get(); + } +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponType.java b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponType.java new file mode 100644 index 000000000..ac542048d --- /dev/null +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponType.java @@ -0,0 +1,8 @@ +package com.iluwatar.factorykit; + +/** + * Enumerates {@link Weapon} types + */ +public enum WeaponType { + SWORD, AXE, BOW, SPEAR +} diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java new file mode 100644 index 000000000..9b9af2530 --- /dev/null +++ b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java @@ -0,0 +1,14 @@ +package com.iluwatar.factorykit.app; + +import com.iluwatar.factorykit.App; +import org.junit.Test; + +public class AppTest { + + @Test + public void test() { + String[] args = {}; + App.main(args); + } +} + diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java new file mode 100644 index 000000000..ea629f57d --- /dev/null +++ b/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java @@ -0,0 +1,59 @@ +package com.iluwatar.factorykit.factorykit; + +import com.iluwatar.factorykit.*; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class FactoryKitTest { + + private WeaponFactory factory; + + @Before + public void init() { + factory = WeaponFactory.factory(builder -> { + builder.add(WeaponType.SPEAR, Spear::new); + builder.add(WeaponType.AXE, Axe::new); + builder.add(WeaponType.SWORD, Sword::new); + }); + } + + /** + * Testing {@link WeaponFactory} to produce a SPEAR asserting that the Weapon is an instance of {@link Spear} + */ + @Test + public void testSpearWeapon() { + Weapon weapon = factory.create(WeaponType.SPEAR); + verifyWeapon(weapon, Spear.class); + } + + /** + * Testing {@link WeaponFactory} to produce a AXE asserting that the Weapon is an instance of {@link Axe} + */ + @Test + public void testAxeWeapon() { + Weapon weapon = factory.create(WeaponType.AXE); + verifyWeapon(weapon, Axe.class); + } + + + /** + * Testing {@link WeaponFactory} to produce a SWORD asserting that the Weapon is an instance of {@link Sword} + */ + @Test + public void testWeapon() { + Weapon weapon = factory.create(WeaponType.SWORD); + verifyWeapon(weapon, Sword.class); + } + + /** + * This method asserts that the weapon object that is passed is an instance of the clazz + * + * @param weapon weapon object which is to be verified + * @param clazz expected class of the weapon + */ + private void verifyWeapon(Weapon weapon, Class clazz) { + assertTrue("Weapon must be an object of: " + clazz.getName(), clazz.isInstance(weapon)); + } +} diff --git a/pom.xml b/pom.xml index c15ca20cf..e3bb0d51d 100644 --- a/pom.xml +++ b/pom.xml @@ -119,6 +119,7 @@ publish-subscribe delegation event-driven-architecture + factory-kit feature-toggle value-object