diff --git a/factory/README.md b/factory/README.md index 147ae546c..dd5582bec 100644 --- a/factory/README.md +++ b/factory/README.md @@ -16,16 +16,17 @@ tags: ## Intent -Providing a static method encapsulated in a class called factory, in order to hide the -implementation logic and makes client code focus on usage rather then initialization new objects. +Providing a static method encapsulated in a class called the factory, to hide the implementation +logic and make client code focus on usage rather than initializing new objects. ## Explanation -Real world example +Real-world example -> Lets say we have a web application connected to SQLServer, but now we want to switch to Oracle. To -> do so without modifying existing source code, we need to implements Simple Factory pattern, in -> which a static method can be invoked to create connection to a given database. +> Imagine an alchemist who is about to manufacture coins. The alchemist must be able to create both +> gold and copper coins and switching between them must be possible without modifying the existing +> source code. The factory pattern makes it possible by providing a static construction method which +> can be called with relevant parameters. Wikipedia says @@ -34,16 +35,16 @@ Wikipedia says **Programmatic Example** -We have an interface `Car` and two implementations `Ford` and `Ferrari`. +We have an interface `Coin` and two implementations `GoldCoin` and `CopperCoin`. ```java -public interface Car { +public interface Coin { String getDescription(); } -public class Ford implements Car { +public class GoldCoin implements Coin { - static final String DESCRIPTION = "This is Ford."; + static final String DESCRIPTION = "This is a gold coin."; @Override public String getDescription() { @@ -51,9 +52,9 @@ public class Ford implements Car { } } -public class Ferrari implements Car { +public class CopperCoin implements Coin { - static final String DESCRIPTION = "This is Ferrari."; + static final String DESCRIPTION = "This is a copper coin."; @Override public String getDescription() { @@ -62,51 +63,48 @@ public class Ferrari implements Car { } ``` -Enumeration above represents types of cars that we support (`Ford` and `Ferrari`). +Enumeration above represents types of coins that we support (`GoldCoin` and `CopperCoin`). ```java -public enum CarType { - - FORD(Ford::new), - FERRARI(Ferrari::new); - - private final Supplier constructor; - - CarType(Supplier constructor) { - this.constructor = constructor; - } - - public Supplier getConstructor() { - return this.constructor; - } +@RequiredArgsConstructor +@Getter +public enum CoinType { + + COPPER(CopperCoin::new), + GOLD(GoldCoin::new); + + private final Supplier constructor; } ``` -Then we have the static method `getCar` to create car objects encapsulated in the factory class -`CarsFactory`. + +Then we have the static method `getCoin` to create coin objects encapsulated in the factory class +`CoinFactory`. ```java -public class CarsFactory { - - public static Car getCar(CarType type) { +public class CoinFactory { + + public static Coin getCoin(CoinType type) { return type.getConstructor().get(); } } ``` -Now on the client code we can create different types of cars using the factory class. +Now on the client code we can create different types of coins using the factory class. ```java -var car1 = CarsFactory.getCar(CarType.FORD); -var car2 = CarsFactory.getCar(CarType.FERRARI); -LOGGER.info(car1.getDescription()); -LOGGER.info(car2.getDescription()); +LOGGER.info("The alchemist begins his work."); +var coin1 = CoinFactory.getCoin(CoinType.COPPER); +var coin2 = CoinFactory.getCoin(CoinType.GOLD); +LOGGER.info(coin1.getDescription()); +LOGGER.info(coin2.getDescription()); ``` Program output: ```java -This is Ford. -This is Ferrari. +The alchemist begins his work. +This is a copper coin. +This is a gold coin. ``` ## Class Diagram @@ -115,7 +113,7 @@ This is Ferrari. ## Applicability -Use the Simple Factory pattern when you only care about the creation of a object, not how to create +Use the factory pattern when you only care about the creation of a object, not how to create and manage it. Pros @@ -127,13 +125,13 @@ Cons * The code becomes more complicated than it should be. -## Real world examples +## Known uses * [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) * [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) * [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) * [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) -* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (Returns different singleton objects, depending on a protocol) +* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (returns different singleton objects, depending on a protocol) * [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E)) * [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) and other similar methods. diff --git a/factory/etc/factory.urm.png b/factory/etc/factory.urm.png index 2ba39a571..4b3420792 100644 Binary files a/factory/etc/factory.urm.png and b/factory/etc/factory.urm.png differ diff --git a/factory/etc/factory.urm.puml b/factory/etc/factory.urm.puml index 9eded6328..eb08a4596 100644 --- a/factory/etc/factory.urm.puml +++ b/factory/etc/factory.urm.puml @@ -5,31 +5,32 @@ package com.iluwatar.factory { + App() + main(args : String[]) {static} } - interface Car { + interface Coin { + getDescription() : String {abstract} } - class CarsFactory { - + CarsFactory() - + getCar(type : CarType) : Car {static} + class CoinFactory { + + CoinFactory() + + getCoin(type : CoinType) : Coin {static} } - ~enum CarType { - + FERRARI {static} - + FORD {static} - + valueOf(name : String) : CarType {static} - + values() : CarType[] {static} + enum CoinType { + + COPPER {static} + + GOLD {static} + - constructor : Supplier + + getConstructor() : Supplier + + valueOf(name : String) : CoinType {static} + + values() : CoinType[] {static} } - class Ferrari { + class CopperCoin { ~ DESCRIPTION : String {static} - + Ferrari() + + CopperCoin() + getDescription() : String } - class Ford { + class GoldCoin { ~ DESCRIPTION : String {static} - + Ford() + + GoldCoin() + getDescription() : String } } -CarType ..+ CarsFactory -Ferrari ..|> Car -Ford ..|> Car +CopperCoin ..|> Coin +GoldCoin ..|> Coin @enduml \ No newline at end of file diff --git a/factory/src/main/java/com/iluwatar/factory/App.java b/factory/src/main/java/com/iluwatar/factory/App.java index 732f5458f..6c10fafcb 100644 --- a/factory/src/main/java/com/iluwatar/factory/App.java +++ b/factory/src/main/java/com/iluwatar/factory/App.java @@ -30,8 +30,8 @@ import lombok.extern.slf4j.Slf4j; * create and return objects of varying classes, in order to hide the implementation logic * and makes client code focus on usage rather then objects initialization and management. * - *

In this example the CarFactory is the factory class and it provides a static method to - * create different cars. + *

In this example an alchemist manufactures coins. CoinFactory is the factory class and it + * provides a static method to create different types of coins. */ @Slf4j @@ -41,9 +41,10 @@ public class App { * Program main entry point. */ public static void main(String[] args) { - var car1 = CarsFactory.getCar(CarType.FORD); - var car2 = CarsFactory.getCar(CarType.FERRARI); - LOGGER.info(car1.getDescription()); - LOGGER.info(car2.getDescription()); + LOGGER.info("The alchemist begins his work."); + var coin1 = CoinFactory.getCoin(CoinType.COPPER); + var coin2 = CoinFactory.getCoin(CoinType.GOLD); + LOGGER.info(coin1.getDescription()); + LOGGER.info(coin2.getDescription()); } } diff --git a/factory/src/main/java/com/iluwatar/factory/Car.java b/factory/src/main/java/com/iluwatar/factory/Coin.java similarity index 96% rename from factory/src/main/java/com/iluwatar/factory/Car.java rename to factory/src/main/java/com/iluwatar/factory/Coin.java index e1e248fb4..3b4c1a52a 100644 --- a/factory/src/main/java/com/iluwatar/factory/Car.java +++ b/factory/src/main/java/com/iluwatar/factory/Coin.java @@ -24,9 +24,9 @@ package com.iluwatar.factory; /** - * Car interface. + * Coin interface. */ -public interface Car { +public interface Coin { String getDescription(); diff --git a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java b/factory/src/main/java/com/iluwatar/factory/CoinFactory.java similarity index 87% rename from factory/src/main/java/com/iluwatar/factory/CarsFactory.java rename to factory/src/main/java/com/iluwatar/factory/CoinFactory.java index 941552065..3ff862a23 100644 --- a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java +++ b/factory/src/main/java/com/iluwatar/factory/CoinFactory.java @@ -24,14 +24,14 @@ package com.iluwatar.factory; /** - * Factory of cars. + * Factory of coins. */ -public class CarsFactory { +public class CoinFactory { /** - * Factory method takes as parameter a car type and initiate the appropriate class. + * Factory method takes as a parameter the coin type and calls the appropriate class. */ - public static Car getCar(CarType type) { + public static Coin getCoin(CoinType type) { return type.getConstructor().get(); } } diff --git a/factory/src/main/java/com/iluwatar/factory/CarType.java b/factory/src/main/java/com/iluwatar/factory/CoinType.java similarity index 89% rename from factory/src/main/java/com/iluwatar/factory/CarType.java rename to factory/src/main/java/com/iluwatar/factory/CoinType.java index 074ea32bc..49e0c8166 100644 --- a/factory/src/main/java/com/iluwatar/factory/CarType.java +++ b/factory/src/main/java/com/iluwatar/factory/CoinType.java @@ -28,15 +28,14 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; /** - * Enumeration for different types of cars. + * Enumeration for different types of coins. */ @RequiredArgsConstructor @Getter -public enum CarType { +public enum CoinType { - FORD(Ford::new), - FERRARI(Ferrari::new); - - private final Supplier constructor; + COPPER(CopperCoin::new), + GOLD(GoldCoin::new); + private final Supplier constructor; } diff --git a/factory/src/main/java/com/iluwatar/factory/Ferrari.java b/factory/src/main/java/com/iluwatar/factory/CopperCoin.java similarity index 90% rename from factory/src/main/java/com/iluwatar/factory/Ferrari.java rename to factory/src/main/java/com/iluwatar/factory/CopperCoin.java index c11ee3679..284355360 100644 --- a/factory/src/main/java/com/iluwatar/factory/Ferrari.java +++ b/factory/src/main/java/com/iluwatar/factory/CopperCoin.java @@ -24,11 +24,11 @@ package com.iluwatar.factory; /** - * Ferrari implementation. + * CopperCoin implementation. */ -public class Ferrari implements Car { +public class CopperCoin implements Coin { - static final String DESCRIPTION = "This is Ferrari."; + static final String DESCRIPTION = "This is a copper coin."; @Override public String getDescription() { diff --git a/factory/src/main/java/com/iluwatar/factory/Ford.java b/factory/src/main/java/com/iluwatar/factory/GoldCoin.java similarity index 90% rename from factory/src/main/java/com/iluwatar/factory/Ford.java rename to factory/src/main/java/com/iluwatar/factory/GoldCoin.java index d1091a00b..71eb8debb 100644 --- a/factory/src/main/java/com/iluwatar/factory/Ford.java +++ b/factory/src/main/java/com/iluwatar/factory/GoldCoin.java @@ -24,11 +24,11 @@ package com.iluwatar.factory; /** - * Ford implementation. + * GoldCoin implementation. */ -public class Ford implements Car { +public class GoldCoin implements Coin { - static final String DESCRIPTION = "This is Ford."; + static final String DESCRIPTION = "This is a gold coin."; @Override public String getDescription() { diff --git a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java b/factory/src/test/java/com/iluwatar/factory/CoinFactoryTest.java similarity index 88% rename from factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java rename to factory/src/test/java/com/iluwatar/factory/CoinFactoryTest.java index c29cbbeb4..fadccff55 100644 --- a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java +++ b/factory/src/test/java/com/iluwatar/factory/CoinFactoryTest.java @@ -27,12 +27,11 @@ import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; -class CarsFactoryTest { +class CoinFactoryTest { @Test - void shouldReturnFerrariInstance() { - final var ferrari = CarsFactory.getCar(CarType.FERRARI); - assertTrue(ferrari instanceof Ferrari); + void shouldReturnGoldCoinInstance() { + final var goldCoin = CoinFactory.getCoin(CoinType.GOLD); + assertTrue(goldCoin instanceof GoldCoin); } - }