diff --git a/extension-objects/README.md b/extension-objects/README.md index 5ecc08efb394..b040900c687d 100644 --- a/extension-objects/README.md +++ b/extension-objects/README.md @@ -1,18 +1,24 @@ --- -title: Extension objects -category: Behavioral +title: Extension Objects +category: Structural language: en tag: - - Extensibility + - Encapsulation + - Extensibility + - Object composition + - Polymorphism --- -# Extention Objects Pattern +## Also known as + +* Interface Extensions ## Intent -Anticipate that an object’s interface needs to be extended in the future. Additional -interfaces are defined by extension objects. + +The Extension Objects pattern allows for the flexible extension of an object's behavior without modifying its structure, by attaching additional objects that can dynamically add new functionality. ## Explanation + Real-world example > Suppose you are developing a Java-based game for a client, and in the middle of the development process, new features are suggested. The Extension Objects pattern empowers your program to adapt to unforeseen changes with minimal refactoring, especially when integrating additional functionalities into your project. @@ -27,10 +33,10 @@ Wikipedia says **Programmatic example** -The aim of utilising the Extension Objects pattern is to implement new features/functionality without having to refactor every class. -The following examples shows utilising this pattern for an Enemy class extending Entity within a game: +The aim of utilising the Extension Objects pattern is to implement new features/functionality without having to refactor every class. The following examples shows utilising this pattern for an Enemy class extending Entity within a game: Primary App class to execute our program from. + ```java public class App { public static void main(String[] args) { @@ -50,7 +56,9 @@ public class App { } } ``` + Enemy class with initial actions and extensions. + ```java class Enemy extends Entity { public Enemy(String name) { @@ -72,7 +80,9 @@ class Enemy extends Entity { } } ``` + EnemyExtension class with overriding extendAction() method. + ```java class EnemyExtension implements EntityExtension { @Override @@ -81,7 +91,9 @@ class EnemyExtension implements EntityExtension { } } ``` + Entity class which will be extended by Enemy. + ```java class Entity { private String name; @@ -105,32 +117,62 @@ class Entity { } } ``` + EntityExtension interface to be used by EnemyExtension. + ```java interface EntityExtension { void extendedAction(); } ``` + Program output: + ```markdown Enemy performs the initial action. Enemy wants to attack you. Enemy has advanced towards you! ``` -In this example, the Extension Objects pattern allows the enemy entity to perform unique initial actions and advanced actions when specific extensions are applied. This pattern provides flexibility and extensibility to the codebase while minimizing the need for major code changes. +In this example, the Extension Objects pattern allows the enemy entity to perform unique initial actions and advanced actions when specific extensions are applied. This pattern provides flexibility and extensibility to the codebase while minimizing the need for major code changes. ## Class diagram + ![Extension_objects](./etc/extension_obj.png "Extension objects") ## Applicability -Use the Extension Objects pattern when: -* you need to support the addition of new or unforeseen interfaces to existing classes and you don't want to impact clients that don't need this new interface. Extension Objects lets you keep related operations together by defining them in a separate class -* a class representing a key abstraction plays different roles for different clients. The number of roles the class can play should be open-ended. There is a need to preserve the key abstraction itself. For example, a customer object is still a customer object even if different subsystems view it differently. -* a class should be extensible with new behavior without subclassing from it. +This pattern is applicable in scenarios where an object's functionality needs to be extended at runtime, avoiding the complications of subclassing. It's particularly useful in systems where object capabilities need to be augmented post-deployment, or where the capabilities might vary significantly across instances. -## Real world examples +## Known Uses +* Extending services in an application server without altering existing code. +* Plugins in IDEs like IntelliJ IDEA or Eclipse to add features to the base application. +* Enabling additional features in enterprise software based on license levels. * [OpenDoc](https://en.wikipedia.org/wiki/OpenDoc) * [Object Linking and Embedding](https://en.wikipedia.org/wiki/Object_Linking_and_Embedding) + +## Consequences + +Benefits: + +* Enhances flexibility by allowing dynamic extension of an object's capabilities. +* Promotes loose coupling between the base object and its extensions. +* Supports the [Open/Closed Principle](https://java-design-patterns.com/principles/#open-closed-principle) by keeping the object open for extension but closed for modification. + +Trade-offs: + +* Can increase complexity due to the management of extension objects. +* May introduce performance overhead if the interaction between objects and extensions is not efficiently designed. + +## Related Patterns + +* [Decorator](https://java-design-patterns.com/patterns/decorator/): Similar in intent to add responsibilities dynamically, but uses a different structure. +* [Composite](https://java-design-patterns.com/patterns/composite/): Also manages a group of objects, which can be seen as a form of extension. +* [Strategy](https://java-design-patterns.com/patterns/strategy/): Offers an alternative way to change the behavior of an object dynamically. + +## Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/4aBMuuL) +* [Pattern-Oriented Software Architecture: A System of Patterns](https://amzn.to/3Q9YOtX) +* [Patterns of Enterprise Application Architecture](https://amzn.to/3W6IZYQ) diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java index e3a3325c95f0..a2ffff94129a 100644 --- a/extension-objects/src/main/java/concreteextensions/Commander.java +++ b/extension-objects/src/main/java/concreteextensions/Commander.java @@ -33,12 +33,8 @@ /** * Class defining Commander. */ -@Getter -@RequiredArgsConstructor @Slf4j -public class Commander implements CommanderExtension { - - private final CommanderUnit unit; +public record Commander(CommanderUnit unit) implements CommanderExtension { @Override public void commanderReady() { diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java index beaf30aa73c9..716bd4a1a638 100644 --- a/extension-objects/src/main/java/concreteextensions/Sergeant.java +++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java @@ -33,12 +33,8 @@ /** * Class defining Sergeant. */ -@Getter -@RequiredArgsConstructor @Slf4j -public class Sergeant implements SergeantExtension { - - private final SergeantUnit unit; +public record Sergeant(SergeantUnit unit) implements SergeantExtension { @Override public void sergeantReady() { diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java index ae17665d4e0b..cbd5d2a1aec8 100644 --- a/extension-objects/src/main/java/concreteextensions/Soldier.java +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -33,12 +33,8 @@ /** * Class defining Soldier. */ -@Getter -@RequiredArgsConstructor @Slf4j -public class Soldier implements SoldierExtension { - - private final SoldierUnit unit; +public record Soldier(SoldierUnit unit) implements SoldierExtension { @Override public void soldierReady() { diff --git a/extension-objects/src/test/java/concreteextensions/CommanderTest.java b/extension-objects/src/test/java/concreteextensions/CommanderTest.java index 56343ba4b4c6..74b668d5edb3 100644 --- a/extension-objects/src/test/java/concreteextensions/CommanderTest.java +++ b/extension-objects/src/test/java/concreteextensions/CommanderTest.java @@ -36,9 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; /** - * Created by Srdjan on 03-May-17. - * - * Modified by ToxicDreamz on 15-Aug-20 + * CommanderTest */ class CommanderTest { @@ -56,10 +54,9 @@ void shouldExecuteCommanderReady() { commander.commanderReady(); List logsList = listAppender.list; - assertEquals("[Commander] " + commander.getUnit().getName() + " is ready!", logsList.get(0) + assertEquals("[Commander] " + commander.unit().getName() + " is ready!", logsList.get(0) .getMessage()); assertEquals(Level.INFO, logsList.get(0) .getLevel()); } - -} \ No newline at end of file +} diff --git a/extension-objects/src/test/java/concreteextensions/SergeantTest.java b/extension-objects/src/test/java/concreteextensions/SergeantTest.java index 2c75e3ef5d7a..13f2f8812248 100644 --- a/extension-objects/src/test/java/concreteextensions/SergeantTest.java +++ b/extension-objects/src/test/java/concreteextensions/SergeantTest.java @@ -54,7 +54,7 @@ void sergeantReady() { sergeant.sergeantReady(); List logsList = listAppender.list; - assertEquals("[Sergeant] " + sergeant.getUnit().getName() + " is ready!", logsList.get(0) + assertEquals("[Sergeant] " + sergeant.unit().getName() + " is ready!", logsList.get(0) .getMessage()); assertEquals(Level.INFO, logsList.get(0) .getLevel()); diff --git a/extension-objects/src/test/java/concreteextensions/SoldierTest.java b/extension-objects/src/test/java/concreteextensions/SoldierTest.java index 9b30f803e197..d5ebcca701d0 100644 --- a/extension-objects/src/test/java/concreteextensions/SoldierTest.java +++ b/extension-objects/src/test/java/concreteextensions/SoldierTest.java @@ -55,7 +55,7 @@ void soldierReady() { soldier.soldierReady(); List logsList = listAppender.list; - assertEquals("[Soldier] " + soldier.getUnit().getName() + " is ready!", logsList.get(0) + assertEquals("[Soldier] " + soldier.unit().getName() + " is ready!", logsList.get(0) .getMessage()); assertEquals(Level.INFO, logsList.get(0) .getLevel()); diff --git a/extension-objects/src/test/java/units/UnitTest.java b/extension-objects/src/test/java/units/UnitTest.java index 6700101a856a..2ec0bcf52b2f 100644 --- a/extension-objects/src/test/java/units/UnitTest.java +++ b/extension-objects/src/test/java/units/UnitTest.java @@ -35,7 +35,7 @@ class UnitTest { @Test - void testConstGetSet() throws Exception { + void testConstGetSet() { final var name = "testName"; final var unit = new Unit(name); assertEquals(name, unit.getName()); diff --git a/facade/README.md b/facade/README.md index 4efa8f7b76c7..b57db7405c6b 100644 --- a/facade/README.md +++ b/facade/README.md @@ -3,23 +3,21 @@ title: Facade category: Structural language: en tag: - - Gang Of Four - - Decoupling + - Code simplification + - Encapsulation + - Gang Of Four + - Object composition --- ## Intent -Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level -interface that makes the subsystem easier to use. +Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. ## Explanation Real-world example -> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you -> believe because you are using a simple interface that goldmine provides on the outside, internally -> it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a -> facade. +> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you believe because you are using a simple interface that goldmine provides on the outside, internally it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a facade. In plain words @@ -27,13 +25,11 @@ In plain words Wikipedia says -> A facade is an object that provides a simplified interface to a larger body of code, such as a -> class library. +> A facade is an object that provides a simplified interface to a larger body of code, such as a class library. **Programmatic Example** -Let's take our goldmine example from above. Here we have the dwarven mine worker hierarchy. First -there's a base class `DwarvenMineWorker`: +Let's take our goldmine example from above. Here we have the dwarven mine worker hierarchy. First, there's a base class `DwarvenMineWorker`: ```java @@ -81,50 +77,50 @@ public abstract class DwarvenMineWorker { } ``` -Then we have the concrete dwarf classes `DwarvenTunnelDigger`, `DwarvenGoldDigger` and -`DwarvenCartOperator`: +Then we have the concrete dwarf classes `DwarvenTunnelDigger`, `DwarvenGoldDigger` and `DwarvenCartOperator`: ```java + @Slf4j public class DwarvenTunnelDigger extends DwarvenMineWorker { - @Override - public void work() { - LOGGER.info("{} creates another promising tunnel.", name()); - } + @Override + public void work() { + LOGGER.info("{} creates another promising tunnel.", name()); + } - @Override - public String name() { - return "Dwarven tunnel digger"; - } + @Override + public String name() { + return "Dwarven tunnel digger"; + } } @Slf4j public class DwarvenGoldDigger extends DwarvenMineWorker { - @Override - public void work() { - LOGGER.info("{} digs for gold.", name()); - } + @Override + public void work() { + LOGGER.info("{} digs for gold.", name()); + } - @Override - public String name() { - return "Dwarf gold digger"; - } + @Override + public String name() { + return "Dwarf gold digger"; + } } @Slf4j public class DwarvenCartOperator extends DwarvenMineWorker { - @Override - public void work() { - LOGGER.info("{} moves gold chunks out of the mine.", name()); - } + @Override + public void work() { + LOGGER.info("{} moves gold chunks out of the mine.", name()); + } - @Override - public String name() { - return "Dwarf cart operator"; - } + @Override + public String name() { + return "Dwarf cart operator"; + } } ``` @@ -134,31 +130,31 @@ To operate all these goldmine workers we have the `DwarvenGoldmineFacade`: ```java public class DwarvenGoldmineFacade { - private final List workers; + private final List workers; - public DwarvenGoldmineFacade() { - workers = List.of( - new DwarvenGoldDigger(), - new DwarvenCartOperator(), - new DwarvenTunnelDigger()); - } + public DwarvenGoldmineFacade() { + workers = List.of( + new DwarvenGoldDigger(), + new DwarvenCartOperator(), + new DwarvenTunnelDigger()); + } - public void startNewDay() { - makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE); - } + public void startNewDay() { + makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE); + } - public void digOutGold() { - makeActions(workers, DwarvenMineWorker.Action.WORK); - } + public void digOutGold() { + makeActions(workers, DwarvenMineWorker.Action.WORK); + } - public void endDay() { - makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP); - } + public void endDay() { + makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP); + } - private static void makeActions(Collection workers, - DwarvenMineWorker.Action... actions) { - workers.forEach(worker -> worker.action(actions)); - } + private static void makeActions(Collection workers, + DwarvenMineWorker.Action... actions) { + workers.forEach(worker -> worker.action(actions)); + } } ``` @@ -199,29 +195,40 @@ Program output: Use the Facade pattern when -* You want to provide a simple interface to a complex subsystem. Subsystems often get more complex -as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the -subsystem more reusable and easier to customize, but it also becomes harder to use for clients that -don't need to customize it. A facade can provide a simple default view of the subsystem that is good -enough for most clients. Only clients needing more customization will need to look beyond the -facade. -* There are many dependencies between clients and the implementation classes of an abstraction. -Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting -subsystem independence and portability. -* You want to layer your subsystems. Use a facade to define an entry point to each subsystem level. -If subsystems are dependent, then you can simplify the dependencies between them by making them -communicate with each other solely through their facades. +* You want to provide a simple interface to a complex subsystem. +* Subsystems are getting more complex and depend on multiple classes, but most clients only need a part of the functionality. +* There is a need to layer your subsystems. Use a facade to define an entry point to each subsystem level. ## Tutorials -*[DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) +* [DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) * [Refactoring Guru](https://refactoring.guru/design-patterns/facade) * [GeekforGeeks](https://www.geeksforgeeks.org/facade-design-pattern-introduction/) * [Tutorialspoint](https://www.tutorialspoint.com/design_pattern/facade_pattern.htm) +## Known Uses + +* Java libraries such as java.net.URL and javax.faces.context.FacesContext use Facade to simplify complex underlying classes. +* In many Java frameworks, facades are used to simplify the usage of APIs by providing a simpler interface to more complex underlying code structures. + +## Consequences + +Benefits: + +* Isolates clients from subsystem components, making it easier to use and reducing dependencies. +* Promotes weak coupling between the subsystem and its clients. +* Often simplifies the API of complex systems. + +Trade-offs: + +* A facade can become a god object coupled to all classes of an app if not implemented correctly. + +## Related Patterns +* Often used with other design patterns like Singleton and Abstract Factory. +* Command pattern can use Facade to define an interface that simplifies methods invocation. ## Credits -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) -* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3QbO7qN) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/3UpTLrG) diff --git a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java index 4236557577ab..08533a572919 100644 --- a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java +++ b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java @@ -84,7 +84,7 @@ void testFullWorkDay() { // Now do some actual work, start digging gold! goldMine.digOutGold(); - // Since we gave the dig command, every worker should be doing it's job ... + // Since we gave the dig command, every worker should be doing its job ... assertTrue(appender.logContains("Dwarf gold digger digs for gold.")); assertTrue(appender.logContains("Dwarf cart operator moves gold chunks out of the mine.")); assertTrue(appender.logContains("Dwarven tunnel digger creates another promising tunnel.")); diff --git a/factory-kit/README.md b/factory-kit/README.md index 392e8586dd82..ce8f00e82713 100644 --- a/factory-kit/README.md +++ b/factory-kit/README.md @@ -3,11 +3,17 @@ title: Factory Kit category: Creational language: en tag: - - Extensibility + - Decoupling + - Encapsulation + - Generic + - Instantiation + - Object composition --- -## Also Known As -Abstract-Factory +## Also known as + +* Object Kit +* Toolkit ## Intent @@ -17,9 +23,7 @@ Define a factory of immutable content with separated builder and factory interfa 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. +> 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 @@ -47,49 +51,47 @@ public class Sword implements Weapon { } } -// Axe, Bow, and Spear are defined similarly +// 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); + 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. +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); + 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 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())); +list.stream().forEach(weapon->LOGGER.info("{}",weapon.toString())); ``` Here is the console output when the example is run. @@ -115,11 +117,28 @@ Use the Factory Kit pattern when * The builder and creator interfaces need to be separated * Game developments and other applications that have user customisation +## Known Uses + +* In Java libraries such as the Java Development Kit (JDK) where different rendering engines might be instantiated based on the runtime environment. +* Frameworks like Spring or applications where dependency injection is heavily used, often implement this pattern to manage object creation more flexibly. + +## Consequences + +Benefits: + +* Promotes loose coupling by eliminating the need to bind application-specific classes into the code. +* Simplifies code by shifting the responsibility of instantiation to a factory object. + +Trade-offs: + +* Can introduce complexity into the code by requiring additional classes and interfaces. +* Sometimes can lead to dependency issues if not properly managed. + ## Related patterns -* [Builder](https://java-design-patterns.com/patterns/builder/) -* [Factory](https://java-design-patterns.com/patterns/factory/) -* [Abstract-Factory](https://java-design-patterns.com/patterns/abstract-factory/) +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Often used together with the Factory Kit to create families of related objects. +* [Builder](https://java-design-patterns.com/patterns/builder/): Can be used to construct complex objects step-by-step using a similar approach. +* [Prototype](https://java-design-patterns.com/patterns/prototype/): Objects that are created by cloning a prototypical instance often use a factory to manage it. ## Tutorials diff --git a/factory-method/README.md b/factory-method/README.md index f6819617c8d4..4359969dea11 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -3,8 +3,11 @@ title: Factory Method category: Creational language: en tag: - - Extensibility - - Gang of Four + - Encapsulation + - Gang of Four + - Instantiation + - Object composition + - Polymorphism --- ## Also known as @@ -13,15 +16,13 @@ Virtual Constructor ## Intent -Define an interface for creating an object, but let subclasses decide which class to instantiate. -Factory Method lets a class defer instantiation to subclasses. +Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. ## Explanation Real-world example -> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. -> Depending on the customer at hand the right type of blacksmith is summoned. +> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. Depending on the customer at hand the right type of blacksmith is summoned. In plain words @@ -29,16 +30,11 @@ In plain words Wikipedia says -> In class-based programming, the factory method pattern is a creational pattern that uses factory -> methods to deal with the problem of creating objects without having to specify the exact class of -> the object that will be created. This is done by creating objects by calling a factory method -> — either specified in an interface and implemented by child classes, or implemented in a base -> class and optionally overridden by derived classes—rather than by calling a constructor. +> In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method — either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor. - **Programmatic Example** +**Programmatic Example** -Taking our blacksmith example above. First of all, we have a `Blacksmith` interface and some -implementations for it: +Taking our blacksmith example above. First of all, we have a `Blacksmith` interface and some implementations for it: ```java public interface Blacksmith { @@ -58,8 +54,7 @@ public class OrcBlacksmith implements Blacksmith { } ``` -When the customers come, the correct type of blacksmith is summoned and requested weapons are -manufactured: +When the customers come, the correct type of blacksmith is summoned and requested weapons are manufactured: ```java Blacksmith blacksmith = new OrcBlacksmith(); @@ -93,8 +88,7 @@ Use the Factory Method pattern when: * Class cannot anticipate the class of objects it must create. * Class wants its subclasses to specify the objects it creates. -* Classes delegate responsibility to one of several helper subclasses, and you want to localize the -knowledge of which helper subclass is the delegate. +* Classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate. ## Known uses @@ -105,9 +99,27 @@ knowledge of which helper subclass is the delegate. * [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-) * [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-) * [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) +* Frameworks that run application components, configured dynamically at runtime. + +## Consequences + +Benefits: + +* Provides hooks for subclasses, creating flexibility in code. +* Connects parallel class hierarchies. +* Eliminates the need to bind application-specific classes into the code. The code only deals with the product interface; hence it can work with any user-defined concrete product classes. + +Trade-offs: + +* Can complicate the code by requiring the addition of new subclasses to implement the extended factory methods. + +## Related Patterns + +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Factory methods are often called within Abstract Factory patterns. +* [Prototype](https://java-design-patterns.com/patterns/prototype/): A factory method that returns a new instance of a class that is a clone of a prototype class. ## Credits -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) -* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) -* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0Rk5y) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/3UpTLrG) +* [Patterns of Enterprise Application Architecture](https://amzn.to/4b2ZxoM) diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java index b076650eefb8..e055132e2733 100644 --- a/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java +++ b/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java @@ -30,11 +30,7 @@ /** * ElfWeapon. */ -@RequiredArgsConstructor -@Getter -public class ElfWeapon implements Weapon { - - private final WeaponType weaponType; +public record ElfWeapon(WeaponType weaponType) implements Weapon { @Override public String toString() { diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java index 901e2028841f..8446b9099451 100644 --- a/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java +++ b/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java @@ -30,11 +30,7 @@ /** * OrcWeapon. */ -@RequiredArgsConstructor -@Getter -public class OrcWeapon implements Weapon { - - private final WeaponType weaponType; +public record OrcWeapon(WeaponType weaponType) implements Weapon { @Override public String toString() { diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java index 37c528bedee6..97f8cb1d7aec 100644 --- a/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java +++ b/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java @@ -29,6 +29,6 @@ */ public interface Weapon { - WeaponType getWeaponType(); + WeaponType weaponType(); } diff --git a/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java b/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java index 9aa89d455cb1..25b15836eaa2 100644 --- a/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java +++ b/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java @@ -98,6 +98,6 @@ void testElfBlacksmithWithSpear() { private void verifyWeapon(Weapon weapon, WeaponType expectedWeaponType, Class clazz) { assertTrue(clazz.isInstance(weapon), "Weapon must be an object of: " + clazz.getName()); assertEquals(expectedWeaponType, weapon - .getWeaponType(), "Weapon must be of weaponType: " + expectedWeaponType); + .weaponType(), "Weapon must be of weaponType: " + expectedWeaponType); } } diff --git a/factory/README.md b/factory/README.md index ed841bd0e2da..7ee6feffaf3e 100644 --- a/factory/README.md +++ b/factory/README.md @@ -3,32 +3,23 @@ title: Factory category: Creational language: en tag: - - Gang of Four + - Gang of Four + - Instantiation --- -## Also known as - -* Simple Factory -* Static Factory Method - ## Intent -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. +The Factory design pattern is intended to define an interface for creating an object, but allows subclasses to alter the type of objects that will be created. This pattern is particularly useful when the creation process involves complexity. ## Explanation Real-world example -> 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. +> 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 -> 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. +> 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** @@ -74,8 +65,7 @@ public enum CoinType { } ``` -Then we have the static method `getCoin` to create coin objects encapsulated in the factory class -`CoinFactory`. +Then we have the static method `getCoin` to create coin objects encapsulated in the factory class `CoinFactory`. ```java public class CoinFactory { @@ -110,17 +100,9 @@ This is a gold coin. ## Applicability -Use the factory pattern when you only care about the creation of an object, not how to create -and manage it. - -Pros - -* Allows keeping all objects creation in one place and avoid of spreading 'new' keyword across codebase. -* Allows to write loosely coupled code. Some of its main advantages include better testability, easy-to-understand code, swappable components, scalability and isolated features. - -Cons - -* The code becomes more complicated than it should be. +* Use the Factory pattern in Java when the class doesn't know beforehand the exact types and dependencies of the objects it needs to create. +* When a method returns one of several possible classes that share a common super class and wants to encapsulate the logic of which object to create. +* The pattern is commonly used when designing frameworks or libraries to give the best flexibility and isolation from concrete class types. ## Known uses @@ -131,9 +113,28 @@ Cons * [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. +* JavaFX uses Factory patterns for creating various UI controls tailored to the specifics of the user's environment. + +## Consequences + +Benefits: + +* Reduces coupling between the implementation of an application and the classes it uses. +* Supports the [Open/Closed Principle](https://java-design-patterns.com/principles/#open-closed-principle), as the system can introduce new types without changing existing code. + +Trade-offs: + +* The code can become more complicated due to the introduction of multiple additional classes. +* Overuse can make the code less readable if the underlying complexity of the object creation is low or unnecessary. + +## Related Patterns + +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Can be considered a kind of Factory that works with groups of products. +* [Singleton](https://java-design-patterns.com/patterns/singleton/): Often used in conjunction with Factory to ensure that a class has only one instance. +* [Builder](https://java-design-patterns.com/patterns/builder/): Separates the construction of a complex object from its representation, similar to how factories manage instantiation. +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): Is a factory of immutable content with separated builder and factory interfaces. -## Related patterns +## Credits -* [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/) +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0Rk5y) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/3UpTLrG) diff --git a/factory/src/main/java/com/iluwatar/factory/App.java b/factory/src/main/java/com/iluwatar/factory/App.java index 3162828e1003..d1f3313b4b31 100644 --- a/factory/src/main/java/com/iluwatar/factory/App.java +++ b/factory/src/main/java/com/iluwatar/factory/App.java @@ -31,7 +31,7 @@ * create and return objects of varying classes, in order to hide the implementation logic * and makes client code focus on usage rather than objects initialization and management. * - *

In this example an alchemist manufactures coins. CoinFactory is the factory class and it + *

In this example an alchemist manufactures coins. CoinFactory is the factory class, and it * provides a static method to create different types of coins. */