Update factory example

This commit is contained in:
Ilkka Seppälä 2021-06-13 10:50:29 +03:00
parent 0d41af972d
commit 588b106ada
No known key found for this signature in database
GPG Key ID: 31B7C8F5CC412ECB
10 changed files with 85 additions and 87 deletions

View File

@ -16,16 +16,17 @@ tags:
## Intent ## Intent
Providing a static method encapsulated in a class called factory, in order to hide the Providing a static method encapsulated in a class called the factory, to hide the implementation
implementation logic and makes client code focus on usage rather then initialization new objects. logic and make client code focus on usage rather than initializing new objects.
## Explanation ## 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 > Imagine an alchemist who is about to manufacture coins. The alchemist must be able to create both
> do so without modifying existing source code, we need to implements Simple Factory pattern, in > gold and copper coins and switching between them must be possible without modifying the existing
> which a static method can be invoked to create connection to a given database. > source code. The factory pattern makes it possible by providing a static construction method which
> can be called with relevant parameters.
Wikipedia says Wikipedia says
@ -34,16 +35,16 @@ Wikipedia says
**Programmatic Example** **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 ```java
public interface Car { public interface Coin {
String getDescription(); 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 @Override
public String getDescription() { 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 @Override
public String getDescription() { 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 ```java
public enum CarType { @RequiredArgsConstructor
@Getter
FORD(Ford::new), public enum CoinType {
FERRARI(Ferrari::new);
COPPER(CopperCoin::new),
private final Supplier<Car> constructor; GOLD(GoldCoin::new);
CarType(Supplier<Car> constructor) { private final Supplier<Coin> constructor;
this.constructor = constructor;
}
public Supplier<Car> getConstructor() {
return this.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 ```java
public class CarsFactory { public class CoinFactory {
public static Car getCar(CarType type) { public static Coin getCoin(CoinType type) {
return type.getConstructor().get(); 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 ```java
var car1 = CarsFactory.getCar(CarType.FORD); LOGGER.info("The alchemist begins his work.");
var car2 = CarsFactory.getCar(CarType.FERRARI); var coin1 = CoinFactory.getCoin(CoinType.COPPER);
LOGGER.info(car1.getDescription()); var coin2 = CoinFactory.getCoin(CoinType.GOLD);
LOGGER.info(car2.getDescription()); LOGGER.info(coin1.getDescription());
LOGGER.info(coin2.getDescription());
``` ```
Program output: Program output:
```java ```java
This is Ford. The alchemist begins his work.
This is Ferrari. This is a copper coin.
This is a gold coin.
``` ```
## Class Diagram ## Class Diagram
@ -115,7 +113,7 @@ This is Ferrari.
## Applicability ## 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. and manage it.
Pros Pros
@ -127,13 +125,13 @@ Cons
* The code becomes more complicated than it should be. * 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.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.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.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.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)) * [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. * [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) and other similar methods.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -5,31 +5,32 @@ package com.iluwatar.factory {
+ App() + App()
+ main(args : String[]) {static} + main(args : String[]) {static}
} }
interface Car { interface Coin {
+ getDescription() : String {abstract} + getDescription() : String {abstract}
} }
class CarsFactory { class CoinFactory {
+ CarsFactory() + CoinFactory()
+ getCar(type : CarType) : Car {static} + getCoin(type : CoinType) : Coin {static}
} }
~enum CarType { enum CoinType {
+ FERRARI {static} + COPPER {static}
+ FORD {static} + GOLD {static}
+ valueOf(name : String) : CarType {static} - constructor : Supplier<Coin>
+ values() : CarType[] {static} + getConstructor() : Supplier<Coin>
+ valueOf(name : String) : CoinType {static}
+ values() : CoinType[] {static}
} }
class Ferrari { class CopperCoin {
~ DESCRIPTION : String {static} ~ DESCRIPTION : String {static}
+ Ferrari() + CopperCoin()
+ getDescription() : String + getDescription() : String
} }
class Ford { class GoldCoin {
~ DESCRIPTION : String {static} ~ DESCRIPTION : String {static}
+ Ford() + GoldCoin()
+ getDescription() : String + getDescription() : String
} }
} }
CarType ..+ CarsFactory CopperCoin ..|> Coin
Ferrari ..|> Car GoldCoin ..|> Coin
Ford ..|> Car
@enduml @enduml

View File

@ -30,8 +30,8 @@ import lombok.extern.slf4j.Slf4j;
* create and return objects of varying classes, in order to hide the implementation logic * 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. * and makes client code focus on usage rather then objects initialization and management.
* *
* <p>In this example the CarFactory is the factory class and it provides a static method to * <p>In this example an alchemist manufactures coins. CoinFactory is the factory class and it
* create different cars. * provides a static method to create different types of coins.
*/ */
@Slf4j @Slf4j
@ -41,9 +41,10 @@ public class App {
* Program main entry point. * Program main entry point.
*/ */
public static void main(String[] args) { public static void main(String[] args) {
var car1 = CarsFactory.getCar(CarType.FORD); LOGGER.info("The alchemist begins his work.");
var car2 = CarsFactory.getCar(CarType.FERRARI); var coin1 = CoinFactory.getCoin(CoinType.COPPER);
LOGGER.info(car1.getDescription()); var coin2 = CoinFactory.getCoin(CoinType.GOLD);
LOGGER.info(car2.getDescription()); LOGGER.info(coin1.getDescription());
LOGGER.info(coin2.getDescription());
} }
} }

View File

@ -24,9 +24,9 @@
package com.iluwatar.factory; package com.iluwatar.factory;
/** /**
* Car interface. * Coin interface.
*/ */
public interface Car { public interface Coin {
String getDescription(); String getDescription();

View File

@ -24,14 +24,14 @@
package com.iluwatar.factory; 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(); return type.getConstructor().get();
} }
} }

View File

@ -28,15 +28,14 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
/** /**
* Enumeration for different types of cars. * Enumeration for different types of coins.
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
public enum CarType { public enum CoinType {
FORD(Ford::new), COPPER(CopperCoin::new),
FERRARI(Ferrari::new); GOLD(GoldCoin::new);
private final Supplier<Car> constructor;
private final Supplier<Coin> constructor;
} }

View File

@ -24,11 +24,11 @@
package com.iluwatar.factory; 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 @Override
public String getDescription() { public String getDescription() {

View File

@ -24,11 +24,11 @@
package com.iluwatar.factory; 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 @Override
public String getDescription() { public String getDescription() {

View File

@ -27,12 +27,11 @@ import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class CarsFactoryTest { class CoinFactoryTest {
@Test @Test
void shouldReturnFerrariInstance() { void shouldReturnGoldCoinInstance() {
final var ferrari = CarsFactory.getCar(CarType.FERRARI); final var goldCoin = CoinFactory.getCoin(CoinType.GOLD);
assertTrue(ferrari instanceof Ferrari); assertTrue(goldCoin instanceof GoldCoin);
} }
} }