properties) {
super(properties);
}
}
- private DocumentImplementation document = new DocumentImplementation(new HashMap<>());
+ private final DocumentImplementation document = new DocumentImplementation(new HashMap<>());
@Test
public void shouldPutAndGetValue() {
diff --git a/abstract-factory/README.md b/abstract-factory/README.md
index 6a840f316..141bf5021 100644
--- a/abstract-factory/README.md
+++ b/abstract-factory/README.md
@@ -9,13 +9,16 @@ tags:
---
## Also known as
+
Kit
## Intent
+
Provide an interface for creating families of related or dependent
objects without specifying their concrete classes.
## Explanation
+
Real world example
> To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
@@ -36,9 +39,11 @@ Translating the kingdom example above. First of all we have some interfaces and
public interface Castle {
String getDescription();
}
+
public interface King {
String getDescription();
}
+
public interface Army {
String getDescription();
}
@@ -66,7 +71,7 @@ public class ElfArmy implements Army {
}
}
-// Orcish implementations similarly...
+// Orcish implementations similarly -> ...
```
@@ -112,9 +117,17 @@ var castle = factory.createCastle();
var king = factory.createKing();
var army = factory.createArmy();
-castle.getDescription(); // Output: This is the Elven castle!
-king.getDescription(); // Output: This is the Elven king!
-army.getDescription(); // Output: This is the Elven Army!
+castle.getDescription();
+king.getDescription();
+army.getDescription();
+```
+
+Program output:
+
+```java
+This is the Elven castle!
+This is the Elven king!
+This is the Elven Army!
```
Now, we can design a factory for our different kingdom factories. In this example, we created FactoryMaker, responsible for returning an instance of either ElfKingdomFactory or OrcKingdomFactory.
@@ -156,37 +169,39 @@ public static void main(String[] args) {
```
## Class diagram
+

## Applicability
+
Use the Abstract Factory pattern when
-* a system should be independent of how its products are created, composed and represented
-* a system should be configured with one of multiple families of products
-* a family of related product objects is designed to be used together, and you need to enforce this constraint
-* you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
-* the lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
-* you need a run-time value to construct a particular dependency
-* you want to decide which product to call from a family at runtime.
-* you need to supply one or more parameters only known at run-time before you can resolve a dependency.
-* when you need consistency among products
-* you don’t want to change existing code when adding new products or families of products to the program.
+* The system should be independent of how its products are created, composed and represented
+* The system should be configured with one of multiple families of products
+* The family of related product objects is designed to be used together, and you need to enforce this constraint
+* You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
+* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
+* You need a run-time value to construct a particular dependency
+* You want to decide which product to call from a family at runtime.
+* You need to supply one or more parameters only known at run-time before you can resolve a dependency.
+* When you need consistency among products
+* You don’t want to change existing code when adding new products or families of products to the program.
## Use Cases:
-* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
-* Unit test case writing becomes much easier
+* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
+* Unit test case writing becomes much easier
* UI tools for different OS
## Consequences:
-* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
+* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
* While the pattern is great when creating predefined objects, adding the new ones might be challenging.
-* The code may become more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
-
+* The code becomes more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
## Tutorial
+
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
@@ -198,4 +213,5 @@ Use the Abstract Factory pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
index be83cc315..f3db525a1 100644
--- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
+++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class AbstractFactoryTest {
- private App app = new App();
+ private final App app = new App();
private KingdomFactory elfFactory;
private KingdomFactory orcFactory;
diff --git a/acyclic-visitor/README.md b/acyclic-visitor/README.md
index f293e4393..19e886505 100644
--- a/acyclic-visitor/README.md
+++ b/acyclic-visitor/README.md
@@ -9,12 +9,126 @@ tags:
---
## Intent
-Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating the troublesome dependency cycles that are inherent to the GOF VISITOR Pattern.
+
+Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating
+the troublesome dependency cycles that are inherent to the GoF Visitor Pattern.
+
+## Explanation
+
+Real world example
+
+> We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based
+> on filtering criteria (is it Unix or DOS compatible modem).
+
+In plain words
+
+> Acyclic Visitor allows functions to be added to existing class hierarchies without modifying the hierarchies.
+
+[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) says
+
+> The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies without affecting those
+> hierarchies, and without creating the dependency cycles that are inherent to the GangOfFour VisitorPattern.
+
+**Programmatic Example**
+
+Here's the `Modem` hierarchy.
+
+```java
+public abstract class Modem {
+ public abstract void accept(ModemVisitor modemVisitor);
+}
+
+public class Zoom extends Modem {
+ ...
+ @Override
+ public void accept(ModemVisitor modemVisitor) {
+ if (modemVisitor instanceof ZoomVisitor) {
+ ((ZoomVisitor) modemVisitor).visit(this);
+ } else {
+ LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem");
+ }
+ }
+}
+
+public class Hayes extends Modem {
+ ...
+ @Override
+ public void accept(ModemVisitor modemVisitor) {
+ if (modemVisitor instanceof HayesVisitor) {
+ ((HayesVisitor) modemVisitor).visit(this);
+ } else {
+ LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem");
+ }
+ }
+}
+```
+
+Next we introduce the `ModemVisitor` hierarchy.
+
+```java
+public interface ModemVisitor {
+}
+
+public interface HayesVisitor extends ModemVisitor {
+ void visit(Hayes hayes);
+}
+
+public interface ZoomVisitor extends ModemVisitor {
+ void visit(Zoom zoom);
+}
+
+public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
+}
+
+public class ConfigureForDosVisitor implements AllModemVisitor {
+ ...
+ @Override
+ public void visit(Hayes hayes) {
+ LOGGER.info(hayes + " used with Dos configurator.");
+ }
+ @Override
+ public void visit(Zoom zoom) {
+ LOGGER.info(zoom + " used with Dos configurator.");
+ }
+}
+
+public class ConfigureForUnixVisitor implements ZoomVisitor {
+ ...
+ @Override
+ public void visit(Zoom zoom) {
+ LOGGER.info(zoom + " used with Unix configurator.");
+ }
+}
+```
+
+Finally here are the visitors in action.
+
+```java
+ var conUnix = new ConfigureForUnixVisitor();
+ var conDos = new ConfigureForDosVisitor();
+ var zoom = new Zoom();
+ var hayes = new Hayes();
+ hayes.accept(conDos);
+ zoom.accept(conDos);
+ hayes.accept(conUnix);
+ zoom.accept(conUnix);
+```
+
+Program output:
+
+```
+ // Hayes modem used with Dos configurator.
+ // Zoom modem used with Dos configurator.
+ // Only HayesVisitor is allowed to visit Hayes modem
+ // Zoom modem used with Unix configurator.
+```
## Class diagram
+

## Applicability
+
This pattern can be used:
* When you need to add a new function to an existing hierarchy without the need to alter or affect that hierarchy.
@@ -24,6 +138,7 @@ This pattern can be used:
* When the recompilation, relinking, retesting or redistribution of the derivatives of Element is very expensive.
## Consequences
+
The good:
* No dependency cycles between class hierarchies.
@@ -32,11 +147,14 @@ The good:
The bad:
-* Violates the principle of least surprise or Liskov's Substitution principle by showing that it can accept all visitors but actually only being interested in particular visitors.
+* Violates [Liskov's Substitution Principle](https://java-design-patterns.com/principles/#liskov-substitution-principle) by showing that it can accept all visitors but actually only being interested in particular visitors.
* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy.
## Related patterns
-* [Visitor Pattern](../visitor/)
+
+* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/)
## Credits
-* [Acyclic Visitor](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
+
+* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
+* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor)
diff --git a/acyclic-visitor/etc/Acyclic Visitor.ucls b/acyclic-visitor/etc/Acyclic Visitor.ucls
deleted file mode 100644
index 03b6c77dd..000000000
--- a/acyclic-visitor/etc/Acyclic Visitor.ucls
+++ /dev/null
@@ -1,115 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/acyclic-visitor/etc/acyclic-visitor.png b/acyclic-visitor/etc/acyclic-visitor.png
index 636532c4d..7b4df13d8 100644
Binary files a/acyclic-visitor/etc/acyclic-visitor.png and b/acyclic-visitor/etc/acyclic-visitor.png differ
diff --git a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java
index 8847a131e..79097a454 100644
--- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java
+++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java
@@ -37,7 +37,7 @@ import uk.org.lidalia.slf4jtest.TestLoggerFactory;
*/
public class ConfigureForDosVisitorTest {
- private TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
+ private final TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
@Test
public void testVisitForZoom() {
diff --git a/adapter/README.md b/adapter/README.md
index a8a0214be..75edad180 100644
--- a/adapter/README.md
+++ b/adapter/README.md
@@ -56,7 +56,7 @@ And captain expects an implementation of `RowingBoat` interface to be able to mo
```java
public class Captain {
- private RowingBoat rowingBoat;
+ private final RowingBoat rowingBoat;
// default constructor and setter for rowingBoat
public Captain(RowingBoat rowingBoat) {
this.rowingBoat = rowingBoat;
@@ -75,7 +75,7 @@ public class FishingBoatAdapter implements RowingBoat {
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
- private FishingBoat boat;
+ private final FishingBoat boat;
public FishingBoatAdapter() {
boat = new FishingBoat();
@@ -129,5 +129,7 @@ An object adapter
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [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)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+* [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)
diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java
index 5ccde5c53..39a9adab4 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java
@@ -29,7 +29,7 @@ package com.iluwatar.adapter;
*/
public class FishingBoatAdapter implements RowingBoat {
- private FishingBoat boat;
+ private final FishingBoat boat;
public FishingBoatAdapter() {
boat = new FishingBoat();
diff --git a/ambassador/README.md b/ambassador/README.md
index 78b3a8856..11abfaf88 100644
--- a/ambassador/README.md
+++ b/ambassador/README.md
@@ -5,7 +5,8 @@ folder: ambassador
permalink: /patterns/ambassador/
categories: Structural
tags:
- - Decoupling
+ - Decoupling
+ - Cloud distributed
---
## Intent
@@ -22,8 +23,7 @@ In plain words
Microsoft documentation states
-> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client.
- This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
+> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
**Programmatic Example**
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
index 3cfea2623..6c45acf66 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
@@ -48,7 +48,7 @@ class RemoteServiceTest {
}
private static class StaticRandomProvider implements RandomProvider {
- private double value;
+ private final double value;
StaticRandomProvider(double value) {
this.value = value;
diff --git a/api-gateway/README.md b/api-gateway/README.md
index 3a4f13e35..0d67b8d9b 100644
--- a/api-gateway/README.md
+++ b/api-gateway/README.md
@@ -5,14 +5,142 @@ folder: api-gateway
permalink: /patterns/api-gateway/
categories: Architectural
tags:
-- Cloud distributed
-- Decoupling
+ - Cloud distributed
+ - Decoupling
+ - Microservices
---
## Intent
-Aggregate calls to microservices in a single location: the API Gateway. The user makes a single
-call to the API Gateway, and the API Gateway then calls each relevant microservice.
+Aggregate calls to microservices in a single location: the API Gateway. The user makes a single call to the API Gateway,
+and the API Gateway then calls each relevant microservice.
+
+## Explanation
+
+With the Microservices pattern, a client may need data from multiple different microservices. If the client called each
+microservice directly, that could contribute to longer load times, since the client would have to make a network request
+for each microservice called. Moreover, having the client call each microservice directly ties the client to that
+microservice - if the internal implementations of the microservices change (for example, if two microservices are
+combined sometime in the future) or if the location (host and port) of a microservice changes, then every client that
+makes use of those microservices must be updated.
+
+The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway pattern, an additional
+entity (the API Gateway) is placed between the client and the microservices. The job of the API Gateway is to aggregate
+the calls to the microservices. Rather than the client calling each microservice individually, the client calls the
+API Gateway a single time. The API Gateway then calls each of the microservices that the client needs.
+
+Real world example
+
+> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system the API Gateway makes
+calls to the Image and Price microservices.
+
+In plain words
+
+> For a system implemented using microservices architecture, API Gateway is the single entry point that aggregates the
+calls to the individual microservices.
+
+Wikipedia says
+
+> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling and security
+policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often
+includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also
+provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to
+support authentication, authorization, security, audit and regulatory compliance.
+
+**Programmatic Example**
+
+This implementation shows what the API Gateway pattern could look like for an e-commerce site. The `ApiGateway` makes
+calls to the Image and Price microservices using the `ImageClientImpl` and `PriceClientImpl` respectively. Customers
+viewing the site on a desktop device can see both price information and an image of a product, so the `ApiGateway` calls
+both of the microservices and aggregates the data in the `DesktopProduct` model. However, mobile users only see price
+information; they do not see a product image. For mobile users, the `ApiGateway` only retrieves price information, which
+it uses to populate the `MobileProduct`.
+
+Here's the Image microservice implementation.
+
+```java
+public interface ImageClient {
+ String getImagePath();
+}
+
+public class ImageClientImpl implements ImageClient {
+
+ @Override
+ public String getImagePath() {
+ var httpClient = HttpClient.newHttpClient();
+ var httpGet = HttpRequest.newBuilder()
+ .GET()
+ .uri(URI.create("http://localhost:50005/image-path"))
+ .build();
+
+ try {
+ var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
+ return httpResponse.body();
+ } catch (IOException | InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
+```
+
+Here's the Price microservice implementation.
+
+```java
+public interface PriceClient {
+ String getPrice();
+}
+
+public class PriceClientImpl implements PriceClient {
+
+ @Override
+ public String getPrice() {
+ var httpClient = HttpClient.newHttpClient();
+ var httpGet = HttpRequest.newBuilder()
+ .GET()
+ .uri(URI.create("http://localhost:50006/price"))
+ .build();
+
+ try {
+ var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
+ return httpResponse.body();
+ } catch (IOException | InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
+```
+
+And here we can see how API Gateway maps the requests to the microservices.
+
+```java
+public class ApiGateway {
+
+ @Resource
+ private ImageClient imageClient;
+
+ @Resource
+ private PriceClient priceClient;
+
+ @RequestMapping(path = "/desktop", method = RequestMethod.GET)
+ public DesktopProduct getProductDesktop() {
+ var desktopProduct = new DesktopProduct();
+ desktopProduct.setImagePath(imageClient.getImagePath());
+ desktopProduct.setPrice(priceClient.getPrice());
+ return desktopProduct;
+ }
+
+ @RequestMapping(path = "/mobile", method = RequestMethod.GET)
+ public MobileProduct getProductMobile() {
+ var mobileProduct = new MobileProduct();
+ mobileProduct.setPrice(priceClient.getPrice());
+ return mobileProduct;
+ }
+}
+```
## Class diagram

@@ -21,10 +149,11 @@ call to the API Gateway, and the API Gateway then calls each relevant microservi
Use the API Gateway pattern when
-* you're also using the Microservices pattern and need a single point of aggregation for your
-microservice calls
+* You're using microservices architecture and need a single point of aggregation for your microservice calls.
## Credits
* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html)
* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)
+* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=ac7b6a57f866ac006a309d9086e8cfbd)
+* [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/gp/product/1491950358/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1491950358&linkId=4c95ca9831e05e3f0dadb08841d77bf1)
diff --git a/arrange-act-assert/README.md b/arrange-act-assert/README.md
new file mode 100644
index 000000000..02b7ee8b7
--- /dev/null
+++ b/arrange-act-assert/README.md
@@ -0,0 +1,30 @@
+---
+layout: pattern
+title: Arrange/Act/Assert
+folder: arrange-act-assert
+permalink: /patterns/arrange-act-assert/
+categories: Idiom
+tags:
+ - Testing
+---
+
+## Also known as
+Given/When/Then
+
+## Intent
+The Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
+It breaks tests down into three clear and distinct steps:
+1. Arrange: Perform the setup and initialization required for the test.
+2. Act: Take action(s) required for the test.
+3. Assert: Verify the outcome(s) of the test.
+
+## Applicability
+Use Arrange/Act/Assert pattern when
+
+* you need to structure your unit tests so they're easier to read, maintain, and enhance.
+
+## Credits
+
+* [Arrange, Act, Assert: What is AAA Testing?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx)
+* [Bill Wake: 3A – Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/)
+* [Martin Fowler: GivenWhenThen](https://martinfowler.com/bliki/GivenWhenThen.html)
diff --git a/arrange-act-assert/etc/arrange-act-assert.urm.puml b/arrange-act-assert/etc/arrange-act-assert.urm.puml
new file mode 100644
index 000000000..4b22d2a4e
--- /dev/null
+++ b/arrange-act-assert/etc/arrange-act-assert.urm.puml
@@ -0,0 +1,11 @@
+@startuml
+package com.iluwatar.arrangeactassert {
+ class Cash {
+ - amount : int
+ ~ Cash(amount : int)
+ ~ count() : int
+ ~ minus(subtrahend : int) : boolean
+ ~ plus(addend : int)
+ }
+}
+@enduml
\ No newline at end of file
diff --git a/arrange-act-assert/pom.xml b/arrange-act-assert/pom.xml
new file mode 100644
index 000000000..bb0387e7a
--- /dev/null
+++ b/arrange-act-assert/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.23.0-SNAPSHOT
+
+ 4.0.0
+
+ arrange-act-assert
+
+
+ junit
+ junit
+ test
+
+
+
\ No newline at end of file
diff --git a/arrange-act-assert/src/main/java/com/iluwatar/arrangeactassert/Cash.java b/arrange-act-assert/src/main/java/com/iluwatar/arrangeactassert/Cash.java
new file mode 100644
index 000000000..71269359e
--- /dev/null
+++ b/arrange-act-assert/src/main/java/com/iluwatar/arrangeactassert/Cash.java
@@ -0,0 +1,57 @@
+/*
+ * 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.arrangeactassert;
+
+/**
+ * Arrange/Act/Assert (AAA) is a unit test pattern. In this simple example, we have a ({@link Cash})
+ * object for plus, minus and counting amount.
+ */
+public class Cash {
+
+ private int amount;
+
+ Cash(int amount) {
+ this.amount = amount;
+ }
+
+ //plus
+ void plus(int addend) {
+ amount += addend;
+ }
+
+ //minus
+ boolean minus(int subtrahend) {
+ if (amount >= subtrahend) {
+ amount -= subtrahend;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //count
+ int count() {
+ return amount;
+ }
+}
diff --git a/arrange-act-assert/src/test/java/com/iluwatar/arrangeactassert/CashAAATest.java b/arrange-act-assert/src/test/java/com/iluwatar/arrangeactassert/CashAAATest.java
new file mode 100644
index 000000000..115dd3a11
--- /dev/null
+++ b/arrange-act-assert/src/test/java/com/iluwatar/arrangeactassert/CashAAATest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.arrangeactassert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Arrange/Act/Assert (AAA) is a pattern for organizing unit tests. It is a way to structure your
+ * tests so they're easier to read, maintain and enhance.
+ *
+ * It breaks tests down into three clear and distinct steps:
+ *
1. Arrange: Perform the setup and initialization required for the test.
+ *
2. Act: Take action(s) required for the test.
+ *
3. Assert: Verify the outcome(s) of the test.
+ *
+ *
This pattern has several significant benefits. It creates a clear separation between a test's
+ * setup, operations, and results. This structure makes the code easier to read and understand. If
+ * you place the steps in order and format your code to separate them, you can scan a test and
+ * quickly comprehend what it does.
+ *
+ *
It also enforces a certain degree of discipline when you write your tests. You have to think
+ * clearly about the three steps your test will perform. But it makes tests more natural to write at
+ * the same time since you already have an outline.
+ *
+ *
In ({@link CashAAATest}) we have four test methods. Each of them has only one reason to
+ * change and one reason to fail. In a large and complicated code base, tests that honor the single
+ * responsibility principle are much easier to troubleshoot.
+ */
+public class CashAAATest {
+
+ @Test
+ public void testPlus() {
+ //Arrange
+ var cash = new Cash(3);
+ //Act
+ cash.plus(4);
+ //Assert
+ assertEquals(7, cash.count());
+ }
+
+ @Test
+ public void testMinus() {
+ //Arrange
+ var cash = new Cash(8);
+ //Act
+ var result = cash.minus(5);
+ //Assert
+ assertTrue(result);
+ assertEquals(3, cash.count());
+ }
+
+ @Test
+ public void testInsufficientMinus() {
+ //Arrange
+ var cash = new Cash(1);
+ //Act
+ var result = cash.minus(6);
+ //Assert
+ assertFalse(result);
+ assertEquals(1, cash.count());
+ }
+
+ @Test
+ public void testUpdate() {
+ //Arrange
+ var cash = new Cash(5);
+ //Act
+ cash.plus(6);
+ var result = cash.minus(3);
+ //Assert
+ assertTrue(result);
+ assertEquals(8, cash.count());
+ }
+}
diff --git a/arrange-act-assert/src/test/java/com/iluwatar/arrangeactassert/CashAntiAAATest.java b/arrange-act-assert/src/test/java/com/iluwatar/arrangeactassert/CashAntiAAATest.java
new file mode 100644
index 000000000..564b923e7
--- /dev/null
+++ b/arrange-act-assert/src/test/java/com/iluwatar/arrangeactassert/CashAntiAAATest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.arrangeactassert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * ({@link CashAAATest}) is an anti-example of AAA pattern. This test is functionally correct, but
+ * with the addition of new feature, it needs refactoring. There are an awful lot of steps in that
+ * test method, but it verifies the class' important behavior in just eleven lines. It violates the
+ * single responsibility principle. If this test method failed after a small code change, it might
+ * take some digging to discover why.
+ */
+public class CashAntiAAATest {
+
+ @Test
+ public void testCash() {
+ //initialize
+ var cash = new Cash(3);
+ //test plus
+ cash.plus(4);
+ assertEquals(7, cash.count());
+ //test minus
+ cash = new Cash(8);
+ assertTrue(cash.minus(5));
+ assertEquals(3, cash.count());
+ assertFalse(cash.minus(6));
+ assertEquals(3, cash.count());
+ //test update
+ cash.plus(5);
+ assertTrue(cash.minus(5));
+ assertEquals(3, cash.count());
+ }
+}
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
index 7bdf84171..e430e9ce4 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
@@ -100,7 +100,7 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
void setValue(T value) {
this.value = value;
this.state = COMPLETED;
- this.callback.ifPresent(ac -> ac.onComplete(value, Optional.empty()));
+ this.callback.ifPresent(ac -> ac.onComplete(value, Optional.empty()));
synchronized (lock) {
lock.notifyAll();
}
diff --git a/bridge/README.md b/bridge/README.md
index ebd6e5b41..82c2f2735 100644
--- a/bridge/README.md
+++ b/bridge/README.md
@@ -194,4 +194,5 @@ Use the Bridge pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/builder/README.md b/builder/README.md
index ccfc378d6..bb7426e35 100644
--- a/builder/README.md
+++ b/builder/README.md
@@ -131,5 +131,7 @@ Use the Builder pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
-* [Effective Java (2nd Edition)](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683)
+* [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)
+* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb)
+* [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)
diff --git a/business-delegate/README.md b/business-delegate/README.md
index 38eb591b8..b00c67819 100644
--- a/business-delegate/README.md
+++ b/business-delegate/README.md
@@ -26,4 +26,4 @@ Use the Business Delegate pattern when
## Credits
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
index dcf4ce6b2..2c13bc149 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
@@ -28,7 +28,7 @@ package com.iluwatar.business.delegate;
*/
public class Client {
- private BusinessDelegate businessDelegate;
+ private final BusinessDelegate businessDelegate;
public Client(BusinessDelegate businessDelegate) {
this.businessDelegate = businessDelegate;
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
index 87fd1562d..c0f02b5e3 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
@@ -28,5 +28,5 @@ package com.iluwatar.business.delegate;
*/
public enum ServiceType {
- EJB, JMS;
+ EJB, JMS
}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java b/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
index 5afc2fb93..c45301c29 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
@@ -30,9 +30,9 @@ import java.util.Stack;
*/
public class VirtualMachine {
- private Stack stack = new Stack<>();
+ private final Stack stack = new Stack<>();
- private Wizard[] wizards = new Wizard[2];
+ private final Wizard[] wizards = new Wizard[2];
/**
* Constructor.
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
index 61a316f5a..4518ca310 100644
--- a/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
@@ -104,7 +104,7 @@ public class VirtualMachineTest {
bytecode[2] = LITERAL.getIntValue();
bytecode[3] = 50; // health amount
bytecode[4] = SET_HEALTH.getIntValue();
- bytecode[5] = LITERAL.getIntValue();;
+ bytecode[5] = LITERAL.getIntValue();
bytecode[6] = wizardNumber;
bytecode[7] = GET_HEALTH.getIntValue();
diff --git a/caching/README.md b/caching/README.md
index 4172cc72a..912f1d218 100644
--- a/caching/README.md
+++ b/caching/README.md
@@ -5,7 +5,8 @@ folder: caching
permalink: /patterns/caching/
categories: Behavioral
tags:
- - Performance
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -25,4 +26,4 @@ Use the Caching pattern(s) when
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
-* [Cache-Aside](https://msdn.microsoft.com/en-us/library/dn589799.aspx)
+* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
diff --git a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java
index 6bc6dbd77..84b8307f3 100644
--- a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java
+++ b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java
@@ -29,7 +29,7 @@ package com.iluwatar.caching;
public enum CachingPolicy {
THROUGH("through"), AROUND("around"), BEHIND("behind"), ASIDE("aside");
- private String policy;
+ private final String policy;
CachingPolicy(String policy) {
this.policy = policy;
diff --git a/callback/README.md b/callback/README.md
index 6942019f3..78766cc15 100644
--- a/callback/README.md
+++ b/callback/README.md
@@ -9,9 +9,64 @@ tags:
---
## Intent
-Callback is a piece of executable code that is passed as an
-argument to other code, which is expected to call back (execute) the argument
-at some convenient time.
+Callback is a piece of executable code that is passed as an argument to other code, which is expected to call back
+(execute) the argument at some convenient time.
+
+## Explanation
+
+Real world example
+
+> We need to be notified after executing task has finished. We pass a callback method for the executor and wait for it to call back on us.
+
+In plain words
+
+> Callback is a method passed to the executor which will be called at defined moment.
+
+Wikipedia says
+
+> In computer programming, a callback, also known as a "call-after" function, is any executable code that is passed as an argument to other code; that other code is expected to call back (execute) the argument at a given time.
+
+**Programmatic Example**
+
+Callback is a simple interface with single method.
+
+```java
+public interface Callback {
+
+ void call();
+}
+```
+
+Next we define a task that will execute the callback after the task execution has finished.
+
+```java
+public abstract class Task {
+
+ final void executeWith(Callback callback) {
+ execute();
+ Optional.ofNullable(callback).ifPresent(Callback::call);
+ }
+
+ public abstract void execute();
+}
+
+public final class SimpleTask extends Task {
+
+ private static final Logger LOGGER = getLogger(SimpleTask.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("Perform some important activity and after call the callback method.");
+ }
+}
+```
+
+Finally here's how we execute a task and receive a callback when it's finished.
+
+```java
+ var task = new SimpleTask();
+ task.executeWith(() -> LOGGER.info("I'm done now."));
+```
## Class diagram

diff --git a/callback/src/main/java/com/iluwatar/callback/Task.java b/callback/src/main/java/com/iluwatar/callback/Task.java
index 5632dbc4f..f3e8e478a 100644
--- a/callback/src/main/java/com/iluwatar/callback/Task.java
+++ b/callback/src/main/java/com/iluwatar/callback/Task.java
@@ -33,7 +33,7 @@ public abstract class Task {
/**
* Execute with callback.
*/
- final void executeWith(final Callback callback) {
+ final void executeWith(Callback callback) {
execute();
Optional.ofNullable(callback).ifPresent(Callback::call);
}
diff --git a/callback/src/main/java/com/iluwatar/callback/module-info.java b/callback/src/main/java/com/iluwatar/callback/module-info.java
deleted file mode 100644
index 21a7a732b..000000000
--- a/callback/src/main/java/com/iluwatar/callback/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.callback {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/chain/README.md b/chain/README.md
index 1dc8af41c..f11f0c59e 100644
--- a/chain/README.md
+++ b/chain/README.md
@@ -65,7 +65,7 @@ Then the request handler hierarchy
```java
public abstract class RequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
- private RequestHandler next;
+ private final RequestHandler next;
public RequestHandler(RequestHandler next) {
this.next = next;
@@ -157,4 +157,5 @@ Use Chain of Responsibility when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
index 7923f03a6..4778ecf91 100644
--- a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
+++ b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
@@ -33,7 +33,7 @@ public abstract class RequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
- private RequestHandler next;
+ private final RequestHandler next;
public RequestHandler(RequestHandler next) {
this.next = next;
diff --git a/chain/src/main/java/com/iluwatar/chain/module-info.java b/chain/src/main/java/com/iluwatar/chain/module-info.java
deleted file mode 100644
index 4f11ab327..000000000
--- a/chain/src/main/java/com/iluwatar/chain/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.chain {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/circuit-breaker/README.md b/circuit-breaker/README.md
index e0ef7d1fb..ce280a570 100644
--- a/circuit-breaker/README.md
+++ b/circuit-breaker/README.md
@@ -5,8 +5,9 @@ folder: circuit-breaker
permalink: /patterns/circuit-breaker/
categories: Behavioral
tags:
- - Performance
- - Decoupling
+ - Performance
+ - Decoupling
+ - Cloud distributed
---
## Intent
@@ -187,4 +188,4 @@ Use the Circuit Breaker pattern when
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a)
-* [Microsoft docs](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
+* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
diff --git a/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Car.java b/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Car.java
index 2828cffd4..cffdc7c82 100644
--- a/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Car.java
+++ b/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Car.java
@@ -87,10 +87,7 @@ public class Car {
} else if (!model.equals(other.model)) {
return false;
}
- if (year != other.year) {
- return false;
- }
- return true;
+ return year == other.year;
}
public String getMake() {
diff --git a/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Person.java b/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Person.java
index 2e564b701..3e25f6993 100644
--- a/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Person.java
+++ b/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Person.java
@@ -29,7 +29,7 @@ import java.util.List;
* A Person class that has the list of cars that the person owns and use.
*/
public class Person {
- private List cars;
+ private final List cars;
/**
* Constructor to create an instance of person.
diff --git a/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/module-info.java b/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/module-info.java
deleted file mode 100644
index f8bd30a68..000000000
--- a/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.collectionpipeline {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/collection-pipeline/src/test/java/com/iluwatar/collectionpipeline/AppTest.java b/collection-pipeline/src/test/java/com/iluwatar/collectionpipeline/AppTest.java
index 6bf373e81..cedc492b9 100644
--- a/collection-pipeline/src/test/java/com/iluwatar/collectionpipeline/AppTest.java
+++ b/collection-pipeline/src/test/java/com/iluwatar/collectionpipeline/AppTest.java
@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
public class AppTest {
private static final Logger LOGGER = LoggerFactory.getLogger(AppTest.class);
- private List cars = CarFactory.createCars();
+ private final List cars = CarFactory.createCars();
@Test
public void testGetModelsAfter2000UsingFor() {
diff --git a/command/README.md b/command/README.md
index bab95b90c..fc0a11d9f 100644
--- a/command/README.md
+++ b/command/README.md
@@ -12,9 +12,214 @@ tags:
Action, Transaction
## Intent
-Encapsulate a request as an object, thereby letting you
-parameterize clients with different requests, queue or log requests, and
-support undoable operations.
+Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
+
+## Explanation
+Real world example
+
+> There is a wizard casting spells on a goblin. The spells are executed on the goblin one by one. The first spell shrinks the goblin and the second makes him invisible. Then the wizard reverses the spells one by one. Each spell here is a command object that can be undone.
+
+In plain words
+
+> Storing requests as command objects allows performing an action or undoing it at a later time.
+
+Wikipedia says
+
+> In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time.
+
+**Programmatic Example**
+
+Here's the sample code with wizard and goblin. Let's start from the wizard class.
+
+```java
+public class Wizard {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
+
+ private final Deque undoStack = new LinkedList<>();
+ private final Deque redoStack = new LinkedList<>();
+
+ public Wizard() {}
+
+ public void castSpell(Command command, Target target) {
+ LOGGER.info("{} casts {} at {}", this, command, target);
+ command.execute(target);
+ undoStack.offerLast(command);
+ }
+
+ public void undoLastSpell() {
+ if (!undoStack.isEmpty()) {
+ var previousSpell = undoStack.pollLast();
+ redoStack.offerLast(previousSpell);
+ LOGGER.info("{} undoes {}", this, previousSpell);
+ previousSpell.undo();
+ }
+ }
+
+ public void redoLastSpell() {
+ if (!redoStack.isEmpty()) {
+ var previousSpell = redoStack.pollLast();
+ undoStack.offerLast(previousSpell);
+ LOGGER.info("{} redoes {}", this, previousSpell);
+ previousSpell.redo();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Wizard";
+ }
+}
+```
+
+Next we present the spell hierarchy.
+
+```java
+public abstract class Command {
+
+ public abstract void execute(Target target);
+
+ public abstract void undo();
+
+ public abstract void redo();
+
+ @Override
+ public abstract String toString();
+}
+
+public class InvisibilitySpell extends Command {
+
+ private Target target;
+
+ @Override
+ public void execute(Target target) {
+ target.setVisibility(Visibility.INVISIBLE);
+ this.target = target;
+ }
+
+ @Override
+ public void undo() {
+ if (target != null) {
+ target.setVisibility(Visibility.VISIBLE);
+ }
+ }
+
+ @Override
+ public void redo() {
+ if (target != null) {
+ target.setVisibility(Visibility.INVISIBLE);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Invisibility spell";
+ }
+}
+
+public class ShrinkSpell extends Command {
+
+ private Size oldSize;
+ private Target target;
+
+ @Override
+ public void execute(Target target) {
+ oldSize = target.getSize();
+ target.setSize(Size.SMALL);
+ this.target = target;
+ }
+
+ @Override
+ public void undo() {
+ if (oldSize != null && target != null) {
+ var temp = target.getSize();
+ target.setSize(oldSize);
+ oldSize = temp;
+ }
+ }
+
+ @Override
+ public void redo() {
+ undo();
+ }
+
+ @Override
+ public String toString() {
+ return "Shrink spell";
+ }
+}
+```
+
+And last we have the goblin who's the target of the spells.
+
+```java
+public abstract class Target {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Target.class);
+
+ private Size size;
+
+ private Visibility visibility;
+
+ public Size getSize() {
+ return size;
+ }
+
+ public void setSize(Size size) {
+ this.size = size;
+ }
+
+ public Visibility getVisibility() {
+ return visibility;
+ }
+
+ public void setVisibility(Visibility visibility) {
+ this.visibility = visibility;
+ }
+
+ @Override
+ public abstract String toString();
+
+ public void printStatus() {
+ LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility());
+ }
+}
+
+public class Goblin extends Target {
+
+ public Goblin() {
+ setSize(Size.NORMAL);
+ setVisibility(Visibility.VISIBLE);
+ }
+
+ @Override
+ public String toString() {
+ return "Goblin";
+ }
+
+}
+```
+
+Finally here's the whole example in action.
+
+```java
+var wizard = new Wizard();
+var goblin = new Goblin();
+goblin.printStatus();
+// Goblin, [size=normal] [visibility=visible]
+wizard.castSpell(new ShrinkSpell(), goblin);
+// Wizard casts Shrink spell at Goblin
+goblin.printStatus();
+// Goblin, [size=small] [visibility=visible]
+wizard.castSpell(new InvisibilitySpell(), goblin);
+// Wizard casts Invisibility spell at Goblin
+goblin.printStatus();
+// Goblin, [size=small] [visibility=invisible]
+wizard.undoLastSpell();
+// Wizard undoes Invisibility spell
+goblin.printStatus();
+// Goblin, [size=small] [visibility=visible]
+```
## Class diagram

@@ -43,4 +248,7 @@ Use the Command pattern when you want to
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
diff --git a/command/src/main/java/com/iluwatar/command/Size.java b/command/src/main/java/com/iluwatar/command/Size.java
index ae327d8b1..c9aeb7017 100644
--- a/command/src/main/java/com/iluwatar/command/Size.java
+++ b/command/src/main/java/com/iluwatar/command/Size.java
@@ -1,43 +1,43 @@
-/*
- * 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.command;
-
-/**
- * Enumeration for target size.
- */
-public enum Size {
-
- SMALL("small"), NORMAL("normal");
-
- private String title;
-
- Size(String title) {
- this.title = title;
- }
-
- @Override
- public String toString() {
- return title;
- }
-}
+/*
+ * 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.command;
+
+/**
+ * Enumeration for target size.
+ */
+public enum Size {
+
+ SMALL("small"), NORMAL("normal");
+
+ private final String title;
+
+ Size(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
diff --git a/command/src/main/java/com/iluwatar/command/Visibility.java b/command/src/main/java/com/iluwatar/command/Visibility.java
index 3c48990a0..8fe0ce7bb 100644
--- a/command/src/main/java/com/iluwatar/command/Visibility.java
+++ b/command/src/main/java/com/iluwatar/command/Visibility.java
@@ -1,43 +1,43 @@
-/*
- * 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.command;
-
-/**
- * Enumeration for target visibility.
- */
-public enum Visibility {
-
- VISIBLE("visible"), INVISIBLE("invisible");
-
- private String title;
-
- Visibility(String title) {
- this.title = title;
- }
-
- @Override
- public String toString() {
- return title;
- }
-}
+/*
+ * 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.command;
+
+/**
+ * Enumeration for target visibility.
+ */
+public enum Visibility {
+
+ VISIBLE("visible"), INVISIBLE("invisible");
+
+ private final String title;
+
+ Visibility(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
diff --git a/command/src/main/java/com/iluwatar/command/Wizard.java b/command/src/main/java/com/iluwatar/command/Wizard.java
index e0b973265..dd469d3c0 100644
--- a/command/src/main/java/com/iluwatar/command/Wizard.java
+++ b/command/src/main/java/com/iluwatar/command/Wizard.java
@@ -35,8 +35,8 @@ public class Wizard {
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
- private Deque undoStack = new LinkedList<>();
- private Deque redoStack = new LinkedList<>();
+ private final Deque undoStack = new LinkedList<>();
+ private final Deque redoStack = new LinkedList<>();
public Wizard() {
// comment to ignore sonar issue: LEVEL critical
diff --git a/command/src/main/java/com/iluwatar/command/module-info.java b/command/src/main/java/com/iluwatar/command/module-info.java
deleted file mode 100644
index 0e0c0b31f..000000000
--- a/command/src/main/java/com/iluwatar/command/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.command {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/commander/src/main/java/com/iluwatar/commander/employeehandle/EmployeeDatabase.java b/commander/src/main/java/com/iluwatar/commander/employeehandle/EmployeeDatabase.java
index 496bb545a..69ebc1fd9 100644
--- a/commander/src/main/java/com/iluwatar/commander/employeehandle/EmployeeDatabase.java
+++ b/commander/src/main/java/com/iluwatar/commander/employeehandle/EmployeeDatabase.java
@@ -33,7 +33,7 @@ import java.util.Hashtable;
*/
public class EmployeeDatabase extends Database {
- private Hashtable data;
+ private final Hashtable data;
public EmployeeDatabase() {
this.data = new Hashtable<>();
diff --git a/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingDatabase.java b/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingDatabase.java
index fbba52cac..22ad733cb 100644
--- a/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingDatabase.java
+++ b/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingDatabase.java
@@ -33,7 +33,7 @@ import java.util.Hashtable;
*/
public class MessagingDatabase extends Database {
- private Hashtable data;
+ private final Hashtable data;
public MessagingDatabase() {
this.data = new Hashtable<>();
diff --git a/commander/src/main/java/com/iluwatar/commander/paymentservice/PaymentDatabase.java b/commander/src/main/java/com/iluwatar/commander/paymentservice/PaymentDatabase.java
index 644979883..bf9e846bb 100644
--- a/commander/src/main/java/com/iluwatar/commander/paymentservice/PaymentDatabase.java
+++ b/commander/src/main/java/com/iluwatar/commander/paymentservice/PaymentDatabase.java
@@ -34,7 +34,7 @@ import java.util.Hashtable;
public class PaymentDatabase extends Database {
- private Hashtable data;
+ private final Hashtable data;
public PaymentDatabase() {
this.data = new Hashtable<>();
diff --git a/commander/src/main/java/com/iluwatar/commander/queue/QueueDatabase.java b/commander/src/main/java/com/iluwatar/commander/queue/QueueDatabase.java
index 91a7966f7..003a7da46 100644
--- a/commander/src/main/java/com/iluwatar/commander/queue/QueueDatabase.java
+++ b/commander/src/main/java/com/iluwatar/commander/queue/QueueDatabase.java
@@ -35,7 +35,7 @@ import java.util.List;
public class QueueDatabase extends Database {
- private Queue data;
+ private final Queue data;
public List exceptionsList;
public QueueDatabase(Exception... exc) {
diff --git a/commander/src/main/java/com/iluwatar/commander/shippingservice/ShippingDatabase.java b/commander/src/main/java/com/iluwatar/commander/shippingservice/ShippingDatabase.java
index 305122db2..abaf27c9d 100644
--- a/commander/src/main/java/com/iluwatar/commander/shippingservice/ShippingDatabase.java
+++ b/commander/src/main/java/com/iluwatar/commander/shippingservice/ShippingDatabase.java
@@ -34,7 +34,7 @@ import java.util.Hashtable;
public class ShippingDatabase extends Database {
- private Hashtable data;
+ private final Hashtable data;
public ShippingDatabase() {
this.data = new Hashtable<>();
diff --git a/composite/README.md b/composite/README.md
index 1db1ce14f..dad6fb5a5 100644
--- a/composite/README.md
+++ b/composite/README.md
@@ -34,7 +34,7 @@ Taking our sentence example from above. Here we have the base class and differen
```java
public abstract class LetterComposite {
- private List children = new ArrayList<>();
+ private final List children = new ArrayList<>();
public void add(LetterComposite letter) {
children.add(letter);
@@ -59,7 +59,7 @@ public abstract class LetterComposite {
public class Letter extends LetterComposite {
- private char character;
+ private final char character;
public Letter(char c) {
this.character = c;
@@ -168,4 +168,6 @@ Use the Composite pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/composite/src/main/java/com/iluwatar/composite/Letter.java b/composite/src/main/java/com/iluwatar/composite/Letter.java
index ab2d496ea..00b1a9639 100644
--- a/composite/src/main/java/com/iluwatar/composite/Letter.java
+++ b/composite/src/main/java/com/iluwatar/composite/Letter.java
@@ -28,7 +28,7 @@ package com.iluwatar.composite;
*/
public class Letter extends LetterComposite {
- private char character;
+ private final char character;
public Letter(char c) {
this.character = c;
diff --git a/composite/src/main/java/com/iluwatar/composite/LetterComposite.java b/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
index 25808c468..0daf88222 100644
--- a/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
+++ b/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
@@ -1,58 +1,58 @@
-/*
- * 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.composite;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Composite interface.
- */
-public abstract class LetterComposite {
-
- private List children = new ArrayList<>();
-
- public void add(LetterComposite letter) {
- children.add(letter);
- }
-
- public int count() {
- return children.size();
- }
-
- protected void printThisBefore() {
- }
-
- protected void printThisAfter() {
- }
-
- /**
- * Print.
- */
- public void print() {
- printThisBefore();
- children.forEach(LetterComposite::print);
- printThisAfter();
- }
-}
+/*
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Composite interface.
+ */
+public abstract class LetterComposite {
+
+ private final List children = new ArrayList<>();
+
+ public void add(LetterComposite letter) {
+ children.add(letter);
+ }
+
+ public int count() {
+ return children.size();
+ }
+
+ protected void printThisBefore() {
+ }
+
+ protected void printThisAfter() {
+ }
+
+ /**
+ * Print.
+ */
+ public void print() {
+ printThisBefore();
+ children.forEach(LetterComposite::print);
+ printThisAfter();
+ }
+}
diff --git a/composite/src/main/java/com/iluwatar/composite/module-info.java b/composite/src/main/java/com/iluwatar/composite/module-info.java
deleted file mode 100644
index d75a7b8f8..000000000
--- a/composite/src/main/java/com/iluwatar/composite/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.composite {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/converter/src/main/java/com/iluwatar/converter/User.java b/converter/src/main/java/com/iluwatar/converter/User.java
index 637d77a25..2c1ba9ff0 100644
--- a/converter/src/main/java/com/iluwatar/converter/User.java
+++ b/converter/src/main/java/com/iluwatar/converter/User.java
@@ -29,10 +29,10 @@ import java.util.Objects;
* User class.
*/
public class User {
- private String firstName;
- private String lastName;
- private boolean isActive;
- private String userId;
+ private final String firstName;
+ private final String lastName;
+ private final boolean isActive;
+ private final String userId;
/**
* Constructor.
diff --git a/converter/src/main/java/com/iluwatar/converter/UserDto.java b/converter/src/main/java/com/iluwatar/converter/UserDto.java
index e75aaab8c..67a886087 100644
--- a/converter/src/main/java/com/iluwatar/converter/UserDto.java
+++ b/converter/src/main/java/com/iluwatar/converter/UserDto.java
@@ -30,10 +30,10 @@ import java.util.Objects;
*/
public class UserDto {
- private String firstName;
- private String lastName;
- private boolean isActive;
- private String email;
+ private final String firstName;
+ private final String lastName;
+ private final boolean isActive;
+ private final String email;
/**
* Constructor.
diff --git a/converter/src/main/java/com/iluwatar/converter/module-info.java b/converter/src/main/java/com/iluwatar/converter/module-info.java
deleted file mode 100644
index d83a43c6b..000000000
--- a/converter/src/main/java/com/iluwatar/converter/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.converter {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java
index d9e4e418b..46aca82a7 100644
--- a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java
+++ b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class ConverterTest {
- private UserConverter userConverter = new UserConverter();
+ private final UserConverter userConverter = new UserConverter();
/**
* Tests whether a converter created of opposite functions holds equality as a bijection.
diff --git a/cqrs/README.md b/cqrs/README.md
index 431ae6279..017e0a003 100644
--- a/cqrs/README.md
+++ b/cqrs/README.md
@@ -5,8 +5,8 @@ folder: cqrs
permalink: /patterns/cqrs/
categories: Architectural
tags:
- - Performance
- - Cloud distributed
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -18,12 +18,13 @@ CQRS Command Query Responsibility Segregation - Separate the query side from the
## Applicability
Use the CQRS pattern when
-* you want to scale the queries and commands independently.
-* you want to use different data models for queries and commands. Useful when dealing with complex domains.
-* you want to use architectures like event sourcing or task based UI.
+* You want to scale the queries and commands independently.
+* You want to use different data models for queries and commands. Useful when dealing with complex domains.
+* You want to use architectures like event sourcing or task based UI.
## Credits
* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/)
* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html)
* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw)
+* [Command and Query Responsibility Segregation (CQRS) pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)
diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java
index ba08811e7..e402adad8 100644
--- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java
+++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java
@@ -34,7 +34,7 @@ import org.hibernate.SessionFactory;
*/
public class CommandServiceImpl implements ICommandService {
- private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
+ private final SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
private Author getAuthorByUsername(String username) {
Author author;
diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java
index 9b008402e..d30c0f386 100644
--- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java
+++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java
@@ -38,7 +38,7 @@ import org.hibernate.transform.Transformers;
*/
public class QueryServiceImpl implements IQueryService {
- private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
+ private final SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
@Override
public Author getAuthorByUsername(String username) {
diff --git a/dao/README.md b/dao/README.md
index 9065cb3ee..11e5f9ca3 100644
--- a/dao/README.md
+++ b/dao/README.md
@@ -9,8 +9,298 @@ tags:
---
## Intent
-Object provides an abstract interface to some type of database or
-other persistence mechanism.
+Object provides an abstract interface to some type of database or other persistence mechanism.
+
+## Explanation
+
+Real world example
+
+> There's a set of customers that need to be persisted to database. Additionally we need the whole set of CRUD (create/read/update/delete) operations so we can operate on customers easily.
+
+In plain words
+
+> DAO is an interface we provide over the base persistence mechanism.
+
+Wikipedia says
+
+> In computer software, a data access object (DAO) is a pattern that provides an abstract interface to some type of database or other persistence mechanism.
+
+**Programmatic Example**
+
+Walking through our customers example, here's the basic Customer entity.
+
+```java
+public class Customer {
+
+ private int id;
+ private String firstName;
+ private String lastName;
+
+ public Customer(int id, String firstName, String lastName) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(final String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(final String lastName) {
+ this.lastName = lastName;
+ }
+
+ @Override
+ public String toString() {
+ return "Customer{" + "id=" + getId() + ", firstName='" + getFirstName() + '\'' + ", lastName='"
+ + getLastName() + '\'' + '}';
+ }
+
+ @Override
+ public boolean equals(final Object that) {
+ var isEqual = false;
+ if (this == that) {
+ isEqual = true;
+ } else if (that != null && getClass() == that.getClass()) {
+ final var customer = (Customer) that;
+ if (getId() == customer.getId()) {
+ isEqual = true;
+ }
+ }
+ return isEqual;
+ }
+
+ @Override
+ public int hashCode() {
+ return getId();
+ }
+}
+```
+
+Here's the DAO interface and two different implementations for it. InMemoryCustomerDao keeps a simple map of customers
+in memory while DBCustomerDao is the real RDBMS implementation.
+
+```java
+public interface CustomerDao {
+
+ Stream getAll() throws Exception;
+
+ Optional getById(int id) throws Exception;
+
+ boolean add(Customer customer) throws Exception;
+
+ boolean update(Customer customer) throws Exception;
+
+ boolean delete(Customer customer) throws Exception;
+}
+
+public class InMemoryCustomerDao implements CustomerDao {
+
+ private final Map idToCustomer = new HashMap<>();
+
+ @Override
+ public Stream getAll() {
+ return idToCustomer.values().stream();
+ }
+
+ @Override
+ public Optional getById(final int id) {
+ return Optional.ofNullable(idToCustomer.get(id));
+ }
+
+ @Override
+ public boolean add(final Customer customer) {
+ if (getById(customer.getId()).isPresent()) {
+ return false;
+ }
+
+ idToCustomer.put(customer.getId(), customer);
+ return true;
+ }
+
+ @Override
+ public boolean update(final Customer customer) {
+ return idToCustomer.replace(customer.getId(), customer) != null;
+ }
+
+ @Override
+ public boolean delete(final Customer customer) {
+ return idToCustomer.remove(customer.getId()) != null;
+ }
+}
+
+public class DbCustomerDao implements CustomerDao {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DbCustomerDao.class);
+
+ private final DataSource dataSource;
+
+ public DbCustomerDao(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ @Override
+ public Stream getAll() throws Exception {
+ try {
+ var connection = getConnection();
+ var statement = connection.prepareStatement("SELECT * FROM CUSTOMERS");
+ var resultSet = statement.executeQuery();
+ return StreamSupport.stream(new Spliterators.AbstractSpliterator(Long.MAX_VALUE,
+ Spliterator.ORDERED) {
+
+ @Override
+ public boolean tryAdvance(Consumer super Customer> action) {
+ try {
+ if (!resultSet.next()) {
+ return false;
+ }
+ action.accept(createCustomer(resultSet));
+ return true;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }, false).onClose(() -> mutedClose(connection, statement, resultSet));
+ } catch (SQLException e) {
+ throw new CustomException(e.getMessage(), e);
+ }
+ }
+
+ private Connection getConnection() throws SQLException {
+ return dataSource.getConnection();
+ }
+
+ private void mutedClose(Connection connection, PreparedStatement statement, ResultSet resultSet) {
+ try {
+ resultSet.close();
+ statement.close();
+ connection.close();
+ } catch (SQLException e) {
+ LOGGER.info("Exception thrown " + e.getMessage());
+ }
+ }
+
+ private Customer createCustomer(ResultSet resultSet) throws SQLException {
+ return new Customer(resultSet.getInt("ID"),
+ resultSet.getString("FNAME"),
+ resultSet.getString("LNAME"));
+ }
+
+ @Override
+ public Optional getById(int id) throws Exception {
+
+ ResultSet resultSet = null;
+
+ try (var connection = getConnection();
+ var statement = connection.prepareStatement("SELECT * FROM CUSTOMERS WHERE ID = ?")) {
+
+ statement.setInt(1, id);
+ resultSet = statement.executeQuery();
+ if (resultSet.next()) {
+ return Optional.of(createCustomer(resultSet));
+ } else {
+ return Optional.empty();
+ }
+ } catch (SQLException ex) {
+ throw new CustomException(ex.getMessage(), ex);
+ } finally {
+ if (resultSet != null) {
+ resultSet.close();
+ }
+ }
+ }
+
+ @Override
+ public boolean add(Customer customer) throws Exception {
+ if (getById(customer.getId()).isPresent()) {
+ return false;
+ }
+
+ try (var connection = getConnection();
+ var statement = connection.prepareStatement("INSERT INTO CUSTOMERS VALUES (?,?,?)")) {
+ statement.setInt(1, customer.getId());
+ statement.setString(2, customer.getFirstName());
+ statement.setString(3, customer.getLastName());
+ statement.execute();
+ return true;
+ } catch (SQLException ex) {
+ throw new CustomException(ex.getMessage(), ex);
+ }
+ }
+
+ @Override
+ public boolean update(Customer customer) throws Exception {
+ try (var connection = getConnection();
+ var statement =
+ connection
+ .prepareStatement("UPDATE CUSTOMERS SET FNAME = ?, LNAME = ? WHERE ID = ?")) {
+ statement.setString(1, customer.getFirstName());
+ statement.setString(2, customer.getLastName());
+ statement.setInt(3, customer.getId());
+ return statement.executeUpdate() > 0;
+ } catch (SQLException ex) {
+ throw new CustomException(ex.getMessage(), ex);
+ }
+ }
+
+ @Override
+ public boolean delete(Customer customer) throws Exception {
+ try (var connection = getConnection();
+ var statement = connection.prepareStatement("DELETE FROM CUSTOMERS WHERE ID = ?")) {
+ statement.setInt(1, customer.getId());
+ return statement.executeUpdate() > 0;
+ } catch (SQLException ex) {
+ throw new CustomException(ex.getMessage(), ex);
+ }
+ }
+}
+```
+
+Finally here's how we use our DAO to manage customers.
+
+```java
+ final var dataSource = createDataSource();
+ createSchema(dataSource);
+ final var customerDao = new DbCustomerDao(dataSource);
+
+ addCustomers(customerDao);
+ log.info(ALL_CUSTOMERS);
+ try (var customerStream = customerDao.getAll()) {
+ customerStream.forEach((customer) -> log.info(customer.toString()));
+ }
+ log.info("customerDao.getCustomerById(2): " + customerDao.getById(2));
+ final var customer = new Customer(4, "Dan", "Danson");
+ customerDao.add(customer);
+ log.info(ALL_CUSTOMERS + customerDao.getAll());
+ customer.setFirstName("Daniel");
+ customer.setLastName("Danielson");
+ customerDao.update(customer);
+ log.info(ALL_CUSTOMERS);
+ try (var customerStream = customerDao.getAll()) {
+ customerStream.forEach((cust) -> log.info(cust.toString()));
+ }
+ customerDao.delete(customer);
+ log.info(ALL_CUSTOMERS + customerDao.getAll());
+
+ deleteSchema(dataSource);
+```
+
## Class diagram

@@ -23,4 +313,4 @@ Use the Data Access Object in any of the following situations
## Credits
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
diff --git a/dao/src/main/java/com/iluwatar/dao/App.java b/dao/src/main/java/com/iluwatar/dao/App.java
index de9c7b7c1..6d578bc79 100644
--- a/dao/src/main/java/com/iluwatar/dao/App.java
+++ b/dao/src/main/java/com/iluwatar/dao/App.java
@@ -44,7 +44,7 @@ import org.slf4j.LoggerFactory;
*/
public class App {
private static final String DB_URL = "jdbc:h2:~/dao";
- private static Logger log = LoggerFactory.getLogger(App.class);
+ private static final Logger log = LoggerFactory.getLogger(App.class);
private static final String ALL_CUSTOMERS = "customerDao.getAllCustomers(): ";
/**
diff --git a/dao/src/main/java/com/iluwatar/dao/Customer.java b/dao/src/main/java/com/iluwatar/dao/Customer.java
index 43649989b..2630c9252 100644
--- a/dao/src/main/java/com/iluwatar/dao/Customer.java
+++ b/dao/src/main/java/com/iluwatar/dao/Customer.java
@@ -35,7 +35,7 @@ public class Customer {
/**
* Creates an instance of customer.
*/
- public Customer(final int id, final String firstName, final String lastName) {
+ public Customer(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
diff --git a/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java b/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java
index 6dbfa367a..0a3bd40e3 100644
--- a/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java
+++ b/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java
@@ -36,7 +36,7 @@ import java.util.stream.Stream;
*/
public class InMemoryCustomerDao implements CustomerDao {
- private Map idToCustomer = new HashMap<>();
+ private final Map idToCustomer = new HashMap<>();
/**
* An eagerly evaluated stream of customers stored in memory.
diff --git a/dao/src/main/java/com/iluwatar/dao/module-info.java b/dao/src/main/java/com/iluwatar/dao/module-info.java
deleted file mode 100644
index 08e4f662e..000000000
--- a/dao/src/main/java/com/iluwatar/dao/module-info.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.dao {
- requires org.slf4j;
- requires java.sql;
- requires h2;
- requires java.naming;
-}
\ No newline at end of file
diff --git a/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java b/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java
index b7a0b9769..8155cda79 100644
--- a/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java
+++ b/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java
@@ -50,7 +50,7 @@ public class DbCustomerDaoTest {
private static final String DB_URL = "jdbc:h2:~/dao";
private DbCustomerDao dao;
- private Customer existingCustomer = new Customer(1, "Freddy", "Krueger");
+ private final Customer existingCustomer = new Customer(1, "Freddy", "Krueger");
/**
* Creates customers schema.
diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java
index 5a8218225..d77d56b9f 100644
--- a/data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java
+++ b/data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java
@@ -41,7 +41,7 @@ public class MessageCollectorMember implements Member {
private final String name;
- private List messages = new ArrayList<>();
+ private final List messages = new ArrayList<>();
public MessageCollectorMember(String name) {
this.name = name;
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/App.java b/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
index 9bfc32952..09c027401 100644
--- a/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
@@ -1,83 +1,83 @@
-/*
- * 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.datamapper;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The Data Mapper (DM) is a layer of software that separates the in-memory objects from the
- * database. Its responsibility is to transfer data between the two and also to isolate them from
- * each other. With Data Mapper the in-memory objects needn't know even that there's a database
- * present; they need no SQL interface code, and certainly no knowledge of the database schema. (The
- * database schema is always ignorant of the objects that use it.) Since it's a form of Mapper ,
- * Data Mapper itself is even unknown to the domain layer.
- *
- * The below example demonstrates basic CRUD operations: Create, Read, Update, and Delete.
- */
-public final class App {
-
- private static Logger log = LoggerFactory.getLogger(App.class);
- private static final String STUDENT_STRING = "App.main(), student : ";
-
-
- /**
- * Program entry point.
- *
- * @param args command line args.
- */
- public static void main(final String... args) {
-
- /* Create new data mapper for type 'first' */
- final var mapper = new StudentDataMapperImpl();
-
- /* Create new student */
- var student = new Student(1, "Adam", 'A');
-
- /* Add student in respectibe store */
- mapper.insert(student);
-
- log.debug(STUDENT_STRING + student + ", is inserted");
-
- /* Find this student */
- final var studentToBeFound = mapper.find(student.getStudentId());
-
- log.debug(STUDENT_STRING + studentToBeFound + ", is searched");
-
- /* Update existing student object */
- student = new Student(student.getStudentId(), "AdamUpdated", 'A');
-
- /* Update student in respectibe db */
- mapper.update(student);
-
- log.debug(STUDENT_STRING + student + ", is updated");
- log.debug(STUDENT_STRING + student + ", is going to be deleted");
-
- /* Delete student in db */
- mapper.delete(student);
- }
-
- private App() {
- }
-}
+/*
+ * 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.datamapper;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Data Mapper (DM) is a layer of software that separates the in-memory objects from the
+ * database. Its responsibility is to transfer data between the two and also to isolate them from
+ * each other. With Data Mapper the in-memory objects needn't know even that there's a database
+ * present; they need no SQL interface code, and certainly no knowledge of the database schema. (The
+ * database schema is always ignorant of the objects that use it.) Since it's a form of Mapper ,
+ * Data Mapper itself is even unknown to the domain layer.
+ *
+ *
The below example demonstrates basic CRUD operations: Create, Read, Update, and Delete.
+ */
+public final class App {
+
+ private static final Logger log = LoggerFactory.getLogger(App.class);
+ private static final String STUDENT_STRING = "App.main(), student : ";
+
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args.
+ */
+ public static void main(final String... args) {
+
+ /* Create new data mapper for type 'first' */
+ final var mapper = new StudentDataMapperImpl();
+
+ /* Create new student */
+ var student = new Student(1, "Adam", 'A');
+
+ /* Add student in respectibe store */
+ mapper.insert(student);
+
+ log.debug(STUDENT_STRING + student + ", is inserted");
+
+ /* Find this student */
+ final var studentToBeFound = mapper.find(student.getStudentId());
+
+ log.debug(STUDENT_STRING + studentToBeFound + ", is searched");
+
+ /* Update existing student object */
+ student = new Student(student.getStudentId(), "AdamUpdated", 'A');
+
+ /* Update student in respectibe db */
+ mapper.update(student);
+
+ log.debug(STUDENT_STRING + student + ", is updated");
+ log.debug(STUDENT_STRING + student + ", is going to be deleted");
+
+ /* Delete student in db */
+ mapper.delete(student);
+ }
+
+ private App() {
+ }
+}
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
index 85ad4aa8d..7abe04e3f 100644
--- a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
@@ -33,7 +33,7 @@ import java.util.Optional;
public final class StudentDataMapperImpl implements StudentDataMapper {
/* Note: Normally this would be in the form of an actual database */
- private List students = new ArrayList<>();
+ private final List students = new ArrayList<>();
@Override
public Optional find(int studentId) {
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/module-info.java b/data-mapper/src/main/java/com/iluwatar/datamapper/module-info.java
deleted file mode 100644
index 7abd78826..000000000
--- a/data-mapper/src/main/java/com/iluwatar/datamapper/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.datamapper {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/data-transfer-object/README.md b/data-transfer-object/README.md
index f269fc66b..fd0ff1137 100644
--- a/data-transfer-object/README.md
+++ b/data-transfer-object/README.md
@@ -9,8 +9,89 @@ tags:
---
## Intent
-Pass data with multiple attributes in one shot from client to server,
-to avoid multiple calls to remote server.
+Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to remote server.
+
+## Explanation
+
+Real world example
+
+> We need to fetch information about customers from remote database. Instead of querying the attributes one at a time, we use DTOs to transfer all the relevant attributes in a single shot.
+
+In plain words
+
+> Using DTO relevant information can be fetched with a single backend query.
+
+Wikipedia says
+
+> In the field of programming a data transfer object (DTO) is an object that carries data between processes. The
+motivation for its use is that communication between processes is usually done resorting to remote interfaces
+(e.g., web services), where each call is an expensive operation. Because the majority of the cost of each call is
+related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an
+object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by
+one call only.
+
+**Programmatic Example**
+
+Let's first introduce our simple customer DTO class.
+
+```java
+public class CustomerDto {
+ private final String id;
+ private final String firstName;
+ private final String lastName;
+
+ public CustomerDto(String id, String firstName, String lastName) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+}
+```
+
+Customer resource class acts as the server for customer information.
+
+```java
+public class CustomerResource {
+ private final List customers;
+
+ public CustomerResource(List customers) {
+ this.customers = customers;
+ }
+
+ public List getAllCustomers() {
+ return customers;
+ }
+
+ public void save(CustomerDto customer) {
+ customers.add(customer);
+ }
+
+ public void delete(String customerId) {
+ customers.removeIf(customer -> customer.getId().equals(customerId));
+ }
+}
+```
+
+Now fetching customer information is easy since we have the DTOs.
+
+```java
+ var allCustomers = customerResource.getAllCustomers();
+ allCustomers.forEach(customer -> LOGGER.info(customer.getFirstName()));
+ // Kelly
+ // Alfonso
+```
## Class diagram

@@ -26,3 +107,5 @@ Use the Data Transfer Object pattern when
* [Design Pattern - Transfer Object Pattern](https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm)
* [Data Transfer Object](https://msdn.microsoft.com/en-us/library/ff649585.aspx)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
+* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=014237a67c9d46f384b35e10151956bd)
diff --git a/data-transfer-object/etc/data-transfer-object.ucls b/data-transfer-object/etc/data-transfer-object.ucls
index 15f777aad..66236f32d 100644
--- a/data-transfer-object/etc/data-transfer-object.ucls
+++ b/data-transfer-object/etc/data-transfer-object.ucls
@@ -1,7 +1,7 @@
-
diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml
index 5889daba8..459b1ab1e 100644
--- a/data-transfer-object/pom.xml
+++ b/data-transfer-object/pom.xml
@@ -48,7 +48,7 @@
- com.iluwatar.datatransfer.CustomerClientApp
+ com.iluwatar.datatransfer.App
diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/App.java
similarity index 93%
rename from data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java
rename to data-transfer-object/src/main/java/com/iluwatar/datatransfer/App.java
index ebc44dc57..b8630d4ea 100644
--- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java
+++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/App.java
@@ -32,15 +32,15 @@ import org.slf4j.LoggerFactory;
* The Data Transfer Object pattern is a design pattern in which an data transfer object is used to
* serve related information together to avoid multiple call for each piece of information.
*
- * In this example, ({@link CustomerClientApp}) as as customer details consumer i.e. client to
+ *
In this example, ({@link App}) as as customer details consumer i.e. client to
* request for customer details to server.
*
*
CustomerResource ({@link CustomerResource}) act as server to serve customer information. And
* The CustomerDto ({@link CustomerDto} is data transfer object to share customer information.
*/
-public class CustomerClientApp {
+public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(CustomerClientApp.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Method as act client and request to server for details.
diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java
index 7e4b8340d..d0a153f6f 100644
--- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java
+++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java
@@ -30,7 +30,7 @@ import java.util.List;
* has all customer details.
*/
public class CustomerResource {
- private List customers;
+ private final List customers;
/**
* Initialise resource with existing customers.
diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/module-info.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/module-info.java
deleted file mode 100644
index 25685d4d0..000000000
--- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.datatransfer {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/module-info.java b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java
similarity index 85%
rename from abstract-document/src/main/java/com/iluwatar/abstractdocument/module-info.java
rename to data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java
index 9121f0049..3a58d0c54 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/module-info.java
+++ b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java
@@ -21,6 +21,13 @@
* THE SOFTWARE.
*/
-module com.iluwatar.abstractdocument {
- requires org.slf4j;
-}
\ No newline at end of file
+package com.iluwatar.datatransfer;
+
+import org.junit.jupiter.api.Test;
+
+public class AppTest {
+ @Test
+ public void test() throws Exception {
+ App.main(new String[]{});
+ }
+}
diff --git a/decorator/README.md b/decorator/README.md
index 99f225a4c..26dbd1803 100644
--- a/decorator/README.md
+++ b/decorator/README.md
@@ -70,7 +70,7 @@ public class ClubbedTroll implements Troll {
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
- private Troll decorated;
+ private final Troll decorated;
public ClubbedTroll(Troll decorated) {
this.decorated = decorated;
@@ -131,6 +131,9 @@ Use Decorator
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
-* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1)
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [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)
+* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+* [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)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
diff --git a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java
index 70fd15489..74a1434e1 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java
@@ -33,7 +33,7 @@ public class ClubbedTroll implements Troll {
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
- private Troll decorated;
+ private final Troll decorated;
public ClubbedTroll(Troll decorated) {
this.decorated = decorated;
diff --git a/decorator/src/main/java/com/iluwatar/decorator/module-info.java b/decorator/src/main/java/com/iluwatar/decorator/module-info.java
deleted file mode 100644
index 50d17f022..000000000
--- a/decorator/src/main/java/com/iluwatar/decorator/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.decorator {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java
index c9f62407c..a398135e6 100644
--- a/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java
+++ b/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java
@@ -68,7 +68,7 @@ public class SimpleTrollTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/delegation/src/main/java/com/iluwatar/delegation/module-info.java b/delegation/src/main/java/com/iluwatar/delegation/module-info.java
deleted file mode 100644
index 156477cde..000000000
--- a/delegation/src/main/java/com/iluwatar/delegation/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.delegation {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
index 2da1e0571..8aefc4b56 100644
--- a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
+++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
@@ -86,7 +86,7 @@ public class DelegateTest {
*/
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/dependency-injection/README.md b/dependency-injection/README.md
index 90edd4061..b47c1d2f9 100644
--- a/dependency-injection/README.md
+++ b/dependency-injection/README.md
@@ -9,12 +9,78 @@ tags:
---
## Intent
-Dependency Injection is a software design pattern in which one or
-more dependencies (or services) are injected, or passed by reference, into a
-dependent object (or client) and are made part of the client's state. The
-pattern separates the creation of a client's dependencies from its own
-behavior, which allows program designs to be loosely coupled and to follow the
-inversion of control and single responsibility principles.
+Dependency Injection is a software design pattern in which one or more dependencies (or services) are injected, or
+passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates
+the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and
+to follow the inversion of control and single responsibility principles.
+
+## Explanation
+Real world example
+
+> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably.
+
+In plain words
+
+> Dependency Injection separates creation of client's dependencies from its own behavior.
+
+Wikipedia says
+
+> In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies.
+
+**Programmatic Example**
+
+Let's first introduce the tobacco brands.
+
+```java
+public abstract class Tobacco {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class);
+
+ public void smoke(Wizard wizard) {
+ LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
+ this.getClass().getSimpleName());
+ }
+}
+
+public class SecondBreakfastTobacco extends Tobacco {
+}
+
+public class RivendellTobacco extends Tobacco {
+}
+
+public class OldTobyTobacco extends Tobacco {
+}
+```
+
+Next here's the wizard class hierarchy.
+
+```java
+public interface Wizard {
+
+ void smoke();
+}
+
+public class AdvancedWizard implements Wizard {
+
+ private final Tobacco tobacco;
+
+ public AdvancedWizard(Tobacco tobacco) {
+ this.tobacco = tobacco;
+ }
+
+ @Override
+ public void smoke() {
+ tobacco.smoke(this);
+ }
+}
+```
+
+And lastly we can show how easy it is to give the old wizard any brand of tobacco.
+
+```java
+ var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
+ advancedWizard.smoke();
+```
## Class diagram

@@ -22,5 +88,12 @@ inversion of control and single responsibility principles.
## Applicability
Use the Dependency Injection pattern when
-* when you need to remove knowledge of concrete implementation from object
-* to enable unit testing of classes in isolation using mock objects or stubs
+* When you need to remove knowledge of concrete implementation from object
+* To enable unit testing of classes in isolation using mock objects or stubs
+
+## Credits
+
+* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd)
+* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871)
+* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1)
+* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe)
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
index e0c952186..f0ff2da94 100644
--- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
@@ -29,7 +29,7 @@ package com.iluwatar.dependency.injection;
*/
public class AdvancedWizard implements Wizard {
- private Tobacco tobacco;
+ private final Tobacco tobacco;
public AdvancedWizard(Tobacco tobacco) {
this.tobacco = tobacco;
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
index 319a635eb..d769ffd46 100644
--- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
@@ -31,7 +31,7 @@ import javax.inject.Inject;
*/
public class GuiceWizard implements Wizard {
- private Tobacco tobacco;
+ private final Tobacco tobacco;
@Inject
public GuiceWizard(Tobacco tobacco) {
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
index 40bca0ffb..0136ff69f 100644
--- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
@@ -29,7 +29,7 @@ package com.iluwatar.dependency.injection;
*/
public class SimpleWizard implements Wizard {
- private OldTobyTobacco tobacco = new OldTobyTobacco();
+ private final OldTobyTobacco tobacco = new OldTobyTobacco();
public void smoke() {
tobacco.smoke(this);
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java
index 9d0ad1b3b..d91099af9 100644
--- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java
@@ -37,7 +37,7 @@ import java.util.List;
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/dirty-flag/README.md b/dirty-flag/README.md
index 31cfbae1f..28041782c 100644
--- a/dirty-flag/README.md
+++ b/dirty-flag/README.md
@@ -9,6 +9,9 @@ tags:
- Performance
---
+## Also known as
+* IsDirty pattern
+
## Intent
To avoid expensive re-acquisition of resources. The resources retain their identity, are kept in some
fast-access storage, and are re-used to avoid having to acquire them again.
@@ -24,3 +27,4 @@ Use the Dirty Flag pattern when
## Credits
* [Design Patterns: Dirty Flag](https://www.takeupcode.com/podcast/89-design-patterns-dirty-flag/)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
diff --git a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java b/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java
index db60924c1..1d4fbfa75 100644
--- a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java
+++ b/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java
@@ -34,7 +34,7 @@ import java.util.List;
public class World {
private List countries;
- private DataFetcher df;
+ private final DataFetcher df;
public World() {
this.countries = new ArrayList();
diff --git a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/module-info.java b/dirty-flag/src/main/java/com/iluwatar/dirtyflag/module-info.java
deleted file mode 100644
index bf47d2cd7..000000000
--- a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.dirtyflag {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java b/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java
index 5f683cf1e..4b974a2e8 100644
--- a/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java
+++ b/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java
@@ -33,7 +33,7 @@ public class FrameBuffer implements Buffer {
public static final int WIDTH = 10;
public static final int HEIGHT = 8;
- private Pixel[] pixels = new Pixel[WIDTH * HEIGHT];
+ private final Pixel[] pixels = new Pixel[WIDTH * HEIGHT];
public FrameBuffer() {
clearAll();
diff --git a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java
index 501797743..54f130b1d 100644
--- a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java
+++ b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java
@@ -31,7 +31,7 @@ public enum Pixel {
WHITE(0),
BLACK(1);
- private int color;
+ private final int color;
Pixel(int color) {
this.color = color;
diff --git a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java
index 2c1503918..8ee72ded4 100644
--- a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java
+++ b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java
@@ -35,7 +35,7 @@ public class Scene {
private static final Logger LOGGER = LoggerFactory.getLogger(Scene.class);
- private Buffer[] frameBuffers;
+ private final Buffer[] frameBuffers;
private int current;
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/module-info.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/module-info.java
deleted file mode 100644
index 4f4216ea7..000000000
--- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.doublecheckedlocking {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
index e8ea7c6f8..fe0cbf5e9 100644
--- a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
+++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
@@ -109,7 +109,7 @@ public class InventoryTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
index bd832287c..ea18ca3dc 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
@@ -28,10 +28,10 @@ package com.iluwatar.doubledispatch;
*/
public class Rectangle {
- private int left;
- private int top;
- private int right;
- private int bottom;
+ private final int left;
+ private final int top;
+ private final int right;
+ private final int bottom;
/**
* Constructor.
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/module-info.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/module-info.java
deleted file mode 100644
index b1bc2e824..000000000
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.doubledispatch {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/eip-aggregator/README.md b/eip-aggregator/README.md
index 6138af0a8..8f19c21ad 100644
--- a/eip-aggregator/README.md
+++ b/eip-aggregator/README.md
@@ -29,3 +29,4 @@ Use the Aggregator pattern when
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html)
* [Apache Camel - Documentation](http://camel.apache.org/aggregator2.html)
+* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
diff --git a/eip-message-channel/README.md b/eip-message-channel/README.md
index 8e2f5dc8f..b1c456aeb 100644
--- a/eip-message-channel/README.md
+++ b/eip-message-channel/README.md
@@ -23,3 +23,4 @@ Use the Message Channel pattern when
## Real world examples
* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html)
+* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
diff --git a/eip-message-channel/src/main/java/com/iluwatar/eip/message/channel/module-info.java b/eip-message-channel/src/main/java/com/iluwatar/eip/message/channel/module-info.java
deleted file mode 100644
index b904ee1c8..000000000
--- a/eip-message-channel/src/main/java/com/iluwatar/eip/message/channel/module-info.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.eipmessagechannel {
- requires org.slf4j;
- requires camel.core;
-}
\ No newline at end of file
diff --git a/eip-publish-subscribe/README.md b/eip-publish-subscribe/README.md
index 3952913af..f4df3135f 100644
--- a/eip-publish-subscribe/README.md
+++ b/eip-publish-subscribe/README.md
@@ -21,4 +21,5 @@ Use the Publish Subscribe Channel pattern when
## Credits
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
diff --git a/eip-publish-subscribe/src/main/java/com/iluwatar/eip/publish/subscribe/module-info.java b/eip-publish-subscribe/src/main/java/com/iluwatar/eip/publish/subscribe/module-info.java
deleted file mode 100644
index 50eab8360..000000000
--- a/eip-publish-subscribe/src/main/java/com/iluwatar/eip/publish/subscribe/module-info.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.eippublishsubscribe {
- requires org.slf4j;
- requires camel.core;
-}
\ No newline at end of file
diff --git a/eip-splitter/README.md b/eip-splitter/README.md
index 648462229..d1206664f 100644
--- a/eip-splitter/README.md
+++ b/eip-splitter/README.md
@@ -28,3 +28,4 @@ Use the Splitter pattern when
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Sequencer.html)
* [Apache Camel - Documentation](http://camel.apache.org/splitter.html)
+* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
diff --git a/eip-wire-tap/README.md b/eip-wire-tap/README.md
index 83b43dfd1..b1fd80466 100644
--- a/eip-wire-tap/README.md
+++ b/eip-wire-tap/README.md
@@ -26,3 +26,4 @@ Use the Wire Tap pattern when
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/WireTap.html)
* [Apache Camel - Documentation](http://camel.apache.org/wire-tap.html)
+* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
index 7a125c042..91bb020ee 100644
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
@@ -31,7 +31,7 @@ public enum Event {
STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED(
"Traitor detected");
- private String description;
+ private final String description;
Event(String description) {
this.description = description;
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
index 9985cee60..7d3f32a68 100644
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
@@ -31,7 +31,7 @@ import java.util.List;
*/
public abstract class EventEmitter {
- private List observers;
+ private final List observers;
public EventEmitter() {
observers = new LinkedList<>();
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
index 9ec61339c..1e0ce9491 100644
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
@@ -36,7 +36,7 @@ public enum Weekday {
SATURDAY("Saturday"),
SUNDAY("Sunday");
- private String description;
+ private final String description;
Weekday(String description) {
this.description = description;
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/module-info.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/module-info.java
deleted file mode 100644
index 93ebd3173..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.eventaggregator {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
index a8bb6cbaa..f8aa5cb37 100644
--- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
@@ -74,7 +74,7 @@ public class KingJoffreyTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class> clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java
index 6925a2ffd..68c4c9781 100644
--- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java
@@ -33,9 +33,9 @@ public class Event implements IEvent, Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(Event.class);
- private int eventId;
- private int eventTime;
- private boolean isSynchronous;
+ private final int eventId;
+ private final int eventTime;
+ private final boolean isSynchronous;
private Thread thread;
private boolean isComplete = false;
private ThreadCompleteListener eventListener;
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java
index 14d28860b..55671fd82 100644
--- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java
@@ -43,8 +43,8 @@ public class EventManager implements ThreadCompleteListener {
public static final int MAX_ID = MAX_RUNNING_EVENTS;
public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes.
private int currentlyRunningSyncEvent = -1;
- private Random rand;
- private Map eventPool;
+ private final Random rand;
+ private final Map eventPool;
private static final String DOES_NOT_EXIST = " does not exist.";
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/module-info.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/module-info.java
deleted file mode 100644
index aa9b6c29d..000000000
--- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.eventasynchronous {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
index c18426c95..dd5e65a9a 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
@@ -32,7 +32,7 @@ import com.iluwatar.eda.model.User;
*/
public class UserCreatedEvent extends AbstractEvent {
- private User user;
+ private final User user;
public UserCreatedEvent(User user) {
this.user = user;
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
index 59583053c..05370c6a6 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
@@ -32,7 +32,7 @@ import com.iluwatar.eda.model.User;
*/
public class UserUpdatedEvent extends AbstractEvent {
- private User user;
+ private final User user;
public UserUpdatedEvent(User user) {
this.user = user;
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
index dd72c1e93..74a7ee145 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class EventDispatcher {
- private Map, Handler extends Event>> handlers;
+ private final Map, Handler extends Event>> handlers;
public EventDispatcher() {
handlers = new HashMap<>();
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
index 1492c175c..0c9f12501 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
@@ -32,7 +32,7 @@ import com.iluwatar.eda.event.UserUpdatedEvent;
*/
public class User {
- private String username;
+ private final String username;
public User(String username) {
this.username = username;
diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java
index 4286a5ed0..a0ff5d987 100644
--- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java
+++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java
@@ -49,7 +49,7 @@ public class Audio {
private volatile Thread updateThread = null;
- private PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING];
+ private final PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING];
// Visible only for testing purposes
Audio() {
diff --git a/event-sourcing/README.md b/event-sourcing/README.md
index 5efbbbd02..6d24a40e5 100644
--- a/event-sourcing/README.md
+++ b/event-sourcing/README.md
@@ -5,7 +5,8 @@ folder: event-sourcing
permalink: /patterns/event-sourcing/
categories: Architectural
tags:
- - Performance
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -30,3 +31,4 @@ Use the Event Sourcing pattern when
* [Martin Fowler - Event Sourcing] (https://martinfowler.com/eaaDev/EventSourcing.html)
* [Event Sourcing | Microsoft Docs] (https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
* [Reference 3: Introducing Event Sourcing] (https://msdn.microsoft.com/en-us/library/jj591559.aspx)
+* [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
diff --git a/execute-around/README.md b/execute-around/README.md
index 677a97a6e..2873aef9b 100644
--- a/execute-around/README.md
+++ b/execute-around/README.md
@@ -9,10 +9,56 @@ tags:
---
## Intent
-Execute Around idiom frees the user from certain actions that
-should always be executed before and after the business method. A good example
-of this is resource allocation and deallocation leaving the user to specify
-only what to do with the resource.
+Execute Around idiom frees the user from certain actions that should always be executed before and after the business
+method. A good example of this is resource allocation and deallocation leaving the user to specify only what to do with
+the resource.
+
+## Explanation
+
+Real world example
+
+> We need to provide a class that can be used to write text strings to files. To make it easy for the user we let our service class open and close the file automatically, the user only has to specify what is written into which file.
+
+In plain words
+
+> Execute Around idiom handles boilerplate code before and after business method.
+
+[Stack Overflow](https://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom) says
+
+> Basically it's the pattern where you write a method to do things which are always required, e.g. resource allocation and clean-up, and make the caller pass in "what we want to do with the resource".
+
+**Programmatic Example**
+
+Let's introduce our file writer class.
+
+```java
+@FunctionalInterface
+public interface FileWriterAction {
+
+ void writeFile(FileWriter writer) throws IOException;
+
+}
+
+public class SimpleFileWriter {
+
+ public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
+ try (var writer = new FileWriter(filename)) {
+ action.writeFile(writer);
+ }
+ }
+}
+```
+
+To utilize the file writer the following code is needed.
+
+```java
+ FileWriterAction writeHello = writer -> {
+ writer.write("Hello");
+ writer.append(" ");
+ writer.append("there!");
+ };
+ new SimpleFileWriter("testfile.txt", writeHello);
+```
## Class diagram

@@ -24,4 +70,4 @@ Use the Execute Around idiom when
## Credits
-* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1)
+* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b)
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/module-info.java b/execute-around/src/main/java/com/iluwatar/execute/around/module-info.java
deleted file mode 100644
index a3e179094..000000000
--- a/execute-around/src/main/java/com/iluwatar/execute/around/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.executearound {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java
index 5a0552b20..1d8054562 100644
--- a/extension-objects/src/main/java/concreteextensions/Commander.java
+++ b/extension-objects/src/main/java/concreteextensions/Commander.java
@@ -35,7 +35,7 @@ public class Commander implements CommanderExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(Commander.class);
- private CommanderUnit unit;
+ private final CommanderUnit unit;
public Commander(CommanderUnit commanderUnit) {
this.unit = commanderUnit;
diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java
index a45b82f11..4f5a474b3 100644
--- a/extension-objects/src/main/java/concreteextensions/Sergeant.java
+++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java
@@ -35,7 +35,7 @@ public class Sergeant implements SergeantExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(Sergeant.class);
- private SergeantUnit unit;
+ private final SergeantUnit unit;
public Sergeant(SergeantUnit sergeantUnit) {
this.unit = sergeantUnit;
diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java
index b47ba595d..d500ab604 100644
--- a/extension-objects/src/main/java/concreteextensions/Soldier.java
+++ b/extension-objects/src/main/java/concreteextensions/Soldier.java
@@ -34,7 +34,7 @@ import units.SoldierUnit;
public class Soldier implements SoldierExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(Soldier.class);
- private SoldierUnit unit;
+ private final SoldierUnit unit;
public Soldier(SoldierUnit soldierUnit) {
this.unit = soldierUnit;
diff --git a/facade/README.md b/facade/README.md
index 48650dfbb..ce9d892b6 100644
--- a/facade/README.md
+++ b/facade/README.md
@@ -83,7 +83,7 @@ public abstract class DwarvenMineWorker {
public abstract String name();
- static enum Action {
+ enum Action {
GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
}
}
@@ -204,4 +204,5 @@ Use the Facade pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/facade/src/main/java/com/iluwatar/facade/module-info.java b/facade/src/main/java/com/iluwatar/facade/module-info.java
deleted file mode 100644
index 966758790..000000000
--- a/facade/src/main/java/com/iluwatar/facade/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.facade {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
index 3b67f3754..10d6e1ecd 100644
--- a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
+++ b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
@@ -110,7 +110,7 @@ public class DwarvenGoldmineFacadeTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/module-info.java b/factory-kit/src/main/java/com/iluwatar/factorykit/module-info.java
deleted file mode 100644
index 9440571c4..000000000
--- a/factory-kit/src/main/java/com/iluwatar/factorykit/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.factorykit {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/factory-method/README.md b/factory-method/README.md
index 48ba6649c..206388537 100644
--- a/factory-method/README.md
+++ b/factory-method/README.md
@@ -83,4 +83,6 @@ Use the Factory Method pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
index b6f29e43a..99ebcef65 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class ElfBlacksmith implements Blacksmith {
- private static Map ELFARSENAL;
+ private static final Map ELFARSENAL;
static {
ELFARSENAL = new HashMap<>(WeaponType.values().length);
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 66a6ea7e7..208dfa277 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
@@ -28,7 +28,7 @@ package com.iluwatar.factory.method;
*/
public class ElfWeapon implements Weapon {
- private WeaponType weaponType;
+ private final WeaponType weaponType;
public ElfWeapon(WeaponType weaponType) {
this.weaponType = weaponType;
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
index b04830085..ea99200de 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class OrcBlacksmith implements Blacksmith {
- private static Map ORCARSENAL;
+ private static final Map ORCARSENAL;
static {
ORCARSENAL = new HashMap<>(WeaponType.values().length);
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 b35adf798..af1ee5bcf 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
@@ -28,7 +28,7 @@ package com.iluwatar.factory.method;
*/
public class OrcWeapon implements Weapon {
- private WeaponType weaponType;
+ private final WeaponType weaponType;
public OrcWeapon(WeaponType weaponType) {
this.weaponType = weaponType;
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java b/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
index 73ab10dd6..6c7c86712 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
@@ -30,7 +30,7 @@ public enum WeaponType {
SHORT_SWORD("short sword"), SPEAR("spear"), AXE("axe"), UNDEFINED("");
- private String title;
+ private final String title;
WeaponType(String title) {
this.title = title;
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/module-info.java b/factory-method/src/main/java/com/iluwatar/factory/method/module-info.java
deleted file mode 100644
index 4ea385c8b..000000000
--- a/factory-method/src/main/java/com/iluwatar/factory/method/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.factorymethod {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/module-info.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/module-info.java
deleted file mode 100644
index 55c2d7714..000000000
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.
- */
-
-module com.iluwatar.featuretoggle {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
index 6e2281b9a..ed6e69518 100644
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
@@ -42,7 +42,7 @@ import java.util.Properties;
*/
public class PropertiesFeatureToggleVersion implements Service {
- private boolean isEnhanced;
+ private final boolean isEnhanced;
/**
* Creates an instance of {@link PropertiesFeatureToggleVersion} using the passed {@link
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
index 5c660ca59..7924f86e8 100644
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
@@ -29,7 +29,7 @@ package com.iluwatar.featuretoggle.user;
*/
public class User {
- private String name;
+ private final String name;
/**
* Default Constructor setting the username.
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
index 524ea6ef8..7b644afd7 100644
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
@@ -35,8 +35,8 @@ import java.util.List;
*/
public class UserGroup {
- private static List freeGroup = new ArrayList<>();
- private static List paidGroup = new ArrayList<>();
+ private static final List freeGroup = new ArrayList<>();
+ private static final List paidGroup = new ArrayList<>();
/**
diff --git a/fluentinterface/README.md b/fluentinterface/README.md
index 3068468b9..61c5f2eb5 100644
--- a/fluentinterface/README.md
+++ b/fluentinterface/README.md
@@ -9,26 +9,151 @@ tags:
---
## Intent
-A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
+A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using
+this pattern results in code that can be read nearly as human language.
-## Implementation
+## Explanation
+The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those interfaces tend
+to mimic domain specific languages, so they can nearly be read as human languages.
+
A fluent interface can be implemented using any of
* Method Chaining - calling a method returns some object on which further methods can be called.
* Static Factory Methods and Imports
* Named parameters - can be simulated in Java using static factory methods.
+Real world example
+
+> We need to select numbers based on different criteria from the list. It's a great chance to utilize fluent interface pattern to provide readable easy-to-use developer experience.
+
+In plain words
+
+> Fluent Interface pattern provides easily readable flowing interface to code.
+
+Wikipedia says
+
+> In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL).
+
+**Programmatic Example**
+
+In this example two implementations of a `FluentIterable` interface are given.
+
+```java
+public interface FluentIterable extends Iterable {
+
+ FluentIterable filter(Predicate super E> predicate);
+
+ Optional first();
+
+ FluentIterable first(int count);
+
+ Optional last();
+
+ FluentIterable last(int count);
+
+ FluentIterable map(Function super E, T> function);
+
+ List asList();
+
+ static List copyToList(Iterable iterable) {
+ var copy = new ArrayList();
+ iterable.forEach(copy::add);
+ return copy;
+ }
+}
+```
+
+The `SimpleFluentIterable` evaluates eagerly and would be too costly for real world applications.
+
+```java
+public class SimpleFluentIterable implements FluentIterable {
+ ...
+}
+```
+
+The `LazyFluentIterable` is evaluated on termination.
+
+```java
+public class LazyFluentIterable implements FluentIterable {
+ ...
+}
+```
+
+Their usage is demonstrated with a simple number list that is filtered, transformed and collected. The
+result is printed afterwards.
+
+```java
+ var integerList = List.of(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68);
+
+ prettyPrint("The initial list contains: ", integerList);
+
+ var firstFiveNegatives = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(negatives())
+ .first(3)
+ .asList();
+ prettyPrint("The first three negative values are: ", firstFiveNegatives);
+
+
+ var lastTwoPositives = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(positives())
+ .last(2)
+ .asList();
+ prettyPrint("The last two positive values are: ", lastTwoPositives);
+
+ SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(number -> number % 2 == 0)
+ .first()
+ .ifPresent(evenNumber -> LOGGER.info("The first even number is: {}", evenNumber));
+
+
+ var transformedList = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(negatives())
+ .map(transformToString())
+ .asList();
+ prettyPrint("A string-mapped list of negative numbers contains: ", transformedList);
+
+
+ var lastTwoOfFirstFourStringMapped = LazyFluentIterable
+ .from(integerList)
+ .filter(positives())
+ .first(4)
+ .last(2)
+ .map(number -> "String[" + valueOf(number) + "]")
+ .asList();
+ prettyPrint("The lazy list contains the last two of the first four positive numbers "
+ + "mapped to Strings: ", lastTwoOfFirstFourStringMapped);
+
+ LazyFluentIterable
+ .from(integerList)
+ .filter(negatives())
+ .first(2)
+ .last()
+ .ifPresent(number -> LOGGER.info("Last amongst first two negatives: {}", number));
+
+ // The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68.
+ // The first three negative values are: -61, -22, -87.
+ // The last two positive values are: 23, 2.
+ // The first even number is: 14
+ // A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68].
+ // The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6].
+ // Last amongst first two negatives: -22
+```
+
## Class diagram

## Applicability
Use the Fluent Interface pattern when
-* you provide an API that would benefit from a DSL-like usage
-* you have objects that are difficult to configure or use
+* You provide an API that would benefit from a DSL-like usage
+* You have objects that are difficult to configure or use
-## Real world examples
+## Known uses
* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)
* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained)
@@ -41,3 +166,4 @@ Use the Fluent Interface pattern when
* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html)
* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/)
* [Internal DSL](http://www.infoq.com/articles/internal-dsls-java)
+* [Domain Specific Languages](https://www.amazon.com/gp/product/0321712943/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0321712943&linkId=ad8351d6f5be7d8b7ecdb650731f85df)
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
index 547c657e4..09513163c 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
@@ -94,7 +94,7 @@ public class App {
.filter(positives())
.first(4)
.last(2)
- .map(number -> "String[" + valueOf(number) + "]")
+ .map(number -> "String[" + number + "]")
.asList();
prettyPrint("The lazy list contains the last two of the first four positive numbers "
+ "mapped to Strings: ", lastTwoOfFirstFourStringMapped);
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
index f001c532f..966f35287 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
@@ -198,7 +198,7 @@ public class LazyFluentIterable implements FluentIterable {
@Override
public Iterator iterator() {
return new DecoratingIterator(null) {
- Iterator oldTypeIterator = iterable.iterator();
+ final Iterator oldTypeIterator = iterable.iterator();
@Override
public T computeNext() {
diff --git a/flux/src/main/java/com/iluwatar/flux/action/Action.java b/flux/src/main/java/com/iluwatar/flux/action/Action.java
index 6a5f608c2..c8e2e012b 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/Action.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/Action.java
@@ -28,7 +28,7 @@ package com.iluwatar.flux.action;
*/
public abstract class Action {
- private ActionType type;
+ private final ActionType type;
public Action(ActionType type) {
this.type = type;
diff --git a/flux/src/main/java/com/iluwatar/flux/action/ActionType.java b/flux/src/main/java/com/iluwatar/flux/action/ActionType.java
index 6399d2806..e84954efd 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/ActionType.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/ActionType.java
@@ -28,6 +28,6 @@ package com.iluwatar.flux.action;
*/
public enum ActionType {
- MENU_ITEM_SELECTED, CONTENT_CHANGED;
+ MENU_ITEM_SELECTED, CONTENT_CHANGED
}
diff --git a/flux/src/main/java/com/iluwatar/flux/action/Content.java b/flux/src/main/java/com/iluwatar/flux/action/Content.java
index 59a63ec18..6fb2e3e0e 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/Content.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/Content.java
@@ -31,7 +31,7 @@ public enum Content {
PRODUCTS("Products - This page lists the company's products."), COMPANY(
"Company - This page displays information about the company.");
- private String title;
+ private final String title;
Content(String title) {
this.title = title;
diff --git a/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java b/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java
index 3b29b6b4e..c70561a65 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java
@@ -28,7 +28,7 @@ package com.iluwatar.flux.action;
*/
public class ContentAction extends Action {
- private Content content;
+ private final Content content;
public ContentAction(Content content) {
super(ActionType.CONTENT_CHANGED);
diff --git a/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java b/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java
index 5ddeefde4..f833a6187 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java
@@ -29,7 +29,7 @@ package com.iluwatar.flux.action;
*/
public class MenuAction extends Action {
- private MenuItem menuItem;
+ private final MenuItem menuItem;
public MenuAction(MenuItem menuItem) {
super(ActionType.MENU_ITEM_SELECTED);
diff --git a/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java b/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java
index f251e1dd7..90fac3e2e 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java
@@ -30,7 +30,7 @@ public enum MenuItem {
HOME("Home"), PRODUCTS("Products"), COMPANY("Company");
- private String title;
+ private final String title;
MenuItem(String title) {
this.title = title;
diff --git a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
index cf09ecf68..27d374f5d 100644
--- a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
+++ b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
@@ -39,7 +39,7 @@ public final class Dispatcher {
private static Dispatcher instance = new Dispatcher();
- private List stores = new LinkedList<>();
+ private final List stores = new LinkedList<>();
private Dispatcher() {
}
diff --git a/flux/src/main/java/com/iluwatar/flux/store/Store.java b/flux/src/main/java/com/iluwatar/flux/store/Store.java
index cfbdf4af5..34188fff2 100644
--- a/flux/src/main/java/com/iluwatar/flux/store/Store.java
+++ b/flux/src/main/java/com/iluwatar/flux/store/Store.java
@@ -33,7 +33,7 @@ import java.util.List;
*/
public abstract class Store {
- private List views = new LinkedList<>();
+ private final List views = new LinkedList<>();
public abstract void onAction(Action action);
diff --git a/flyweight/README.md b/flyweight/README.md
index a263cc438..7b52ef800 100644
--- a/flyweight/README.md
+++ b/flyweight/README.md
@@ -128,4 +128,5 @@ true
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
index 4fa7312e5..e7af8ee00 100644
--- a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
+++ b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
@@ -34,8 +34,8 @@ public class AlchemistShop {
private static final Logger LOGGER = LoggerFactory.getLogger(AlchemistShop.class);
- private List topShelf;
- private List bottomShelf;
+ private final List topShelf;
+ private final List bottomShelf;
/**
* Constructor.
diff --git a/front-controller/README.md b/front-controller/README.md
index f4a2da970..a1c90b950 100644
--- a/front-controller/README.md
+++ b/front-controller/README.md
@@ -29,6 +29,7 @@ Use the Front Controller pattern when
## Credits
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns)
-* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420)
+* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java b/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java
index 57cfb2454..8cbf7c631 100644
--- a/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java
+++ b/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java
@@ -36,7 +36,7 @@ import java.util.List;
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/game-loop/README.md b/game-loop/README.md
index f0a7eeebb..5f2cd9653 100644
--- a/game-loop/README.md
+++ b/game-loop/README.md
@@ -9,33 +9,227 @@ tags:
---
## Intent
-A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates the game state, and renders the game. It tracks the passage of time to control the rate of gameplay.
+A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates
+the game state, and renders the game. It tracks the passage of time to control the rate of gameplay.
-This pattern decouple the progression of game time from user input and processor speed.
+This pattern decouples progression of game time from user input and processor speed.
## Applicability
This pattern is used in every game engine.
## Explanation
-Game loop is the main process of all the game rendering threads. It drives input process, internal status update, rendering, AI and all the other processes.
+Real world example
-There are a lot of implementations of game loop:
+> Game loop is the main process of all the game rendering threads. It's present in all modern games. It drives input process, internal status update, rendering, AI and all the other processes.
-- Frame-based game loop
+In plain words
-Frame-based game loop is the easiest implementation. The loop always keeps spinning for the following three processes: processInput, update and render. The problem with it is you have no control over how fast the game runs. On a fast machine, that loop will spin so fast users won’t be able to see what’s going on. On a slow machine, the game will crawl. If you have a part of the game that’s content-heavy or does more AI or physics, the game will actually play slower there.
+> Game Loop pattern ensures that game time progresses in equal speed in all different hardware setups.
-- Variable-step game loop
+Wikipedia says
-The variable-step game loop chooses a time step to advance based on how much real time passed since the last frame. The longer the frame takes, the bigger steps the game takes. It always keeps up with real time because it will take bigger and bigger steps to get there.
+> The central component of any game, from a programming standpoint, is the game loop. The game loop allows the game to run smoothly regardless of a user's input or lack thereof.
-- Fixed-step game loop
+**Programmatic Example**
-For fixed-step game loop, a certain amount of real time has elapsed since the last turn of the game loop. This is how much game time need to be simulated for the game’s “now” to catch up with the player’s.
+Let's start with something simple. Here's a bullet that will move in our game. For demonstration it's enough that it has 1-dimensional position.
+
+```java
+public class Bullet {
+
+ private float position;
+
+ public Bullet() {
+ position = 0.0f;
+ }
+
+ public float getPosition() {
+ return position;
+ }
+
+ public void setPosition(float position) {
+ this.position = position;
+ }
+}
+```
+
+GameController is responsible for moving objects in the game. Including the aforementioned bullet.
+
+```java
+public class GameController {
+
+ protected final Bullet bullet;
+
+ public GameController() {
+ bullet = new Bullet();
+ }
+
+ public void moveBullet(float offset) {
+ var currentPosition = bullet.getPosition();
+ bullet.setPosition(currentPosition + offset);
+ }
+
+ public float getBulletPosition() {
+ return bullet.getPosition();
+ }
+}
+```
+
+Now we introduce the game loop. Or actually in this demo we have 3 different game loops.
+
+```java
+public enum GameStatus {
+
+ RUNNING, STOPPED
+}
+
+public abstract class GameLoop {
+
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ protected volatile GameStatus status;
+
+ protected GameController controller;
+
+ private Thread gameThread;
+
+ public GameLoop() {
+ controller = new GameController();
+ status = GameStatus.STOPPED;
+ }
+
+ public void run() {
+ status = GameStatus.RUNNING;
+ gameThread = new Thread(() -> processGameLoop());
+ gameThread.start();
+ }
+
+ public void stop() {
+ status = GameStatus.STOPPED;
+ }
+
+ public boolean isGameRunning() {
+ return status == GameStatus.RUNNING;
+ }
+
+ protected void processInput() {
+ try {
+ var lag = new Random().nextInt(200) + 50;
+ Thread.sleep(lag);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+ protected void render() {
+ var position = controller.getBulletPosition();
+ logger.info("Current bullet position: " + position);
+ }
+
+ protected abstract void processGameLoop();
+}
+
+public class FrameBasedGameLoop extends GameLoop {
+
+ @Override
+ protected void processGameLoop() {
+ while (isGameRunning()) {
+ processInput();
+ update();
+ render();
+ }
+ }
+
+ protected void update() {
+ controller.moveBullet(0.5f);
+ }
+}
+
+public class VariableStepGameLoop extends GameLoop {
+
+ @Override
+ protected void processGameLoop() {
+ var lastFrameTime = System.currentTimeMillis();
+ while (isGameRunning()) {
+ processInput();
+ var currentFrameTime = System.currentTimeMillis();
+ var elapsedTime = currentFrameTime - lastFrameTime;
+ update(elapsedTime);
+ lastFrameTime = currentFrameTime;
+ render();
+ }
+ }
+
+ protected void update(Long elapsedTime) {
+ controller.moveBullet(0.5f * elapsedTime / 1000);
+ }
+}
+
+public class FixedStepGameLoop extends GameLoop {
+
+ private static final long MS_PER_FRAME = 20;
+
+ @Override
+ protected void processGameLoop() {
+ var previousTime = System.currentTimeMillis();
+ var lag = 0L;
+ while (isGameRunning()) {
+ var currentTime = System.currentTimeMillis();
+ var elapsedTime = currentTime - previousTime;
+ previousTime = currentTime;
+ lag += elapsedTime;
+
+ processInput();
+
+ while (lag >= MS_PER_FRAME) {
+ update();
+ lag -= MS_PER_FRAME;
+ }
+
+ render();
+ }
+ }
+
+ protected void update() {
+ controller.moveBullet(0.5f * MS_PER_FRAME / 1000);
+ }
+}
+```
+
+Finally we can show all these game loops in action.
+
+```java
+ try {
+ LOGGER.info("Start frame-based game loop:");
+ var frameBasedGameLoop = new FrameBasedGameLoop();
+ frameBasedGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ frameBasedGameLoop.stop();
+ LOGGER.info("Stop frame-based game loop.");
+
+ LOGGER.info("Start variable-step game loop:");
+ var variableStepGameLoop = new VariableStepGameLoop();
+ variableStepGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ variableStepGameLoop.stop();
+ LOGGER.info("Stop variable-step game loop.");
+
+ LOGGER.info("Start fixed-step game loop:");
+ var fixedStepGameLoop = new FixedStepGameLoop();
+ fixedStepGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ fixedStepGameLoop.stop();
+ LOGGER.info("Stop variable-step game loop.");
+
+ } catch (InterruptedException e) {
+ LOGGER.error(e.getMessage());
+ }
+```
## Class diagram

## Credits
-
* [Game Programming Patterns - Game Loop](http://gameprogrammingpatterns.com/game-loop.html)
+* [Game Programming Patterns](https://www.amazon.com/gp/product/0990582906/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0990582906&linkId=1289749a703b3fe0e24cd8d604d7c40b)
+* [Game Engine Architecture, Third Edition](https://www.amazon.com/gp/product/1138035459/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1138035459&linkId=94502746617211bc40e0ef49d29333ac)
diff --git a/half-sync-half-async/README.md b/half-sync-half-async/README.md
index 5cfb411e5..6a6384422 100644
--- a/half-sync-half-async/README.md
+++ b/half-sync-half-async/README.md
@@ -34,4 +34,4 @@ Use Half-Sync/Half-Async pattern when
## Credits
* [Douglas C. Schmidt and Charles D. Cranor - Half Sync/Half Async](https://www.dre.vanderbilt.edu/~schmidt/PDF/PLoP-95.pdf)
-* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697)
+* [Pattern Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://www.amazon.com/gp/product/0471606952/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0471606952&linkCode=as2&tag=javadesignpat-20&linkId=889e4af72dca8261129bf14935e0f8dc)
diff --git a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java
index 7df2264ab..d013924cb 100644
--- a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java
+++ b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java
@@ -95,7 +95,7 @@ public class App {
* ArithmeticSumTask.
*/
static class ArithmeticSumTask implements AsyncTask {
- private long numberOfElements;
+ private final long numberOfElements;
public ArithmeticSumTask(long numberOfElements) {
this.numberOfElements = numberOfElements;
diff --git a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java
index 3a3bb474c..32f5e9d4a 100644
--- a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java
+++ b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java
@@ -48,7 +48,7 @@ public class AsynchronousService {
* tasks should be performed in the background which does not affect the performance of main
* thread.
*/
- private ExecutorService service;
+ private final ExecutorService service;
/**
* Creates an asynchronous service using {@code workQueue} as communication channel between
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java
index 1a0fdb6b0..746b93508 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class InMemoryBank implements WireTransfers {
- private static Map accounts = new HashMap<>();
+ private static final Map accounts = new HashMap<>();
static {
accounts
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java
index 973747acc..5c0461843 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java
@@ -34,7 +34,7 @@ import java.util.Optional;
*/
public class InMemoryTicketRepository implements LotteryTicketRepository {
- private static Map tickets = new HashMap<>();
+ private static final Map tickets = new HashMap<>();
@Override
public Optional findById(LotteryTicketId id) {
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java
index 8988bba88..acdd2b8c5 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java
@@ -116,7 +116,7 @@ public class LotteryNumbers {
*/
private static class RandomNumberGenerator {
- private PrimitiveIterator.OfInt randomIterator;
+ private final PrimitiveIterator.OfInt randomIterator;
/**
* Initialize a new random number generator that generates random numbers in the range [min,
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java
index dfa324449..114e78c9c 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class LotteryTicketId {
- private static AtomicInteger numAllocated = new AtomicInteger(0);
+ private static final AtomicInteger numAllocated = new AtomicInteger(0);
private final int id;
public LotteryTicketId() {
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java
index ba46f2d97..c632debe8 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java
@@ -41,7 +41,7 @@ public class MongoEventLog implements LotteryEventLog {
private MongoDatabase database;
private MongoCollection eventsCollection;
- private StdOutEventLog stdOutEventLog = new StdOutEventLog();
+ private final StdOutEventLog stdOutEventLog = new StdOutEventLog();
/**
* Constructor.
diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java
index 6d3ba8bc5..541b2b98b 100644
--- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java
+++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java
@@ -43,7 +43,7 @@ import org.junit.jupiter.api.Test;
*/
class LotteryTest {
- private Injector injector;
+ private final Injector injector;
@Inject
private LotteryAdministration administration;
@Inject
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java
index 656008c10..52aa890c1 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java
@@ -51,11 +51,11 @@ public class Client extends JFrame { // NOSONAR
private static final long serialVersionUID = 1L;
private transient FilterManager filterManager;
- private JLabel jl;
- private JTextField[] jtFields;
- private JTextArea[] jtAreas;
- private JButton clearButton;
- private JButton processButton;
+ private final JLabel jl;
+ private final JTextField[] jtFields;
+ private final JTextArea[] jtAreas;
+ private final JButton clearButton;
+ private final JButton processButton;
/**
* Constructor.
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
index e8f3b941f..91e438882 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
@@ -30,7 +30,7 @@ package com.iluwatar.intercepting.filter;
*/
public class FilterManager {
- private FilterChain filterChain;
+ private final FilterChain filterChain;
public FilterManager() {
filterChain = new FilterChain();
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java
index 08ed715b1..db552356d 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java
@@ -46,9 +46,9 @@ public class Target extends JFrame { //NOSONAR
private static final long serialVersionUID = 1L;
- private JTable jt;
- private DefaultTableModel dtm;
- private JButton del;
+ private final JTable jt;
+ private final DefaultTableModel dtm;
+ private final JButton del;
/**
* Constructor.
diff --git a/interpreter/README.md b/interpreter/README.md
index 6a941d2e5..505f417d1 100644
--- a/interpreter/README.md
+++ b/interpreter/README.md
@@ -34,4 +34,6 @@ trees. The Interpreter pattern works best when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java
index 24ef7914e..46b5c96cb 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java
@@ -28,8 +28,8 @@ package com.iluwatar.interpreter;
*/
public class MinusExpression extends Expression {
- private Expression leftExpression;
- private Expression rightExpression;
+ private final Expression leftExpression;
+ private final Expression rightExpression;
public MinusExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java
index 606937e0b..926d6c119 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java
@@ -28,8 +28,8 @@ package com.iluwatar.interpreter;
*/
public class MultiplyExpression extends Expression {
- private Expression leftExpression;
- private Expression rightExpression;
+ private final Expression leftExpression;
+ private final Expression rightExpression;
public MultiplyExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java
index 6b957f6aa..908eec8d1 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java
@@ -28,7 +28,7 @@ package com.iluwatar.interpreter;
*/
public class NumberExpression extends Expression {
- private int number;
+ private final int number;
public NumberExpression(int number) {
this.number = number;
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java
index 1ce080259..38a8bb4af 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java
@@ -28,8 +28,8 @@ package com.iluwatar.interpreter;
*/
public class PlusExpression extends Expression {
- private Expression leftExpression;
- private Expression rightExpression;
+ private final Expression leftExpression;
+ private final Expression rightExpression;
public PlusExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
diff --git a/iterator/README.md b/iterator/README.md
index 61cf0291a..a98010c5a 100644
--- a/iterator/README.md
+++ b/iterator/README.md
@@ -15,6 +15,105 @@ Cursor
Provide a way to access the elements of an aggregate object
sequentially without exposing its underlying representation.
+## Explanation
+
+Real world example
+
+> Treasure chest contains a set of magical items. There multiple types of items such as rings, potions and weapons. The items can be browsed by type using an iterator the treasure chest provides.
+
+In plain words
+
+> Containers can provide a representation agnostic iterator interface to provide access to the elements.
+
+Wikipedia says
+
+> In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements.
+
+**Programmatic Example**
+
+The main class in our example is the treasure chest that contains items.
+
+```java
+public class TreasureChest {
+
+ private final List- items;
+
+ public TreasureChest() {
+ items = List.of(
+ new Item(ItemType.POTION, "Potion of courage"),
+ new Item(ItemType.RING, "Ring of shadows"),
+ new Item(ItemType.POTION, "Potion of wisdom"),
+ new Item(ItemType.POTION, "Potion of blood"),
+ new Item(ItemType.WEAPON, "Sword of silver +1"),
+ new Item(ItemType.POTION, "Potion of rust"),
+ new Item(ItemType.POTION, "Potion of healing"),
+ new Item(ItemType.RING, "Ring of armor"),
+ new Item(ItemType.WEAPON, "Steel halberd"),
+ new Item(ItemType.WEAPON, "Dagger of poison"));
+ }
+
+ public Iterator
- iterator(ItemType itemType) {
+ return new TreasureChestItemIterator(this, itemType);
+ }
+
+ public List
- getItems() {
+ return new ArrayList<>(items);
+ }
+}
+
+public class Item {
+
+ private ItemType type;
+ private final String name;
+
+ public Item(ItemType type, String name) {
+ this.setType(type);
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public ItemType getType() {
+ return type;
+ }
+
+ public final void setType(ItemType type) {
+ this.type = type;
+ }
+}
+
+public enum ItemType {
+
+ ANY, WEAPON, RING, POTION
+
+}
+```
+
+The iterator interface is extremely simple.
+
+```java
+public interface Iterator {
+
+ boolean hasNext();
+
+ T next();
+}
+```
+
+In the following example we iterate through the ring type items found in the chest.
+
+```java
+var itemIterator = TREASURE_CHEST.iterator(ItemType.RING);
+while (itemIterator.hasNext()) {
+ LOGGER.info(itemIterator.next().toString());
+}
+// Ring of shadows
+// Ring of armor
+```
+
## Class diagram

@@ -32,4 +131,5 @@ Use the Iterator pattern
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java b/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java
index b3e0dc3d6..9f584cddc 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java
@@ -36,7 +36,7 @@ import java.util.NoSuchElementException;
*/
public class BstIterator> implements Iterator> {
- private ArrayDeque> pathStack;
+ private final ArrayDeque> pathStack;
public BstIterator(TreeNode root) {
pathStack = new ArrayDeque<>();
diff --git a/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java b/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java
index 87f16e96c..b0ec5f486 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java
@@ -31,7 +31,7 @@ package com.iluwatar.iterator.bst;
*/
public class TreeNode> {
- private T val;
+ private final T val;
private TreeNode left;
private TreeNode right;
diff --git a/iterator/src/main/java/com/iluwatar/iterator/list/Item.java b/iterator/src/main/java/com/iluwatar/iterator/list/Item.java
index 82e66eb30..00d5625a8 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/list/Item.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/list/Item.java
@@ -29,7 +29,7 @@ package com.iluwatar.iterator.list;
public class Item {
private ItemType type;
- private String name;
+ private final String name;
public Item(ItemType type, String name) {
this.setType(type);
diff --git a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java
index f390c760f..8eb4a8e18 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java
@@ -32,7 +32,7 @@ import java.util.List;
*/
public class TreasureChest {
- private List
- items;
+ private final List
- items;
/**
* Constructor.
diff --git a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java
index 90461c420..a309b4ece 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java
@@ -30,9 +30,9 @@ import com.iluwatar.iterator.Iterator;
*/
public class TreasureChestItemIterator implements Iterator
- {
- private TreasureChest chest;
+ private final TreasureChest chest;
private int idx;
- private ItemType type;
+ private final ItemType type;
/**
* Constructor.
diff --git a/layers/README.md b/layers/README.md
index 58c9cd828..1e309f92b 100644
--- a/layers/README.md
+++ b/layers/README.md
@@ -79,7 +79,7 @@ public class CakeViewImpl implements View {
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
- private CakeBakingService cakeBakingService;
+ private final CakeBakingService cakeBakingService;
public CakeViewImpl(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
@@ -103,4 +103,4 @@ Use the Layers architecture when
## Credits
-* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697)
+* [Pattern Oriented Software Architecture Volume 1: A System of Patterns](https://www.amazon.com/gp/product/0471958697/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0471958697&linkCode=as2&tag=javadesignpat-20&linkId=e3f42d7a2a4cc8c619bbc0136b20dadb)
diff --git a/layers/src/main/java/com/iluwatar/layers/app/App.java b/layers/src/main/java/com/iluwatar/layers/app/App.java
index afeb5ba50..e5a4f9995 100644
--- a/layers/src/main/java/com/iluwatar/layers/app/App.java
+++ b/layers/src/main/java/com/iluwatar/layers/app/App.java
@@ -80,7 +80,7 @@ import java.util.List;
*/
public class App {
- private static CakeBakingService cakeBakingService = new CakeBakingServiceImpl();
+ private static final CakeBakingService cakeBakingService = new CakeBakingServiceImpl();
/**
* Application entry point.
diff --git a/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java b/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java
index 226b5bcea..14fee4dfa 100644
--- a/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java
+++ b/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java
@@ -52,7 +52,7 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional
public class CakeBakingServiceImpl implements CakeBakingService {
- private AbstractApplicationContext context;
+ private final AbstractApplicationContext context;
public CakeBakingServiceImpl() {
this.context = new ClassPathXmlApplicationContext("applicationContext.xml");
diff --git a/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java b/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java
index 5fcaac776..a5246e7db 100644
--- a/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java
+++ b/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java
@@ -34,7 +34,7 @@ public class CakeViewImpl implements View {
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
- private CakeBakingService cakeBakingService;
+ private final CakeBakingService cakeBakingService;
public CakeViewImpl(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
diff --git a/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java b/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java
index b707731d2..3c13966de 100644
--- a/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java
+++ b/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java
@@ -90,7 +90,7 @@ public class CakeViewImplTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/lazy-loading/README.md b/lazy-loading/README.md
index 997149b03..53e3b0a83 100644
--- a/lazy-loading/README.md
+++ b/lazy-loading/README.md
@@ -28,4 +28,5 @@ Use the Lazy Loading idiom when
## Credits
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a)
diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java
index 2854a7822..395dfb81c 100644
--- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java
+++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java
@@ -55,7 +55,7 @@ public class Java8Holder {
}
}
- if (!HeavyFactory.class.isInstance(heavy)) {
+ if (!(heavy instanceof HeavyFactory)) {
heavy = new HeavyFactory();
}
diff --git a/leader-election/README.md b/leader-election/README.md
index e6b2428dd..85943d5b4 100644
--- a/leader-election/README.md
+++ b/leader-election/README.md
@@ -9,7 +9,7 @@ tags:
---
## Intent
-Leader Election pattern is commonly used in cloud system design. It can help to ensure that task instances selec the leader instance correctly and do not conflict with each other, cause contention for shared resources, or inadvertently interfere with the work that other task instances are performing.
+Leader Election pattern is commonly used in cloud system design. It can help to ensure that task instances select the leader instance correctly and do not conflict with each other, cause contention for shared resources, or inadvertently interfere with the work that other task instances are performing.
## Class diagram

@@ -30,4 +30,4 @@ Do not use this pattern when
## Credits
-* [ Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568104(v=pandp.10))
+* [Leader Election pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/leader-election)
diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java
index 3138427a3..3461bc8c0 100644
--- a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java
+++ b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java
@@ -31,7 +31,7 @@ import java.util.concurrent.BlockingQueue;
*/
public class TaskSet {
- private BlockingQueue queue = new ArrayBlockingQueue<>(100);
+ private final BlockingQueue queue = new ArrayBlockingQueue<>(100);
public void addTask(Task task) throws InterruptedException {
queue.put(task);
diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java
index 7c63d95d2..935462037 100644
--- a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java
+++ b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java
@@ -34,7 +34,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public class WorkCenter {
private Worker leader;
- private List workers = new CopyOnWriteArrayList<>();
+ private final List workers = new CopyOnWriteArrayList<>();
/**
* Create workers and set leader.
diff --git a/marker/README.md b/marker/README.md
index a411827c3..d8664327f 100644
--- a/marker/README.md
+++ b/marker/README.md
@@ -27,4 +27,4 @@ Use the Marker Interface pattern when
## Credits
-* [Effective Java 2nd Edition by Joshua Bloch](https://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683)
+* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb)
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java
index 6b20211f5..6f889edaa 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java
@@ -81,7 +81,7 @@ public abstract class Master {
for (var i = 0; i < this.expectedNumResults; i++) {
//ith division given to ith worker in this.workers
this.workers.get(i).setReceivedData(this, dividedInput.get(i));
- this.workers.get(i).run();
+ this.workers.get(i).start();
}
}
}
diff --git a/mediator/README.md b/mediator/README.md
index e8e0fa412..22b4556ac 100644
--- a/mediator/README.md
+++ b/mediator/README.md
@@ -34,4 +34,5 @@ Use the Mediator pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/mediator/src/main/java/com/iluwatar/mediator/Action.java b/mediator/src/main/java/com/iluwatar/mediator/Action.java
index 1d93a384b..60ce3949a 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/Action.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/Action.java
@@ -1,52 +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.mediator;
-
-/**
- * Action enumeration.
- */
-public enum Action {
-
- HUNT("hunted a rabbit", "arrives for dinner"),
- TALE("tells a tale", "comes to listen"),
- GOLD("found gold", "takes his share of the gold"),
- ENEMY("spotted enemies", "runs for cover"),
- NONE("", "");
-
- private final String title;
- private final String description;
-
- Action(String title, String description) {
- this.title = title;
- this.description = description;
- }
-
- public String getDescription() {
- return description;
- }
-
- public String toString() {
- return title;
- }
-}
+/*
+ * 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.mediator;
+
+/**
+ * Action enumeration.
+ */
+public enum Action {
+ HUNT("hunted a rabbit", "arrives for dinner"),
+ TALE("tells a tale", "comes to listen"),
+ GOLD("found gold", "takes his share of the gold"),
+ ENEMY("spotted enemies", "runs for cover"),
+ NONE("", "");
+
+ private final String title;
+ private final String description;
+
+ Action(String title, String description) {
+ this.title = title;
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String toString() {
+ return title;
+ }
+}
diff --git a/memento/README.md b/memento/README.md
index 6dd262f9c..b8d95b72a 100644
--- a/memento/README.md
+++ b/memento/README.md
@@ -12,8 +12,177 @@ tags:
Token
## Intent
-Without violating encapsulation, capture and externalize an
-object's internal state so that the object can be restored to this state later.
+Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored
+to this state later.
+
+## Explanation
+Real world example
+
+> We are working on astrology application where we need to analyze star properties over time. We are creating snapshots of star state using Memento pattern.
+
+In plain words
+
+> Memento pattern captures object internal state making it easy to store and restore objects in any point of time.
+
+Wikipedia says
+
+> The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback).
+
+**Programmatic Example**
+
+Let's first define the types of stars we are capable to handle.
+
+```java
+public enum StarType {
+
+ SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
+ "dead star"), UNDEFINED("");
+
+ private final String title;
+
+ StarType(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
+```
+
+Next let's jump straight to the essentials. Here's the star class along with the mementos that we need manipulate.
+
+```java
+public interface StarMemento {
+}
+
+public class Star {
+
+ private StarType type;
+ private int ageYears;
+ private int massTons;
+
+ public Star(StarType startType, int startAge, int startMass) {
+ this.type = startType;
+ this.ageYears = startAge;
+ this.massTons = startMass;
+ }
+
+ public void timePasses() {
+ ageYears *= 2;
+ massTons *= 8;
+ switch (type) {
+ case RED_GIANT:
+ type = StarType.WHITE_DWARF;
+ break;
+ case SUN:
+ type = StarType.RED_GIANT;
+ break;
+ case SUPERNOVA:
+ type = StarType.DEAD;
+ break;
+ case WHITE_DWARF:
+ type = StarType.SUPERNOVA;
+ break;
+ case DEAD:
+ ageYears *= 2;
+ massTons = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ StarMemento getMemento() {
+
+ StarMementoInternal state = new StarMementoInternal();
+ state.setAgeYears(ageYears);
+ state.setMassTons(massTons);
+ state.setType(type);
+ return state;
+ }
+
+ void setMemento(StarMemento memento) {
+
+ StarMementoInternal state = (StarMementoInternal) memento;
+ this.type = state.getType();
+ this.ageYears = state.getAgeYears();
+ this.massTons = state.getMassTons();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons);
+ }
+
+ private static class StarMementoInternal implements StarMemento {
+
+ private StarType type;
+ private int ageYears;
+ private int massTons;
+
+ public StarType getType() {
+ return type;
+ }
+
+ public void setType(StarType type) {
+ this.type = type;
+ }
+
+ public int getAgeYears() {
+ return ageYears;
+ }
+
+ public void setAgeYears(int ageYears) {
+ this.ageYears = ageYears;
+ }
+
+ public int getMassTons() {
+ return massTons;
+ }
+
+ public void setMassTons(int massTons) {
+ this.massTons = massTons;
+ }
+ }
+}
+```
+
+And finally here's how we use the mementos to store and restore star states.
+
+```java
+ Stack states = new Stack<>();
+ Star star = new Star(StarType.SUN, 10000000, 500000);
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ while (states.size() > 0) {
+ star.setMemento(states.pop());
+ LOGGER.info(star.toString());
+ }
+
+ // sun age: 10000000 years mass: 500000 tons
+ // red giant age: 20000000 years mass: 4000000 tons
+ // white dwarf age: 40000000 years mass: 32000000 tons
+ // supernova age: 80000000 years mass: 256000000 tons
+ // dead star age: 160000000 years mass: 2048000000 tons
+ // supernova age: 80000000 years mass: 256000000 tons
+ // white dwarf age: 40000000 years mass: 32000000 tons
+ // red giant age: 20000000 years mass: 4000000 tons
+ // sun age: 10000000 years mass: 500000 tons
+```
+
## Class diagram

@@ -30,4 +199,5 @@ Use the Memento pattern when
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/model-view-controller/README.md b/model-view-controller/README.md
index c1542df04..7d2430642 100644
--- a/model-view-controller/README.md
+++ b/model-view-controller/README.md
@@ -25,5 +25,7 @@ Use the Model-View-Controller pattern when
## Credits
* [Trygve Reenskaug - Model-view-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
-* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
-* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a)
+* [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)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java
index 77034d76b..0f89d8f89 100644
--- a/module/src/main/java/com/iluwatar/module/App.java
+++ b/module/src/main/java/com/iluwatar/module/App.java
@@ -37,6 +37,8 @@ import java.io.FileNotFoundException;
*/
public class App {
+ private static final String ERROR = "Error";
+ private static final String MESSAGE = "Message";
public static FileLoggerModule fileLoggerModule;
public static ConsoleLoggerModule consoleLoggerModule;
@@ -69,12 +71,12 @@ public class App {
public static void execute() {
/* Send logs on file system */
- fileLoggerModule.printString("Message");
- fileLoggerModule.printErrorString("Error");
+ fileLoggerModule.printString(MESSAGE);
+ fileLoggerModule.printErrorString(ERROR);
/* Send logs on console */
- consoleLoggerModule.printString("Message");
- consoleLoggerModule.printErrorString("Error");
+ consoleLoggerModule.printString(MESSAGE);
+ consoleLoggerModule.printErrorString(ERROR);
}
/**
diff --git a/monad/src/main/java/com/iluwatar/monad/User.java b/monad/src/main/java/com/iluwatar/monad/User.java
index f67009bc3..8644c4c0a 100644
--- a/monad/src/main/java/com/iluwatar/monad/User.java
+++ b/monad/src/main/java/com/iluwatar/monad/User.java
@@ -1,66 +1,66 @@
-/*
- * 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.monad;
-
-/**
- * User Definition.
- */
-public class User {
-
- private final String name;
- private final int age;
- private final Sex sex;
- private final String email;
-
- /**
- * Constructor.
- *
- * @param name - name
- * @param age - age
- * @param sex - sex
- * @param email - email address
- */
- public User(String name, int age, Sex sex, String email) {
- this.name = name;
- this.age = age;
- this.sex = sex;
- this.email = email;
- }
-
- public String getName() {
- return name;
- }
-
- public int getAge() {
- return age;
- }
-
- public Sex getSex() {
- return sex;
- }
-
- public String getEmail() {
- return email;
- }
-}
+/*
+ * 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.monad;
+
+/**
+ * User Definition.
+ */
+public class User {
+
+ private final String name;
+ private final int age;
+ private final Sex sex;
+ private final String email;
+
+ /**
+ * Constructor.
+ *
+ * @param name - name
+ * @param age - age
+ * @param sex - sex
+ * @param email - email address
+ */
+ public User(String name, int age, Sex sex, String email) {
+ this.name = name;
+ this.age = age;
+ this.sex = sex;
+ this.email = email;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public Sex getSex() {
+ return sex;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
diff --git a/multiton/README.md b/multiton/README.md
index 4387cf7ac..85ce3acf2 100644
--- a/multiton/README.md
+++ b/multiton/README.md
@@ -12,8 +12,88 @@ tags:
Registry
## Intent
-Ensure a class only has limited number of instances, and provide a
-global point of access to them.
+Ensure a class only has limited number of instances and provide a global point of access to them.
+
+## Explanation
+
+Real world example
+
+> The Nazgûl, also called ringwraiths or the Nine Riders, are Sauron's most terrible servants. By definition there's always nine of them.
+
+In plain words
+
+> Multiton pattern ensures there's predefined amount of instances available globally.
+
+Wikipedia says
+
+> In software engineering, the multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the singleton allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a map.
+
+**Programmatic Example**
+
+Nazgul is the multiton class.
+
+```java
+public enum NazgulName {
+
+ KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
+}
+
+public final class Nazgul {
+
+ private static final Map nazguls;
+
+ private final NazgulName name;
+
+ static {
+ nazguls = new ConcurrentHashMap<>();
+ nazguls.put(NazgulName.KHAMUL, new Nazgul(NazgulName.KHAMUL));
+ nazguls.put(NazgulName.MURAZOR, new Nazgul(NazgulName.MURAZOR));
+ nazguls.put(NazgulName.DWAR, new Nazgul(NazgulName.DWAR));
+ nazguls.put(NazgulName.JI_INDUR, new Nazgul(NazgulName.JI_INDUR));
+ nazguls.put(NazgulName.AKHORAHIL, new Nazgul(NazgulName.AKHORAHIL));
+ nazguls.put(NazgulName.HOARMURATH, new Nazgul(NazgulName.HOARMURATH));
+ nazguls.put(NazgulName.ADUNAPHEL, new Nazgul(NazgulName.ADUNAPHEL));
+ nazguls.put(NazgulName.REN, new Nazgul(NazgulName.REN));
+ nazguls.put(NazgulName.UVATHA, new Nazgul(NazgulName.UVATHA));
+ }
+
+ private Nazgul(NazgulName name) {
+ this.name = name;
+ }
+
+ public static Nazgul getInstance(NazgulName name) {
+ return nazguls.get(name);
+ }
+
+ public NazgulName getName() {
+ return name;
+ }
+}
+```
+
+And here's how we access the Nazgul instances.
+
+```java
+ LOGGER.info("KHAMUL={}", Nazgul.getInstance(NazgulName.KHAMUL));
+ LOGGER.info("MURAZOR={}", Nazgul.getInstance(NazgulName.MURAZOR));
+ LOGGER.info("DWAR={}", Nazgul.getInstance(NazgulName.DWAR));
+ LOGGER.info("JI_INDUR={}", Nazgul.getInstance(NazgulName.JI_INDUR));
+ LOGGER.info("AKHORAHIL={}", Nazgul.getInstance(NazgulName.AKHORAHIL));
+ LOGGER.info("HOARMURATH={}", Nazgul.getInstance(NazgulName.HOARMURATH));
+ LOGGER.info("ADUNAPHEL={}", Nazgul.getInstance(NazgulName.ADUNAPHEL));
+ LOGGER.info("REN={}", Nazgul.getInstance(NazgulName.REN));
+ LOGGER.info("UVATHA={}", Nazgul.getInstance(NazgulName.UVATHA));
+
+ // KHAMUL=com.iluwatar.multiton.Nazgul@2b214b94
+ // MURAZOR=com.iluwatar.multiton.Nazgul@17814b1c
+ // DWAR=com.iluwatar.multiton.Nazgul@7ac9af2a
+ // JI_INDUR=com.iluwatar.multiton.Nazgul@7bb004b8
+ // AKHORAHIL=com.iluwatar.multiton.Nazgul@78e89bfe
+ // HOARMURATH=com.iluwatar.multiton.Nazgul@652ce654
+ // ADUNAPHEL=com.iluwatar.multiton.Nazgul@522ba524
+ // REN=com.iluwatar.multiton.Nazgul@29c5ee1d
+ // UVATHA=com.iluwatar.multiton.Nazgul@15cea7b0
+```
## Class diagram

diff --git a/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java b/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
index bd1fc70ef..e08107eeb 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
@@ -33,7 +33,7 @@ public final class Nazgul {
private static final Map nazguls;
- private NazgulName name;
+ private final NazgulName name;
static {
nazguls = new ConcurrentHashMap<>();
diff --git a/null-object/README.md b/null-object/README.md
index d0a6f530d..5b943630e 100644
--- a/null-object/README.md
+++ b/null-object/README.md
@@ -18,6 +18,143 @@ implements the expected interface, but whose method body is empty. The
advantage of this approach over a working default implementation is that a Null
Object is very predictable and has no side effects: it does nothing.
+## Explanation
+
+Real world example
+
+> We are building a binary tree from nodes. There are ordinary nodes and "empty" nodes. Traversing the tree normally should not cause errors, so we use null object pattern where necessary.
+
+In plain words
+
+> Null Object pattern handles "empty" objects gracefully.
+
+Wikipedia says
+
+> In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).
+
+**Programmatic Example**
+
+Here's the definitions for node interface and its implementations.
+
+```java
+public interface Node {
+
+ String getName();
+
+ int getTreeSize();
+
+ Node getLeft();
+
+ Node getRight();
+
+ void walk();
+}
+
+public class NodeImpl implements Node {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NodeImpl.class);
+
+ private final String name;
+ private final Node left;
+ private final Node right;
+
+ /**
+ * Constructor.
+ */
+ public NodeImpl(String name, Node left, Node right) {
+ this.name = name;
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public int getTreeSize() {
+ return 1 + left.getTreeSize() + right.getTreeSize();
+ }
+
+ @Override
+ public Node getLeft() {
+ return left;
+ }
+
+ @Override
+ public Node getRight() {
+ return right;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void walk() {
+ LOGGER.info(name);
+ if (left.getTreeSize() > 0) {
+ left.walk();
+ }
+ if (right.getTreeSize() > 0) {
+ right.walk();
+ }
+ }
+}
+
+public final class NullNode implements Node {
+
+ private static final NullNode instance = new NullNode();
+
+ private NullNode() {
+ }
+
+ public static NullNode getInstance() {
+ return instance;
+ }
+
+ @Override
+ public int getTreeSize() {
+ return 0;
+ }
+
+ @Override
+ public Node getLeft() {
+ return null;
+ }
+
+ @Override
+ public Node getRight() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public void walk() {
+ // Do nothing
+ }
+}
+
+```
+
+Then we can construct and traverse the binary tree without errors as follows.
+
+```java
+ Node root =
+ new NodeImpl("1", new NodeImpl("11", new NodeImpl("111", NullNode.getInstance(),
+ NullNode.getInstance()), NullNode.getInstance()), new NodeImpl("12",
+ NullNode.getInstance(), new NodeImpl("122", NullNode.getInstance(),
+ NullNode.getInstance())));
+ root.walk();
+
+ // 1
+ // 11
+ // 111
+ // 12
+ // 122
+```
+
## Class diagram

@@ -28,4 +165,5 @@ Use the Null Object pattern when
## Credits
-* [Pattern Languages of Program Design](http://www.amazon.com/Pattern-Languages-Program-Design-Coplien/dp/0201607344/ref=sr_1_1)
+* [Pattern Languages of Program Design 3](https://www.amazon.com/gp/product/0201310112/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201310112&linkCode=as2&tag=javadesignpat-20&linkId=7372ffb8a4e39a3bb10f199b89aef921)
+* [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)
diff --git a/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java b/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java
index 9b28c249b..472a1a2fd 100644
--- a/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java
+++ b/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java
@@ -30,7 +30,7 @@ package com.iluwatar.nullobject;
*/
public final class NullNode implements Node {
- private static NullNode instance = new NullNode();
+ private static final NullNode instance = new NullNode();
private NullNode() {
}
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
index 4ff30f524..3fe584425 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
@@ -141,7 +141,7 @@ public class TreeTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/King.java b/object-mother/src/main/java/com/iluwatar/objectmother/King.java
index 314d152fd..2bd6a39cd 100644
--- a/object-mother/src/main/java/com/iluwatar/objectmother/King.java
+++ b/object-mother/src/main/java/com/iluwatar/objectmother/King.java
@@ -60,7 +60,7 @@ public class King implements Royalty {
* @param queen Queen which should be flirted.
*/
public void flirt(Queen queen) {
- boolean flirtStatus = queen.getFlirted(this);
+ var flirtStatus = queen.getFlirted(this);
if (!flirtStatus) {
this.makeUnhappy();
} else {
diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java
index 4c704f6b1..308760ba9 100644
--- a/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java
+++ b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java
@@ -66,9 +66,6 @@ public class Queen implements Royalty {
* @return A value which describes if the flirt was successful or not.
*/
public boolean getFlirted(King king) {
- if (this.isFlirty && king.isHappy && !king.isDrunk) {
- return true;
- }
- return false;
+ return this.isFlirty && king.isHappy && !king.isDrunk;
}
}
diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java
index 5650e5f48..ff4c8bf39 100644
--- a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java
+++ b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java
@@ -43,7 +43,7 @@ public final class RoyaltyObjectMother {
* @return A drunk {@link com.iluwatar.objectmother.King}.
*/
public static King createDrunkKing() {
- King king = new King();
+ var king = new King();
king.makeDrunk();
return king;
}
@@ -54,7 +54,7 @@ public final class RoyaltyObjectMother {
* @return A happy {@link com.iluwatar.objectmother.King}.
*/
public static King createHappyKing() {
- King king = new King();
+ var king = new King();
king.makeHappy();
return king;
}
@@ -65,7 +65,7 @@ public final class RoyaltyObjectMother {
* @return A drunk and happy {@link com.iluwatar.objectmother.King}.
*/
public static King createHappyDrunkKing() {
- King king = new King();
+ var king = new King();
king.makeHappy();
king.makeDrunk();
return king;
@@ -77,7 +77,7 @@ public final class RoyaltyObjectMother {
* @return A flirty {@link com.iluwatar.objectmother.Queen}.
*/
public static Queen createFlirtyQueen() {
- Queen queen = new Queen();
+ var queen = new Queen();
queen.setFlirtiness(true);
return queen;
}
diff --git a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java
index b9b211d96..525b8e24e 100644
--- a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java
+++ b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java
@@ -40,50 +40,50 @@ public class RoyaltyObjectMotherTest {
@Test
public void unsuccessfulKingFlirt() {
- King soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing();
- Queen flirtyQueen = RoyaltyObjectMother.createFlirtyQueen();
+ var soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing();
+ var flirtyQueen = RoyaltyObjectMother.createFlirtyQueen();
soberUnhappyKing.flirt(flirtyQueen);
assertFalse(soberUnhappyKing.isHappy());
}
@Test
public void queenIsBlockingFlirtCauseDrunkKing() {
- King drunkUnhappyKing = RoyaltyObjectMother.createDrunkKing();
- Queen notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen();
+ var drunkUnhappyKing = RoyaltyObjectMother.createDrunkKing();
+ var notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen();
drunkUnhappyKing.flirt(notFlirtyQueen);
assertFalse(drunkUnhappyKing.isHappy());
}
@Test
public void queenIsBlockingFlirt() {
- King soberHappyKing = RoyaltyObjectMother.createHappyKing();
- Queen notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen();
+ var soberHappyKing = RoyaltyObjectMother.createHappyKing();
+ var notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen();
soberHappyKing.flirt(notFlirtyQueen);
assertFalse(soberHappyKing.isHappy());
}
@Test
public void successfullKingFlirt() {
- King soberHappyKing = RoyaltyObjectMother.createHappyKing();
- Queen flirtyQueen = RoyaltyObjectMother.createFlirtyQueen();
+ var soberHappyKing = RoyaltyObjectMother.createHappyKing();
+ var flirtyQueen = RoyaltyObjectMother.createFlirtyQueen();
soberHappyKing.flirt(flirtyQueen);
assertTrue(soberHappyKing.isHappy());
}
@Test
public void testQueenType() {
- Royalty flirtyQueen = RoyaltyObjectMother.createFlirtyQueen();
- Royalty notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen();
+ var flirtyQueen = RoyaltyObjectMother.createFlirtyQueen();
+ var notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen();
assertEquals(flirtyQueen.getClass(), Queen.class);
assertEquals(notFlirtyQueen.getClass(), Queen.class);
}
@Test
public void testKingType() {
- Royalty drunkKing = RoyaltyObjectMother.createDrunkKing();
- Royalty happyDrunkKing = RoyaltyObjectMother.createHappyDrunkKing();
- Royalty happyKing = RoyaltyObjectMother.createHappyKing();
- Royalty soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing();
+ var drunkKing = RoyaltyObjectMother.createDrunkKing();
+ var happyDrunkKing = RoyaltyObjectMother.createHappyDrunkKing();
+ var happyKing = RoyaltyObjectMother.createHappyKing();
+ var soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing();
assertEquals(drunkKing.getClass(), King.class);
assertEquals(happyDrunkKing.getClass(), King.class);
assertEquals(happyKing.getClass(), King.class);
diff --git a/object-pool/README.md b/object-pool/README.md
index efbf692ae..34d216a02 100644
--- a/object-pool/README.md
+++ b/object-pool/README.md
@@ -15,6 +15,104 @@ short periods of time it is advantageous to utilize the Object Pool pattern.
The Object Pool provides a cache for instantiated objects tracking which ones
are in use and which are available.
+## Explanation
+
+Real world example
+
+> In our war game we need to use oliphaunts, massive and mythic beasts, but the problem is that they are extremely expensive to create. The solution is to create a pool of them, track which ones are in-use, and instead of disposing them re-use the instances.
+
+In plain words
+
+> Object Pool manages a set of instances instead of creating and destroying them on demand.
+
+Wikipedia says
+
+> The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a "pool" – rather than allocating and destroying them on demand.
+
+**Programmatic Example**
+
+Here's the basic Oliphaunt class. These are very expensive to create.
+
+```java
+public class Oliphaunt {
+
+ private static final AtomicInteger counter = new AtomicInteger(0);
+
+ private final int id;
+
+ public Oliphaunt() {
+ id = counter.incrementAndGet();
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Oliphaunt id=%d", id);
+ }
+}
+```
+
+Next we present the Object Pool and more specifically Oliphaunt Pool.
+
+```java
+public abstract class ObjectPool {
+
+ private final Set available = new HashSet<>();
+ private final Set inUse = new HashSet<>();
+
+ protected abstract T create();
+
+ public synchronized T checkOut() {
+ if (available.isEmpty()) {
+ available.add(create());
+ }
+ var instance = available.iterator().next();
+ available.remove(instance);
+ inUse.add(instance);
+ return instance;
+ }
+
+ public synchronized void checkIn(T instance) {
+ inUse.remove(instance);
+ available.add(instance);
+ }
+
+ @Override
+ public synchronized String toString() {
+ return String.format("Pool available=%d inUse=%d", available.size(), inUse.size());
+ }
+}
+
+public class OliphauntPool extends ObjectPool {
+
+ @Override
+ protected Oliphaunt create() {
+ return new Oliphaunt();
+ }
+}
+```
+
+And finally here's how we utilize the pool.
+
+```java
+ var pool = new OliphauntPool();
+ var oliphaunt1 = pool.checkOut();
+ var oliphaunt2 = pool.checkOut();
+ var oliphaunt3 = pool.checkOut();
+ pool.checkIn(oliphaunt1);
+ pool.checkIn(oliphaunt2);
+ var oliphaunt4 = pool.checkOut();
+ var oliphaunt5 = pool.checkOut();
+```
+
## Class diagram

diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/App.java b/object-pool/src/main/java/com/iluwatar/object/pool/App.java
index 3c1774fac..cbfc7dea5 100644
--- a/object-pool/src/main/java/com/iluwatar/object/pool/App.java
+++ b/object-pool/src/main/java/com/iluwatar/object/pool/App.java
@@ -54,14 +54,14 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- OliphauntPool pool = new OliphauntPool();
+ var pool = new OliphauntPool();
LOGGER.info(pool.toString());
- Oliphaunt oliphaunt1 = pool.checkOut();
+ var oliphaunt1 = pool.checkOut();
LOGGER.info("Checked out {}", oliphaunt1);
LOGGER.info(pool.toString());
- Oliphaunt oliphaunt2 = pool.checkOut();
+ var oliphaunt2 = pool.checkOut();
LOGGER.info("Checked out {}", oliphaunt2);
- Oliphaunt oliphaunt3 = pool.checkOut();
+ var oliphaunt3 = pool.checkOut();
LOGGER.info("Checked out {}", oliphaunt3);
LOGGER.info(pool.toString());
LOGGER.info("Checking in {}", oliphaunt1);
@@ -69,9 +69,9 @@ public class App {
LOGGER.info("Checking in {}", oliphaunt2);
pool.checkIn(oliphaunt2);
LOGGER.info(pool.toString());
- Oliphaunt oliphaunt4 = pool.checkOut();
+ var oliphaunt4 = pool.checkOut();
LOGGER.info("Checked out {}", oliphaunt4);
- Oliphaunt oliphaunt5 = pool.checkOut();
+ var oliphaunt5 = pool.checkOut();
LOGGER.info("Checked out {}", oliphaunt5);
LOGGER.info(pool.toString());
}
diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java
index 37009d44b..43ac5d873 100644
--- a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java
+++ b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java
@@ -33,8 +33,8 @@ import java.util.Set;
*/
public abstract class ObjectPool {
- private Set available = new HashSet<>();
- private Set inUse = new HashSet<>();
+ private final Set available = new HashSet<>();
+ private final Set inUse = new HashSet<>();
protected abstract T create();
@@ -45,7 +45,7 @@ public abstract class ObjectPool {
if (available.isEmpty()) {
available.add(create());
}
- T instance = available.iterator().next();
+ var instance = available.iterator().next();
available.remove(instance);
inUse.add(instance);
return instance;
diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java b/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java
index 42db07158..09dedbab0 100644
--- a/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java
+++ b/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class Oliphaunt {
- private static AtomicInteger counter = new AtomicInteger(0);
+ private static final AtomicInteger counter = new AtomicInteger(0);
private final int id;
diff --git a/object-pool/src/test/java/com/iluwatar/object/pool/OliphauntPoolTest.java b/object-pool/src/test/java/com/iluwatar/object/pool/OliphauntPoolTest.java
index d4ca42948..880009f86 100644
--- a/object-pool/src/test/java/com/iluwatar/object/pool/OliphauntPoolTest.java
+++ b/object-pool/src/test/java/com/iluwatar/object/pool/OliphauntPoolTest.java
@@ -44,17 +44,17 @@ public class OliphauntPoolTest {
@Test
public void testSubsequentCheckinCheckout() {
assertTimeout(ofMillis(5000), () -> {
- final OliphauntPool pool = new OliphauntPool();
+ final var pool = new OliphauntPool();
assertEquals("Pool available=0 inUse=0", pool.toString());
- final Oliphaunt expectedOliphaunt = pool.checkOut();
+ final var expectedOliphaunt = pool.checkOut();
assertEquals("Pool available=0 inUse=1", pool.toString());
pool.checkIn(expectedOliphaunt);
assertEquals("Pool available=1 inUse=0", pool.toString());
for (int i = 0; i < 100; i++) {
- final Oliphaunt oliphaunt = pool.checkOut();
+ final var oliphaunt = pool.checkOut();
assertEquals("Pool available=0 inUse=1", pool.toString());
assertSame(expectedOliphaunt, oliphaunt);
assertEquals(expectedOliphaunt.getId(), oliphaunt.getId());
@@ -73,13 +73,13 @@ public class OliphauntPoolTest {
@Test
public void testConcurrentCheckinCheckout() {
assertTimeout(ofMillis(5000), () -> {
- final OliphauntPool pool = new OliphauntPool();
+ final var pool = new OliphauntPool();
assertEquals(pool.toString(), "Pool available=0 inUse=0");
- final Oliphaunt firstOliphaunt = pool.checkOut();
+ final var firstOliphaunt = pool.checkOut();
assertEquals(pool.toString(), "Pool available=0 inUse=1");
- final Oliphaunt secondOliphaunt = pool.checkOut();
+ final var secondOliphaunt = pool.checkOut();
assertEquals(pool.toString(), "Pool available=0 inUse=2");
assertNotSame(firstOliphaunt, secondOliphaunt);
@@ -89,7 +89,7 @@ public class OliphauntPoolTest {
pool.checkIn(secondOliphaunt);
assertEquals(pool.toString(), "Pool available=1 inUse=1");
- final Oliphaunt oliphaunt3 = pool.checkOut();
+ final var oliphaunt3 = pool.checkOut();
assertEquals(pool.toString(), "Pool available=0 inUse=2");
assertSame(secondOliphaunt, oliphaunt3);
@@ -97,7 +97,7 @@ public class OliphauntPoolTest {
pool.checkIn(firstOliphaunt);
assertEquals(pool.toString(), "Pool available=1 inUse=1");
- final Oliphaunt oliphaunt4 = pool.checkOut();
+ final var oliphaunt4 = pool.checkOut();
assertEquals(pool.toString(), "Pool available=0 inUse=2");
assertSame(firstOliphaunt, oliphaunt4);
@@ -110,7 +110,7 @@ public class OliphauntPoolTest {
// The order of the returned instances is not determined, so just put them in a list
// and verify if both expected instances are in there.
- final List oliphaunts = List.of(pool.checkOut(), pool.checkOut());
+ final var oliphaunts = List.of(pool.checkOut(), pool.checkOut());
assertEquals(pool.toString(), "Pool available=0 inUse=2");
assertTrue(oliphaunts.contains(firstOliphaunt));
assertTrue(oliphaunts.contains(secondOliphaunt));
diff --git a/observer/README.md b/observer/README.md
index 7b31c7450..e329a657c 100644
--- a/observer/README.md
+++ b/observer/README.md
@@ -13,9 +13,149 @@ tags:
Dependents, Publish-Subscribe
## Intent
-Define a one-to-many dependency between objects so that when one
-object changes state, all its dependents are notified and updated
-automatically.
+Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified
+and updated automatically.
+
+## Explanation
+
+Real world example
+
+> In a land far away lives the races of hobbits and orcs. Both of them are mostly outdoors so they closely follow the changes in weather. One could say that they are constantly observing the weather.
+
+In plain words
+
+> Register as an observer to receive state changes in the object.
+
+Wikipedia says
+
+> The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
+
+**Programmatic Example**
+
+Let's first introduce the weather observer interface and our races, orcs and hobbits.
+
+```java
+public interface WeatherObserver {
+
+ void update(WeatherType currentWeather);
+}
+
+public class Orcs implements WeatherObserver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class);
+
+ @Override
+ public void update(WeatherType currentWeather) {
+ switch (currentWeather) {
+ case COLD:
+ LOGGER.info("The orcs are freezing cold.");
+ break;
+ case RAINY:
+ LOGGER.info("The orcs are dripping wet.");
+ break;
+ case SUNNY:
+ LOGGER.info("The sun hurts the orcs' eyes.");
+ break;
+ case WINDY:
+ LOGGER.info("The orc smell almost vanishes in the wind.");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+public class Hobbits implements WeatherObserver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class);
+
+ @Override
+ public void update(WeatherType currentWeather) {
+ switch (currentWeather) {
+ case COLD:
+ LOGGER.info("The hobbits are shivering in the cold weather.");
+ break;
+ case RAINY:
+ LOGGER.info("The hobbits look for cover from the rain.");
+ break;
+ case SUNNY:
+ LOGGER.info("The happy hobbits bade in the warm sun.");
+ break;
+ case WINDY:
+ LOGGER.info("The hobbits hold their hats tightly in the windy weather.");
+ break;
+ default:
+ break;
+ }
+ }
+}
+```
+
+Then here's the weather that is constantly changing.
+
+```java
+public class Weather {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class);
+
+ private WeatherType currentWeather;
+ private final List observers;
+
+ public Weather() {
+ observers = new ArrayList<>();
+ currentWeather = WeatherType.SUNNY;
+ }
+
+ public void addObserver(WeatherObserver obs) {
+ observers.add(obs);
+ }
+
+ public void removeObserver(WeatherObserver obs) {
+ observers.remove(obs);
+ }
+
+ /**
+ * Makes time pass for weather.
+ */
+ public void timePasses() {
+ var enumValues = WeatherType.values();
+ currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
+ LOGGER.info("The weather changed to {}.", currentWeather);
+ notifyObservers();
+ }
+
+ private void notifyObservers() {
+ for (var obs : observers) {
+ obs.update(currentWeather);
+ }
+ }
+}
+```
+
+Here's the full example in action.
+
+```java
+ var weather = new Weather();
+ weather.addObserver(new Orcs());
+ weather.addObserver(new Hobbits());
+
+ weather.timePasses();
+ // The weather changed to rainy.
+ // The orcs are dripping wet.
+ // The hobbits look for cover from the rain.
+ weather.timePasses();
+ // The weather changed to windy.
+ // The orc smell almost vanishes in the wind.
+ // The hobbits hold their hats tightly in the windy weather.
+ weather.timePasses();
+ // The weather changed to cold.
+ // The orcs are freezing cold.
+ // The hobbits are shivering in the cold weather.
+ weather.timePasses();
+ // The weather changed to sunny.
+ // The sun hurts the orcs' eyes.
+ // The happy hobbits bade in the warm sun.
+```
## Class diagram

@@ -40,5 +180,7 @@ Use the Observer pattern in any of the following situations
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
-* [Java Generics and Collections](http://www.amazon.com/Java-Generics-Collections-Maurice-Naftalin/dp/0596527756/)
+* [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)
+* [Java Generics and Collections](https://www.amazon.com/gp/product/0596527756/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596527756&linkCode=as2&tag=javadesignpat-20&linkId=246e5e2c26fe1c3ada6a70b15afcb195)
+* [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)
diff --git a/observer/src/main/java/com/iluwatar/observer/App.java b/observer/src/main/java/com/iluwatar/observer/App.java
index d0994b65c..b8fd01f32 100644
--- a/observer/src/main/java/com/iluwatar/observer/App.java
+++ b/observer/src/main/java/com/iluwatar/observer/App.java
@@ -51,7 +51,7 @@ public class App {
*/
public static void main(String[] args) {
- Weather weather = new Weather();
+ var weather = new Weather();
weather.addObserver(new Orcs());
weather.addObserver(new Hobbits());
@@ -62,7 +62,7 @@ public class App {
// Generic observer inspired by Java Generics and Collection by Naftalin & Wadler
LOGGER.info("--Running generic version--");
- GWeather genericWeather = new GWeather();
+ var genericWeather = new GWeather();
genericWeather.addObserver(new GOrcs());
genericWeather.addObserver(new GHobbits());
diff --git a/observer/src/main/java/com/iluwatar/observer/Weather.java b/observer/src/main/java/com/iluwatar/observer/Weather.java
index 3369e8f63..a0d80d6bc 100644
--- a/observer/src/main/java/com/iluwatar/observer/Weather.java
+++ b/observer/src/main/java/com/iluwatar/observer/Weather.java
@@ -37,7 +37,7 @@ public class Weather {
private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class);
private WeatherType currentWeather;
- private List observers;
+ private final List observers;
public Weather() {
observers = new ArrayList<>();
@@ -56,14 +56,14 @@ public class Weather {
* Makes time pass for weather.
*/
public void timePasses() {
- WeatherType[] enumValues = WeatherType.values();
+ var enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
LOGGER.info("The weather changed to {}.", currentWeather);
notifyObservers();
}
private void notifyObservers() {
- for (WeatherObserver obs : observers) {
+ for (var obs : observers) {
obs.update(currentWeather);
}
}
diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java b/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java
index 13ba25534..c8f7bc701 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java
@@ -44,7 +44,7 @@ public class GWeather extends Observable {
* Makes time pass for weather.
*/
public void timePasses() {
- WeatherType[] enumValues = WeatherType.values();
+ var enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
LOGGER.info("The weather changed to {}.", currentWeather);
notifyObservers(currentWeather);
diff --git a/observer/src/main/java/com/iluwatar/observer/generic/Observable.java b/observer/src/main/java/com/iluwatar/observer/generic/Observable.java
index 29d350154..fbb078941 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/Observable.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/Observable.java
@@ -54,7 +54,7 @@ public abstract class Observable
, O extends Observ
*/
@SuppressWarnings("unchecked")
public void notifyObservers(A argument) {
- for (O observer : observers) {
+ for (var observer : observers) {
observer.update((S) this, argument);
}
}
diff --git a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java
index fbaceb02b..7f9b3a790 100644
--- a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java
@@ -80,7 +80,7 @@ public abstract class WeatherObserverTest {
@ParameterizedTest
@MethodSource("dataProvider")
public void testObserver(WeatherType weather, String response) {
- final O observer = this.factory.get();
+ final var observer = this.factory.get();
assertEquals(0, appender.getLogSize());
observer.update(weather);
diff --git a/observer/src/test/java/com/iluwatar/observer/WeatherTest.java b/observer/src/test/java/com/iluwatar/observer/WeatherTest.java
index c00357153..90e090c8d 100644
--- a/observer/src/test/java/com/iluwatar/observer/WeatherTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/WeatherTest.java
@@ -61,9 +61,9 @@ public class WeatherTest {
*/
@Test
public void testAddRemoveObserver() {
- final WeatherObserver observer = mock(WeatherObserver.class);
+ final var observer = mock(WeatherObserver.class);
- final Weather weather = new Weather();
+ final var weather = new Weather();
weather.addObserver(observer);
verifyZeroInteractions(observer);
@@ -84,13 +84,13 @@ public class WeatherTest {
*/
@Test
public void testTimePasses() {
- final WeatherObserver observer = mock(WeatherObserver.class);
- final Weather weather = new Weather();
+ final var observer = mock(WeatherObserver.class);
+ final var weather = new Weather();
weather.addObserver(observer);
- final InOrder inOrder = inOrder(observer);
- final WeatherType[] weatherTypes = WeatherType.values();
- for (int i = 1; i < 20; i++) {
+ final var inOrder = inOrder(observer);
+ final var weatherTypes = WeatherType.values();
+ for (var i = 1; i < 20; i++) {
weather.timePasses();
inOrder.verify(observer).update(weatherTypes[i % weatherTypes.length]);
}
diff --git a/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java b/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java
index 7450a00b9..e45dd5c28 100644
--- a/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java
@@ -59,9 +59,9 @@ public class GWeatherTest {
*/
@Test
public void testAddRemoveObserver() {
- final Race observer = mock(Race.class);
+ final var observer = mock(Race.class);
- final GWeather weather = new GWeather();
+ final var weather = new GWeather();
weather.addObserver(observer);
verifyZeroInteractions(observer);
@@ -82,13 +82,13 @@ public class GWeatherTest {
*/
@Test
public void testTimePasses() {
- final Race observer = mock(Race.class);
- final GWeather weather = new GWeather();
+ final var observer = mock(Race.class);
+ final var weather = new GWeather();
weather.addObserver(observer);
- final InOrder inOrder = inOrder(observer);
- final WeatherType[] weatherTypes = WeatherType.values();
- for (int i = 1; i < 20; i++) {
+ final var inOrder = inOrder(observer);
+ final var weatherTypes = WeatherType.values();
+ for (var i = 1; i < 20; i++) {
weather.timePasses();
inOrder.verify(observer).update(weather, weatherTypes[i % weatherTypes.length]);
}
diff --git a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java
index b5ef7ec0d..f358c88e1 100644
--- a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java
@@ -79,7 +79,7 @@ public abstract class ObserverTest> {
@ParameterizedTest
@MethodSource("dataProvider")
public void testObserver(WeatherType weather, String response) {
- final O observer = this.factory.get();
+ final var observer = this.factory.get();
assertEquals(0, appender.getLogSize());
observer.update(null, weather);
diff --git a/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java
index b3d2bf1bc..132216d19 100644
--- a/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java
+++ b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java
@@ -35,7 +35,7 @@ import java.util.List;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java b/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
index 779458e05..22bc8a5fb 100644
--- a/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
+++ b/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumListPageTest {
- private AlbumListPage albumListPage = new AlbumListPage(new WebClient());
+ private final AlbumListPage albumListPage = new AlbumListPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java b/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
index 601093343..68c836bd3 100644
--- a/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
+++ b/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumPageTest {
- private AlbumPage albumPage = new AlbumPage(new WebClient());
+ private final AlbumPage albumPage = new AlbumPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java b/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
index 022f736ca..460bdcf96 100644
--- a/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
+++ b/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class LoginPageTest {
- private LoginPage loginPage = new LoginPage(new WebClient());
+ private final LoginPage loginPage = new LoginPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
index d1b450a24..1acdd5ba5 100644
--- a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
+++ b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumListPageTest {
- private AlbumListPage albumListPage = new AlbumListPage(new WebClient());
+ private final AlbumListPage albumListPage = new AlbumListPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
index 8e694a592..ecde999c3 100644
--- a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
+++ b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumPageTest {
- private AlbumPage albumPage = new AlbumPage(new WebClient());
+ private final AlbumPage albumPage = new AlbumPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
index 89668882d..429b7fcc5 100644
--- a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
+++ b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class LoginPageTest {
- private LoginPage loginPage = new LoginPage(new WebClient());
+ private final LoginPage loginPage = new LoginPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java b/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
index a61a3c429..11a4f23ca 100644
--- a/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
+++ b/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
@@ -30,8 +30,8 @@ import java.util.Map;
* has all video details.
*/
public class VideoResource {
- private FieldJsonMapper fieldJsonMapper;
- private Map videos;
+ private final FieldJsonMapper fieldJsonMapper;
+ private final Map videos;
/**
* Constructor.
diff --git a/pipeline/README.md b/pipeline/README.md
index bc8f9399a..fd03cd7b9 100644
--- a/pipeline/README.md
+++ b/pipeline/README.md
@@ -9,7 +9,83 @@ tags:
---
## Intent
-Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be used by the next stages.
+Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be
+used by the next stages.
+
+## Explanation
+
+The Pipeline pattern uses ordered stages to process a sequence of input values. Each implemented task is represented by
+a stage of the pipeline. You can think of pipelines as similar to assembly lines in a factory, where each item in the
+assembly line is constructed in stages. The partially assembled item is passed from one assembly stage to another. The
+outputs of the assembly line occur in the same order as that of the inputs.
+
+Real world example
+
+> Suppose we wanted to pass through a string to a series of filtering stages and convert it as a char array on the last stage.
+
+In plain words
+
+> Pipeline pattern is an assembly line where partial results are passed from one stage to another.
+
+Wikipedia says
+
+> In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.
+
+**Programmatic Example**
+
+The stages of our pipeline are called `Handler`s.
+
+```java
+interface Handler {
+ O process(I input);
+}
+```
+
+In our string processing example we have 3 different concrete `Handler`s.
+
+```java
+class RemoveAlphabetsHandler implements Handler {
+ ...
+}
+
+class RemoveDigitsHandler implements Handler {
+ ...
+}
+
+class ConvertToCharArrayHandler implements Handler {
+ ...
+}
+```
+
+Here is the `Pipeline` that will gather and execute the handlers one by one.
+
+```java
+class Pipeline {
+
+ private final Handler currentHandler;
+
+ Pipeline(Handler currentHandler) {
+ this.currentHandler = currentHandler;
+ }
+
+ Pipeline addHandler(Handler newHandler) {
+ return new Pipeline<>(input -> newHandler.process(currentHandler.process(input)));
+ }
+
+ O execute(I input) {
+ return currentHandler.process(input);
+ }
+}
+```
+
+And here's the `Pipeline` in action processing the string.
+
+```java
+ var filters = new Pipeline<>(new RemoveAlphabetsHandler())
+ .addHandler(new RemoveDigitsHandler())
+ .addHandler(new ConvertToCharArrayHandler());
+ filters.execute("GoYankees123!");
+```
## Class diagram

@@ -21,16 +97,16 @@ Use the Pipeline pattern when you want to
* Add readability to complex sequence of operations by providing a fluent builder as an interface
* Improve testability of code since stages will most likely be doing a single thing, complying to the [Single Responsibility Principle (SRP)](https://java-design-patterns.com/principles/#single-responsibility-principle)
-## Typical Use Case
-
-* Implement stages and execute them in an ordered manner
-
-## Real world examples
+## Known uses
* [java.util.Stream](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html)
* [Maven Build Lifecycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
* [Functional Java](https://github.com/functionaljava/functionaljava)
+## Related patterns
+
+* [Chain of Responsibility](https://java-design-patterns.com/patterns/chain/)
+
## Credits
* [The Pipeline Pattern — for fun and profit](https://medium.com/@aaronweatherall/the-pipeline-pattern-for-fun-and-profit-9b5f43a98130)
diff --git a/pipeline/src/main/java/com/iluwatar/pipeline/App.java b/pipeline/src/main/java/com/iluwatar/pipeline/App.java
index 1b1e443e6..cfbcbafc2 100644
--- a/pipeline/src/main/java/com/iluwatar/pipeline/App.java
+++ b/pipeline/src/main/java/com/iluwatar/pipeline/App.java
@@ -59,8 +59,9 @@ public class App {
then is expected to receive an input of char[] array since that is the type being returned
by the previous handler, ConvertToCharArrayHandler.
*/
- new Pipeline<>(new RemoveAlphabetsHandler())
+ var filters = new Pipeline<>(new RemoveAlphabetsHandler())
.addHandler(new RemoveDigitsHandler())
.addHandler(new ConvertToCharArrayHandler());
+ filters.execute("GoYankees123!");
}
}
diff --git a/poison-pill/README.md b/poison-pill/README.md
index 7fd152891..a6cd2fe80 100644
--- a/poison-pill/README.md
+++ b/poison-pill/README.md
@@ -10,8 +10,250 @@ tags:
---
## Intent
-Poison Pill is known predefined data item that allows to provide
-graceful shutdown for separate distributed consumption process.
+Poison Pill is known predefined data item that allows to provide graceful shutdown for separate distributed consumption
+process.
+
+## Explanation
+
+Real world example
+
+> Let's think about a message queue with one producer and one consumer. The producer keeps pushing new messages in the queue and the consumer keeps reading them. Finally when it's time to gracefully shut down the producer sends the poison pill message.
+
+In plain words
+
+> Poison Pill is a known message structure that ends the message exchange.
+
+**Programmatic Example**
+
+Let's define the message structure first.
+
+```java
+public interface Message {
+
+ Message POISON_PILL = new Message() {
+
+ @Override
+ public void addHeader(Headers header, String value) {
+ throw poison();
+ }
+
+ @Override
+ public String getHeader(Headers header) {
+ throw poison();
+ }
+
+ @Override
+ public Map getHeaders() {
+ throw poison();
+ }
+
+ @Override
+ public void setBody(String body) {
+ throw poison();
+ }
+
+ @Override
+ public String getBody() {
+ throw poison();
+ }
+
+ private RuntimeException poison() {
+ return new UnsupportedOperationException("Poison");
+ }
+
+ };
+
+ enum Headers {
+ DATE, SENDER
+ }
+
+ void addHeader(Headers header, String value);
+
+ String getHeader(Headers header);
+
+ Map getHeaders();
+
+ void setBody(String body);
+
+ String getBody();
+}
+
+public class SimpleMessage implements Message {
+
+ private final Map headers = new HashMap<>();
+ private String body;
+
+ @Override
+ public void addHeader(Headers header, String value) {
+ headers.put(header, value);
+ }
+
+ @Override
+ public String getHeader(Headers header) {
+ return headers.get(header);
+ }
+
+ @Override
+ public Map getHeaders() {
+ return Collections.unmodifiableMap(headers);
+ }
+
+ @Override
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ @Override
+ public String getBody() {
+ return body;
+ }
+}
+```
+
+Next we define the types related to the message queue.
+
+```java
+public interface MqPublishPoint {
+
+ void put(Message msg) throws InterruptedException;
+}
+
+public interface MqSubscribePoint {
+
+ Message take() throws InterruptedException;
+}
+
+public interface MessageQueue extends MqPublishPoint, MqSubscribePoint {
+}
+
+public class SimpleMessageQueue implements MessageQueue {
+
+ private final BlockingQueue queue;
+
+ public SimpleMessageQueue(int bound) {
+ queue = new ArrayBlockingQueue<>(bound);
+ }
+
+ @Override
+ public void put(Message msg) throws InterruptedException {
+ queue.put(msg);
+ }
+
+ @Override
+ public Message take() throws InterruptedException {
+ return queue.take();
+ }
+}
+```
+
+Now we need to create the message producer and consumer.
+
+```java
+public class Producer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
+
+ private final MqPublishPoint queue;
+ private final String name;
+ private boolean isStopped;
+
+ /**
+ * Constructor.
+ */
+ public Producer(String name, MqPublishPoint queue) {
+ this.name = name;
+ this.queue = queue;
+ this.isStopped = false;
+ }
+
+ /**
+ * Send message to queue.
+ */
+ public void send(String body) {
+ if (isStopped) {
+ throw new IllegalStateException(String.format(
+ "Producer %s was stopped and fail to deliver requested message [%s].", body, name));
+ }
+ var msg = new SimpleMessage();
+ msg.addHeader(Headers.DATE, new Date().toString());
+ msg.addHeader(Headers.SENDER, name);
+ msg.setBody(body);
+
+ try {
+ queue.put(msg);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ }
+ }
+
+ /**
+ * Stop system by sending poison pill.
+ */
+ public void stop() {
+ isStopped = true;
+ try {
+ queue.put(Message.POISON_PILL);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ }
+ }
+}
+
+public class Consumer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class);
+
+ private final MqSubscribePoint queue;
+ private final String name;
+
+ public Consumer(String name, MqSubscribePoint queue) {
+ this.name = name;
+ this.queue = queue;
+ }
+
+ /**
+ * Consume message.
+ */
+ public void consume() {
+ while (true) {
+ try {
+ var msg = queue.take();
+ if (Message.POISON_PILL.equals(msg)) {
+ LOGGER.info("Consumer {} receive request to terminate.", name);
+ break;
+ }
+ var sender = msg.getHeader(Headers.SENDER);
+ var body = msg.getBody();
+ LOGGER.info("Message [{}] from [{}] received by [{}]", body, sender, name);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ return;
+ }
+ }
+ }
+}
+```
+
+Finally we are ready to present the whole example in action.
+
+```java
+ var queue = new SimpleMessageQueue(10000);
+
+ final var producer = new Producer("PRODUCER_1", queue);
+ final var consumer = new Consumer("CONSUMER_1", queue);
+
+ new Thread(consumer::consume).start();
+
+ new Thread(() -> {
+ producer.send("hand shake");
+ producer.send("some very important information");
+ producer.send("bye!");
+ producer.stop();
+ }).start();
+```
## Class diagram

diff --git a/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java b/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java
index 8a7af515f..70d116c9f 100644
--- a/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java
+++ b/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class SimpleMessage implements Message {
- private Map headers = new HashMap<>();
+ private final Map headers = new HashMap<>();
private String body;
@Override
diff --git a/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java b/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java
index 100565fbc..8365fca17 100644
--- a/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java
+++ b/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java
@@ -92,7 +92,7 @@ public class ConsumerTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/pom.xml b/pom.xml
index b81cfe8d4..3b4f05b37 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,12 @@
1.3.2
1.19.0
1.4.8
+
+ https://sonarcloud.io
+ iluwatar
+ iluwatar_java-design-patterns
+ ${project.artifactId}
+ Java Design Patterns
abstract-factory
@@ -184,6 +190,8 @@
combinator
update-method
leader-followers
+ strangler
+ arrange-act-assert
@@ -367,10 +375,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M3
-
- -Xmx1024M ${argLine}
-
+ 3.0.0-M5
org.springframework.boot
@@ -399,6 +404,11 @@
+
+ org.sonarsource.scanner.maven
+ sonar-maven-plugin
+ 3.7.0.1746
+
@@ -461,7 +471,7 @@
true
- ${projectRoot}${file.separator}license-plugin-header-style.xml
+ license-plugin-header-style.xml
SLASHSTAR_CUSTOM_STYLE
@@ -527,14 +537,4 @@
-
-
-
- org.apache.maven.plugins
- maven-jxr-plugin
- 3.0.0
-
-
-
-
-
\ No newline at end of file
+
diff --git a/priority-queue/README.md b/priority-queue/README.md
index c8d1f7773..924d7169f 100644
--- a/priority-queue/README.md
+++ b/priority-queue/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/priority-queue/
categories: Behavioral
tags:
- Decoupling
+ - Cloud distributed
---
## Intent
@@ -18,12 +19,11 @@ Applications may delegate specific tasks to other services; for example, to perf

## Applicability
-Use the Property pattern when
+Use the Priority Queue pattern when
* The system must handle multiple tasks that might have different priorities.
* Different users or tenants should be served with different priority..
-## Real world examples
+## Credits
-* [ Priority Queue Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589794(v=pandp.10))
-Microsoft Azure does not provide a queuing mechanism that natively support automatic prioritization of messages through sorting. However, it does provide Azure Service Bus topics and subscriptions, which support a queuing mechanism that provides message filtering, together with a wide range of flexible capabilities that make it ideal for use in almost all priority queue implementations.
+* [Priority Queue pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/priority-queue)
diff --git a/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java b/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java
index 695424695..d312cd34a 100644
--- a/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java
+++ b/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java
@@ -1,50 +1,50 @@
-/*
- * 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.privateclassdata;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Immutable stew class, protected with Private Class Data pattern.
- */
-public class ImmutableStew {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ImmutableStew.class);
-
- private StewData data;
-
- public ImmutableStew(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
- data = new StewData(numPotatoes, numCarrots, numMeat, numPeppers);
- }
-
- /**
- * Mix the stew.
- */
- public void mix() {
- LOGGER
- .info("Mixing the immutable stew we find: {} potatoes, {} carrots, {} meat and {} peppers",
- data.getNumPotatoes(), data.getNumCarrots(), data.getNumMeat(), data.getNumPeppers());
- }
-}
+/*
+ * 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.privateclassdata;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Immutable stew class, protected with Private Class Data pattern.
+ */
+public class ImmutableStew {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ImmutableStew.class);
+
+ private final StewData data;
+
+ public ImmutableStew(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
+ data = new StewData(numPotatoes, numCarrots, numMeat, numPeppers);
+ }
+
+ /**
+ * Mix the stew.
+ */
+ public void mix() {
+ LOGGER
+ .info("Mixing the immutable stew we find: {} potatoes, {} carrots, {} meat and {} peppers",
+ data.getNumPotatoes(), data.getNumCarrots(), data.getNumMeat(), data.getNumPeppers());
+ }
+}
diff --git a/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java b/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java
index bcdaba3e9..1b0fd269b 100644
--- a/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java
+++ b/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java
@@ -1,61 +1,61 @@
-/*
- * 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.privateclassdata;
-
-/**
- * Stew ingredients.
- */
-public class StewData {
-
- private int numPotatoes;
- private int numCarrots;
- private int numMeat;
- private int numPeppers;
-
- /**
- * Constructor.
- */
- public StewData(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
- this.numPotatoes = numPotatoes;
- this.numCarrots = numCarrots;
- this.numMeat = numMeat;
- this.numPeppers = numPeppers;
- }
-
- public int getNumPotatoes() {
- return numPotatoes;
- }
-
- public int getNumCarrots() {
- return numCarrots;
- }
-
- public int getNumMeat() {
- return numMeat;
- }
-
- public int getNumPeppers() {
- return numPeppers;
- }
-}
+/*
+ * 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.privateclassdata;
+
+/**
+ * Stew ingredients.
+ */
+public class StewData {
+
+ private final int numPotatoes;
+ private final int numCarrots;
+ private final int numMeat;
+ private final int numPeppers;
+
+ /**
+ * Constructor.
+ */
+ public StewData(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
+ this.numPotatoes = numPotatoes;
+ this.numCarrots = numCarrots;
+ this.numMeat = numMeat;
+ this.numPeppers = numPeppers;
+ }
+
+ public int getNumPotatoes() {
+ return numPotatoes;
+ }
+
+ public int getNumCarrots() {
+ return numCarrots;
+ }
+
+ public int getNumMeat() {
+ return numMeat;
+ }
+
+ public int getNumPeppers() {
+ return numPeppers;
+ }
+}
diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java
index 6fbe638ae..bbcbc8021 100644
--- a/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java
+++ b/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java
@@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java
index 6991ec4d1..89f692282 100644
--- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java
+++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java
@@ -28,9 +28,9 @@ package com.iluwatar.producer.consumer;
*/
public class Item {
- private String producer;
+ private final String producer;
- private int id;
+ private final int id;
public Item(String producer, int id) {
this.id = id;
diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java
index 674fb069a..118e3265d 100644
--- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java
+++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java
@@ -31,7 +31,7 @@ import java.util.concurrent.LinkedBlockingQueue;
*/
public class ItemQueue {
- private BlockingQueue- queue;
+ private final BlockingQueue
- queue;
public ItemQueue() {
diff --git a/promise/README.md b/promise/README.md
index cf3d96c88..993d29a9f 100644
--- a/promise/README.md
+++ b/promise/README.md
@@ -9,18 +9,277 @@ tags:
---
## Also known as
+
CompletableFuture
## Intent
-A Promise represents a proxy for a value not necessarily known when the promise is created. It
-allows you to associate dependent promises to an asynchronous action's eventual success value or
-failure reason. Promises are a way to write async code that still appears as though it is executing
-in a synchronous way.
+
+A Promise represents a proxy for a value not necessarily known when the promise is created. It allows you to associate
+dependent promises to an asynchronous action's eventual success value or failure reason. Promises are a way to write
+async code that still appears as though it is executing in a synchronous way.
+
+## Explanation
+
+The Promise object is used for asynchronous computations. A Promise represents an operation that hasn't completed yet,
+but is expected in the future.
+
+Promises provide a few advantages over callback objects:
+ * Functional composition and error handling
+ * Prevents callback hell and provides callback aggregation
+
+Real world example
+
+> We are developing a software solution that downloads files and calculates the number of lines and character
+frequencies in those files. Promise is an ideal solution to make the code concise and easy to understand.
+
+In plain words
+
+> Promise is a placeholder for an asynchronous operation that is ongoing.
+
+Wikipedia says
+
+> In computer science, future, promise, delay, and deferred refer to constructs used for synchronizing program
+execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is
+initially unknown, usually because the computation of its value is not yet complete.
+
+**Programmatic Example**
+
+In the example a file is downloaded and its line count is calculated. The calculated line count is then consumed and
+printed on console.
+
+Let's first introduce a support class we need for implementation. Here's `PromiseSupport`.
+
+```java
+class PromiseSupport implements Future {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PromiseSupport.class);
+
+ private static final int RUNNING = 1;
+ private static final int FAILED = 2;
+ private static final int COMPLETED = 3;
+
+ private final Object lock;
+
+ private volatile int state = RUNNING;
+ private T value;
+ private Exception exception;
+
+ PromiseSupport() {
+ this.lock = new Object();
+ }
+
+ void fulfill(T value) {
+ this.value = value;
+ this.state = COMPLETED;
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ void fulfillExceptionally(Exception exception) {
+ this.exception = exception;
+ this.state = FAILED;
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return state > RUNNING;
+ }
+
+ @Override
+ public T get() throws InterruptedException, ExecutionException {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ lock.wait();
+ }
+ }
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
+ }
+
+ @Override
+ public T get(long timeout, TimeUnit unit) throws ExecutionException {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ try {
+ lock.wait(unit.toMillis(timeout));
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted!", e);
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
+ }
+}
+```
+
+With `PromiseSupport` in place we can implement the actual `Promise`.
+
+```java
+public class Promise extends PromiseSupport {
+
+ private Runnable fulfillmentAction;
+ private Consumer super Throwable> exceptionHandler;
+
+ public Promise() {
+ }
+
+ @Override
+ public void fulfill(T value) {
+ super.fulfill(value);
+ postFulfillment();
+ }
+
+ @Override
+ public void fulfillExceptionally(Exception exception) {
+ super.fulfillExceptionally(exception);
+ handleException(exception);
+ postFulfillment();
+ }
+
+ private void handleException(Exception exception) {
+ if (exceptionHandler == null) {
+ return;
+ }
+ exceptionHandler.accept(exception);
+ }
+
+ private void postFulfillment() {
+ if (fulfillmentAction == null) {
+ return;
+ }
+ fulfillmentAction.run();
+ }
+
+ public Promise fulfillInAsync(final Callable task, Executor executor) {
+ executor.execute(() -> {
+ try {
+ fulfill(task.call());
+ } catch (Exception ex) {
+ fulfillExceptionally(ex);
+ }
+ });
+ return this;
+ }
+
+ public Promise thenAccept(Consumer super T> action) {
+ var dest = new Promise();
+ fulfillmentAction = new ConsumeAction(this, dest, action);
+ return dest;
+ }
+
+ public Promise onError(Consumer super Throwable> exceptionHandler) {
+ this.exceptionHandler = exceptionHandler;
+ return this;
+ }
+
+ public Promise thenApply(Function super T, V> func) {
+ Promise dest = new Promise<>();
+ fulfillmentAction = new TransformAction(this, dest, func);
+ return dest;
+ }
+
+ private class ConsumeAction implements Runnable {
+
+ private final Promise src;
+ private final Promise dest;
+ private final Consumer super T> action;
+
+ private ConsumeAction(Promise src, Promise dest, Consumer super T> action) {
+ this.src = src;
+ this.dest = dest;
+ this.action = action;
+ }
+
+ @Override
+ public void run() {
+ try {
+ action.accept(src.get());
+ dest.fulfill(null);
+ } catch (Throwable throwable) {
+ dest.fulfillExceptionally((Exception) throwable.getCause());
+ }
+ }
+ }
+
+ private class TransformAction implements Runnable {
+
+ private final Promise src;
+ private final Promise dest;
+ private final Function super T, V> func;
+
+ private TransformAction(Promise src, Promise dest, Function super T, V> func) {
+ this.src = src;
+ this.dest = dest;
+ this.func = func;
+ }
+
+ @Override
+ public void run() {
+ try {
+ dest.fulfill(func.apply(src.get()));
+ } catch (Throwable throwable) {
+ dest.fulfillExceptionally((Exception) throwable.getCause());
+ }
+ }
+ }
+}
+```
+
+Now we can show the full example in action. Here's how to download and count the number of lines in a file using
+`Promise`.
+
+```java
+ countLines().thenAccept(
+ count -> {
+ LOGGER.info("Line count is: {}", count);
+ taskCompleted();
+ }
+ );
+
+ private Promise countLines() {
+ return download(DEFAULT_URL).thenApply(Utility::countLines);
+ }
+
+ private Promise download(String urlString) {
+ return new Promise()
+ .fulfillInAsync(
+ () -> Utility.downloadFile(urlString), executor)
+ .onError(
+ throwable -> {
+ throwable.printStackTrace();
+ taskCompleted();
+ }
+ );
+ }
+```
## Class diagram
+

## Applicability
+
Promise pattern is applicable in concurrent programming when some work needs to be done asynchronously
and:
@@ -35,10 +294,17 @@ and:
* [Guava ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained)
## Related Patterns
- * Async Method Invocation
- * Callback
+
+ * [Async Method Invocation](https://java-design-patterns.com/patterns/async-method-invocation/)
+ * [Callback](https://java-design-patterns.com/patterns/callback/)
+
+## Tutorials
+
+* [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture)
## Credits
* [You are missing the point to Promises](https://gist.github.com/domenic/3889970)
* [Functional style callbacks using CompletableFuture](https://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture)
+* [Java 8 in Action: Lambdas, Streams, and functional-style programming](https://www.amazon.com/gp/product/1617291994/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617291994&linkId=995af46887bb7b65e6c788a23eaf7146)
+* [Modern Java in Action: Lambdas, streams, functional and reactive programming](https://www.amazon.com/gp/product/1617293563/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617293563&linkId=f70fe0d3e1efaff89554a6479c53759c)
diff --git a/prototype/README.md b/prototype/README.md
index 65d0dbb88..472e8330c 100644
--- a/prototype/README.md
+++ b/prototype/README.md
@@ -10,10 +10,13 @@ tags:
---
## Intent
-Specify the kinds of objects to create using a prototypical
-instance, and create new objects by copying this prototype.
+Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
## Explanation
+
+First it should be noted that Prototype pattern is not used to gain performance benefits. It's only used for creating
+new objects from prototype instance.
+
Real world example
> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is that it is all about cloning.
@@ -78,4 +81,5 @@ Use the Prototype pattern when a system should be independent of how its product
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java b/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
index 1401460d6..8e2ed9474 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class ElfBeast extends Beast {
- private String helpType;
+ private final String helpType;
public ElfBeast(String helpType) {
this.helpType = helpType;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java b/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
index 4a7eea98f..42a54ca97 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class ElfMage extends Mage {
- private String helpType;
+ private final String helpType;
public ElfMage(String helpType) {
this.helpType = helpType;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java b/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
index 101cd5942..fb426a444 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class ElfWarlord extends Warlord {
- private String helpType;
+ private final String helpType;
public ElfWarlord(String helpType) {
this.helpType = helpType;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java b/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
index eb84b2982..14516f3b4 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
@@ -1,65 +1,65 @@
-/*
- * 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.prototype;
-
-/**
- * Concrete factory class.
- */
-public class HeroFactoryImpl implements HeroFactory {
-
- private Mage mage;
- private Warlord warlord;
- private Beast beast;
-
- /**
- * Constructor.
- */
- public HeroFactoryImpl(Mage mage, Warlord warlord, Beast beast) {
- this.mage = mage;
- this.warlord = warlord;
- this.beast = beast;
- }
-
- /**
- * Create mage.
- */
- public Mage createMage() {
- return mage.copy();
- }
-
- /**
- * Create warlord.
- */
- public Warlord createWarlord() {
- return warlord.copy();
- }
-
- /**
- * Create beast.
- */
- public Beast createBeast() {
- return beast.copy();
- }
-
-}
+/*
+ * 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.prototype;
+
+/**
+ * Concrete factory class.
+ */
+public class HeroFactoryImpl implements HeroFactory {
+
+ private final Mage mage;
+ private final Warlord warlord;
+ private final Beast beast;
+
+ /**
+ * Constructor.
+ */
+ public HeroFactoryImpl(Mage mage, Warlord warlord, Beast beast) {
+ this.mage = mage;
+ this.warlord = warlord;
+ this.beast = beast;
+ }
+
+ /**
+ * Create mage.
+ */
+ public Mage createMage() {
+ return mage.copy();
+ }
+
+ /**
+ * Create warlord.
+ */
+ public Warlord createWarlord() {
+ return warlord.copy();
+ }
+
+ /**
+ * Create beast.
+ */
+ public Beast createBeast() {
+ return beast.copy();
+ }
+
+}
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java b/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
index cf3dc18d8..91339887c 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class OrcBeast extends Beast {
- private String weapon;
+ private final String weapon;
public OrcBeast(String weapon) {
this.weapon = weapon;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java b/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
index cb8239c3f..439e7f368 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class OrcMage extends Mage {
- private String weapon;
+ private final String weapon;
public OrcMage(String weapon) {
this.weapon = weapon;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java b/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
index 39facc41e..a2ae31b4d 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class OrcWarlord extends Warlord {
- private String weapon;
+ private final String weapon;
public OrcWarlord(String weapon) {
this.weapon = weapon;
diff --git a/proxy/README.md b/proxy/README.md
index f9538f4cd..b89d2a624 100644
--- a/proxy/README.md
+++ b/proxy/README.md
@@ -140,4 +140,5 @@ are several common situations in which the Proxy pattern is applicable
## Credits
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [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)
diff --git a/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java
index 2187c3300..173825288 100644
--- a/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java
+++ b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java
@@ -35,7 +35,7 @@ import org.slf4j.LoggerFactory;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase