diff --git a/factory/README.md b/factory/README.md new file mode 100644 index 000000000..42c8838a3 --- /dev/null +++ b/factory/README.md @@ -0,0 +1,128 @@ +--- +layout: pattern +title: Factory +folder: factory +permalink: /patterns/factory/ +categories: Creational +tags: + - Gang of Four +--- + +## Also known as + +* Simple Factory +* Static Factory Method + +## 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. + +## Explanation + +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. + +Wikipedia says + +> Factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class. + +**Programmatic Example** + +We have an interface "Car" and tow implementations "Ford" and "Ferrari". + +```java +/** + * Car interface. + */ +public interface Car { + + public String getDescription(); + +} + +/** + * Ford implementation. + */ +public class Ford implements Car { + + static final String DESCRIPTION = "This is Ford."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +/** + * Ferrari implementation. + */ +public class Ferrari implements Car { + + static final String DESCRIPTION = "This is Ferrari."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} +``` + +Then we have the static method "getCar" to create car objects encapsulated in the factory class "CarSimpleFactory". + +```java +/** + * Factory of cars. + */ +public class CarSimpleFactory { + + /** + * Enumeration for different types of cars. + */ + static enum CarType { + FORD, FERRARI + } + + /** + * Factory method takes as parameter a car type and initiate the appropriate class. + */ + public static Car getCar(CarType type) { + switch (type) { + case FORD: return new Ford(); + case FERRARI: return new Ferrari(); + default: throw new IllegalArgumentException("Model not supported."); + } + } +} +``` + +Now on the client code we can create differentes types of cars(Ford or Ferrari) using the factory class. + +```java +Car car1 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FORD); +Car car2 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FERRARI); +LOGGER.info(car1.getDescription()); +LOGGER.info(car2.getDescription()); +``` + +Program output: + +```java +This is Ford. +This Ferrari. +``` +## Applicability + +Use the Simple Factory pattern when you only care about the creation of a object, not how to create and manage it. + +## Disadvantages: + +The code becomes more complicated than it should be. + +## Related patterns + +[Factory Method](https://java-design-patterns.com/patterns/factory-method/) +[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) +[Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) + + diff --git a/factory/etc/factory.urm.puml b/factory/etc/factory.urm.puml new file mode 100644 index 000000000..9eded6328 --- /dev/null +++ b/factory/etc/factory.urm.puml @@ -0,0 +1,35 @@ +@startuml +package com.iluwatar.factory { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface Car { + + getDescription() : String {abstract} + } + class CarsFactory { + + CarsFactory() + + getCar(type : CarType) : Car {static} + } + ~enum CarType { + + FERRARI {static} + + FORD {static} + + valueOf(name : String) : CarType {static} + + values() : CarType[] {static} + } + class Ferrari { + ~ DESCRIPTION : String {static} + + Ferrari() + + getDescription() : String + } + class Ford { + ~ DESCRIPTION : String {static} + + Ford() + + getDescription() : String + } +} +CarType ..+ CarsFactory +Ferrari ..|> Car +Ford ..|> Car +@enduml \ No newline at end of file diff --git a/factory/pom.xml b/factory/pom.xml new file mode 100644 index 000000000..fbca994a7 --- /dev/null +++ b/factory/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.24.0-SNAPSHOT + + factory + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.factory.App + + + + + + + + + \ 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 new file mode 100644 index 000000000..13f217646 --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/App.java @@ -0,0 +1,51 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.factory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Factory is an object for creating other objects, it providing Providing a static method to + * 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. + */ + +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * Program main entry point. + */ + public static void main(String[] args) { + var car1 = CarsFactory.getCar(CarsFactory.CarType.FORD); + var car2 = CarsFactory.getCar(CarsFactory.CarType.FERRARI); + LOGGER.info(car1.getDescription()); + LOGGER.info(car2.getDescription()); + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/Car.java b/factory/src/main/java/com/iluwatar/factory/Car.java new file mode 100644 index 000000000..6f564233c --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/Car.java @@ -0,0 +1,10 @@ +package com.iluwatar.factory; + +/** + * Car interface. + */ +public interface Car { + + public String getDescription(); + +} diff --git a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java new file mode 100644 index 000000000..01ad157ca --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java @@ -0,0 +1,25 @@ +package com.iluwatar.factory; + +/** + * Factory of cars. + */ +public class CarsFactory { + + /** + * Enumeration for different types of cars. + */ + static enum CarType { + FORD, FERRARI + } + + /** + * Factory method takes as parameter a car type and initiate the appropriate class. + */ + public static Car getCar(CarType type) { + switch (type) { + case FORD: return new Ford(); + case FERRARI: return new Ferrari(); + default: throw new IllegalArgumentException("Model not supported."); + } + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/Ferrari.java b/factory/src/main/java/com/iluwatar/factory/Ferrari.java new file mode 100644 index 000000000..590167f81 --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/Ferrari.java @@ -0,0 +1,14 @@ +package com.iluwatar.factory; + +/** + * Ferrari implementation. + */ +public class Ferrari implements Car { + + static final String DESCRIPTION = "This is Ferrari."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/Ford.java b/factory/src/main/java/com/iluwatar/factory/Ford.java new file mode 100644 index 000000000..13ae7a49e --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/Ford.java @@ -0,0 +1,14 @@ +package com.iluwatar.factory; + +/** + * Ford implementation. + */ +public class Ford implements Car { + + static final String DESCRIPTION = "This is Ford."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} diff --git a/factory/src/test/java/com/iluwatar/factory/AppTest.java b/factory/src/test/java/com/iluwatar/factory/AppTest.java new file mode 100644 index 000000000..d29ffb6a2 --- /dev/null +++ b/factory/src/test/java/com/iluwatar/factory/AppTest.java @@ -0,0 +1,14 @@ +package com.iluwatar.factory; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void shouldExecuteWithoutExceptions() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } + +} diff --git a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java new file mode 100644 index 000000000..eae75919a --- /dev/null +++ b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java @@ -0,0 +1,15 @@ +package com.iluwatar.factory; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class CarsFactoryTest { + + @Test + void shouldReturnFerrariInstance() { + final var ferrari = CarsFactory.getCar(CarsFactory.CarType.FERRARI); + assertTrue(ferrari instanceof Ferrari); + } + +}