This Enum replaces the integer value previously
+ * stored in {@link RemoteServiceInterface} as SonarCloud was identifying
+ * it as an issue. All test cases have been checked after changes,
+ * without failures.
+ */
+
+public enum RemoteServiceStatus {
+ FAILURE(-1)
+ ;
+
+ private final long remoteServiceStatusValue;
+
+ RemoteServiceStatus(long remoteServiceStatusValue) {
+ this.remoteServiceStatusValue = remoteServiceStatusValue;
+ }
+
+ public long getRemoteServiceStatusValue() {
+ return remoteServiceStatusValue;
+ }
+}
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java
index a9d34581c..57e444d88 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java
@@ -23,6 +23,7 @@
package com.iluwatar.ambassador;
+import static com.iluwatar.ambassador.RemoteServiceStatus.FAILURE;
import static java.lang.Thread.sleep;
import org.slf4j.Logger;
@@ -58,14 +59,14 @@ public class ServiceAmbassador implements RemoteServiceInterface {
private long safeCall(int value) {
var retries = 0;
- var result = (long) FAILURE;
+ var result = FAILURE.getRemoteServiceStatusValue();
for (int i = 0; i < RETRIES; i++) {
if (retries >= RETRIES) {
- return FAILURE;
+ return FAILURE.getRemoteServiceStatusValue();
}
- if ((result = checkLatency(value)) == FAILURE) {
+ if ((result = checkLatency(value)) == FAILURE.getRemoteServiceStatusValue()) {
LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
retries++;
try {
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java
index c9a4d09b6..186f13715 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java
@@ -25,13 +25,23 @@ package com.iluwatar.ambassador;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java
index 12a93a1cb..bab319bee 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java
@@ -37,6 +37,6 @@ class ClientTest {
Client client = new Client();
var result = client.useService(10);
- assertTrue(result == 100 || result == RemoteService.FAILURE);
+ assertTrue(result == 100 || result == RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue());
}
}
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
index 6c45acf66..374a909f3 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
@@ -37,7 +37,7 @@ class RemoteServiceTest {
void testFailedCall() {
var remoteService = new RemoteService(new StaticRandomProvider(0.21));
var result = remoteService.doRemoteFunction(10);
- assertEquals(RemoteServiceInterface.FAILURE, result);
+ assertEquals(RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue(), result);
}
@Test
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java
index 8eb55b30a..48d128115 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java
@@ -35,6 +35,6 @@ class ServiceAmbassadorTest {
@Test
void test() {
long result = new ServiceAmbassador().doRemoteFunction(10);
- assertTrue(result == 100 || result == RemoteServiceInterface.FAILURE);
+ assertTrue(result == 100 || result == RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue());
}
}
diff --git a/api-gateway/README.md b/api-gateway/README.md
index 0d67b8d9b..66cdb20af 100644
--- a/api-gateway/README.md
+++ b/api-gateway/README.md
@@ -12,49 +12,53 @@ tags:
## 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
+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.
+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.
+> 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.
+> 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.
+> 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`.
+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.
@@ -64,7 +68,6 @@ public interface ImageClient {
}
public class ImageClientImpl implements ImageClient {
-
@Override
public String getImagePath() {
var httpClient = HttpClient.newHttpClient();
@@ -114,7 +117,7 @@ public class PriceClientImpl implements PriceClient {
}
```
-And here we can see how API Gateway maps the requests to the microservices.
+Here we can see how API Gateway maps the requests to the microservices.
```java
public class ApiGateway {
diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml
index 744023e90..c5ca117b6 100644
--- a/api-gateway/api-gateway-service/pom.xml
+++ b/api-gateway/api-gateway-service/pom.xml
@@ -29,7 +29,7 @@
api-gatewaycom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0api-gateway-service
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java
index 52dd065ff..6fea815fc 100644
--- a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java
@@ -23,11 +23,16 @@
package com.iluwatar.api.gateway;
+import static org.slf4j.LoggerFactory.getLogger;
+
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
+
+import org.slf4j.Logger;
import org.springframework.stereotype.Component;
/**
@@ -35,6 +40,8 @@ import org.springframework.stereotype.Component;
*/
@Component
public class ImageClientImpl implements ImageClient {
+ private static final Logger LOGGER = getLogger(ImageClientImpl.class);
+
/**
* Makes a simple HTTP Get request to the Image microservice.
*
@@ -49,12 +56,26 @@ public class ImageClientImpl implements ImageClient {
.build();
try {
+ LOGGER.info("Sending request to fetch image path");
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
+ logResponse(httpResponse);
return httpResponse.body();
} catch (IOException | InterruptedException e) {
- e.printStackTrace();
+ LOGGER.error("Failure occurred while getting image path", e);
}
return null;
}
+
+ private void logResponse(HttpResponse httpResponse) {
+ if (isSuccessResponse(httpResponse.statusCode())) {
+ LOGGER.info("Image path received successfully");
+ } else {
+ LOGGER.warn("Image path request failed");
+ }
+ }
+
+ private boolean isSuccessResponse(int responseCode) {
+ return responseCode >= 200 && responseCode <= 299;
+ }
}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java
index 0dc44a51b..f773d0d54 100644
--- a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java
@@ -23,18 +23,26 @@
package com.iluwatar.api.gateway;
+import static org.slf4j.LoggerFactory.getLogger;
+
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
+
+import org.slf4j.Logger;
import org.springframework.stereotype.Component;
+
/**
* An adapter to communicate with the Price microservice.
*/
@Component
public class PriceClientImpl implements PriceClient {
+ private static final Logger LOGGER = getLogger(PriceClientImpl.class);
+
/**
* Makes a simple HTTP Get request to the Price microservice.
*
@@ -49,12 +57,26 @@ public class PriceClientImpl implements PriceClient {
.build();
try {
+ LOGGER.info("Sending request to fetch price info");
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
+ logResponse(httpResponse);
return httpResponse.body();
} catch (IOException | InterruptedException e) {
- e.printStackTrace();
+ LOGGER.error("Failure occurred while getting price info", e);
}
return null;
}
+
+ private void logResponse(HttpResponse httpResponse) {
+ if (isSuccessResponse(httpResponse.statusCode())) {
+ LOGGER.info("Price info received successfully");
+ } else {
+ LOGGER.warn("Price info request failed");
+ }
+ }
+
+ private boolean isSuccessResponse(int responseCode) {
+ return responseCode >= 200 && responseCode <= 299;
+ }
}
diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml
index 27ef343af..821857449 100644
--- a/api-gateway/image-microservice/pom.xml
+++ b/api-gateway/image-microservice/pom.xml
@@ -29,7 +29,7 @@
api-gatewaycom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0image-microservice
diff --git a/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java b/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java
index b1f6dd3f7..a96ef4f41 100644
--- a/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java
+++ b/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java
@@ -23,15 +23,20 @@
package com.iluwatar.image.microservice;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.slf4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
+
/**
* Exposes the Image microservice's endpoints.
*/
@RestController
public class ImageController {
+ private static final Logger LOGGER = getLogger(ImageController.class);
/**
* An endpoint for a user to retrieve an image path.
@@ -40,6 +45,7 @@ public class ImageController {
*/
@RequestMapping(value = "/image-path", method = RequestMethod.GET)
public String getImagePath() {
+ LOGGER.info("Successfully found image path");
return "/product-image.png";
}
}
diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml
index 63a986996..8ed569412 100644
--- a/api-gateway/pom.xml
+++ b/api-gateway/pom.xml
@@ -29,7 +29,7 @@
java-design-patternscom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0api-gateway
diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml
index e7b144c58..dc3591bf3 100644
--- a/api-gateway/price-microservice/pom.xml
+++ b/api-gateway/price-microservice/pom.xml
@@ -29,7 +29,7 @@
api-gatewaycom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0
diff --git a/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java b/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java
index cf2f5eb4f..dbcd59952 100644
--- a/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java
+++ b/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java
@@ -23,15 +23,20 @@
package com.iluwatar.price.microservice;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.slf4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
+
/**
* Exposes the Price microservice's endpoints.
*/
@RestController
public class PriceController {
+ private static final Logger LOGGER = getLogger(PriceController.class);
/**
* An endpoint for a user to retrieve a product's price.
@@ -40,6 +45,7 @@ public class PriceController {
*/
@RequestMapping(value = "/price", method = RequestMethod.GET)
public String getPrice() {
+ LOGGER.info("Successfully found price info");
return "20";
}
}
diff --git a/arrange-act-assert/README.md b/arrange-act-assert/README.md
index 02b7ee8b7..6b3cb4058 100644
--- a/arrange-act-assert/README.md
+++ b/arrange-act-assert/README.md
@@ -9,22 +9,137 @@ tags:
---
## Also known as
+
Given/When/Then
## Intent
-The Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
+
+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.
+## Explanation
+
+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. It makes tests more natural to write at
+the same time since you already have an outline.
+
+Real world example
+
+> We need to write comprehensive and clear unit test suite for a class.
+
+In plain words
+
+> Arrange/Act/Assert is a testing pattern that organizes tests into three clear steps for easy
+> maintenance.
+
+WikiWikiWeb says
+
+> Arrange/Act/Assert is a pattern for arranging and formatting code in UnitTest methods.
+
+**Programmatic Example**
+
+Let's first introduce our `Cash` class to be unit tested.
+
+```java
+public class Cash {
+
+ private int amount;
+
+ Cash(int amount) {
+ this.amount = amount;
+ }
+
+ void plus(int addend) {
+ amount += addend;
+ }
+
+ boolean minus(int subtrahend) {
+ if (amount >= subtrahend) {
+ amount -= subtrahend;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ int count() {
+ return amount;
+ }
+}
+```
+
+Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the clearly
+separated steps for each unit test.
+
+```java
+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());
+ }
+}
+```
+
## Applicability
+
Use Arrange/Act/Assert pattern when
-* you need to structure your unit tests so they're easier to read, maintain, and enhance.
+* You need to structure your unit tests so that 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)
+* [xUnit Test Patterns: Refactoring Test Code](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f7e8dd50d720c9b63dbf)
+* [Unit Testing Principles, Practices, and Patterns](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cf22a63c3e4758ae08aa0a0cc35)
+* [Test Driven Development: By Example](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b84ca5087472ef0e05)
diff --git a/arrange-act-assert/pom.xml b/arrange-act-assert/pom.xml
index bb0387e7a..4b0d57ebf 100644
--- a/arrange-act-assert/pom.xml
+++ b/arrange-act-assert/pom.xml
@@ -29,7 +29,7 @@
java-design-patternscom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0
diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml
index 46aa9d354..b4f7dd670 100644
--- a/async-method-invocation/pom.xml
+++ b/async-method-invocation/pom.xml
@@ -22,7 +22,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTasync-method-invocation
diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
index 830e66a2d..5dfe901e8 100644
--- a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
+++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
@@ -25,12 +25,24 @@ package com.iluwatar.async.method.invocation;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() throws Exception {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+
}
}
diff --git a/balking/pom.xml b/balking/pom.xml
index 964531692..0a86bc430 100644
--- a/balking/pom.xml
+++ b/balking/pom.xml
@@ -20,7 +20,7 @@
java-design-patternscom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0
diff --git a/balking/src/test/java/com/iluwatar/balking/AppTest.java b/balking/src/test/java/com/iluwatar/balking/AppTest.java
index 8c75a1f62..b12b6e1ec 100644
--- a/balking/src/test/java/com/iluwatar/balking/AppTest.java
+++ b/balking/src/test/java/com/iluwatar/balking/AppTest.java
@@ -24,15 +24,26 @@
package com.iluwatar.balking;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void main() {
- App.main();
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow((Executable) App::main);
}
}
\ No newline at end of file
diff --git a/bridge/README.md b/bridge/README.md
index 82c2f2735..12a6358f5 100644
--- a/bridge/README.md
+++ b/bridge/README.md
@@ -9,20 +9,26 @@ tags:
---
## Also known as
+
Handle/Body
## Intent
+
Decouple an abstraction from its implementation so that the two can vary independently.
## Explanation
Real world example
-> Consider you have a weapon with different enchantments and you are supposed to allow mixing different weapons with different enchantments. What would you do? Create multiple copies of each of the weapons for each of the enchantments or would you just create separate enchantment and set it for the weapon as needed? Bridge pattern allows you to do the second.
+> Consider you have a weapon with different enchantments, and you are supposed to allow mixing
+> different weapons with different enchantments. What would you do? Create multiple copies of each
+> of the weapons for each of the enchantments or would you just create separate enchantment and set
+> it for the weapon as needed? Bridge pattern allows you to do the second.
In Plain Words
-> Bridge pattern is about preferring composition over inheritance. Implementation details are pushed from a hierarchy to another object with a separate hierarchy.
+> Bridge pattern is about preferring composition over inheritance. Implementation details are pushed
+> from a hierarchy to another object with a separate hierarchy.
Wikipedia says
@@ -30,7 +36,7 @@ Wikipedia says
**Programmatic Example**
-Translating our weapon example from above. Here we have the `Weapon` hierarchy
+Translating our weapon example from above. Here we have the `Weapon` hierarchy:
```java
public interface Weapon {
@@ -105,7 +111,7 @@ public class Hammer implements Weapon {
}
```
-And the separate enchantment hierarchy
+Here's the separate enchantment hierarchy:
```java
public interface Enchantment {
@@ -151,7 +157,7 @@ public class SoulEatingEnchantment implements Enchantment {
}
```
-And both the hierarchies in action
+Here are both hierarchies in action:
```java
var enchantedSword = new Sword(new SoulEatingEnchantment());
@@ -178,18 +184,21 @@ hammer.unwield();
```
## Class diagram
+

## Applicability
+
Use the Bridge pattern when
-* you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.
-* both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently
-* changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
-* you have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies
-* you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation.
+* You want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.
+* Both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently.
+* Changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
+* You have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies.
+* You want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation.
## Tutorial
+
* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java)
## Credits
diff --git a/bridge/pom.xml b/bridge/pom.xml
index 0664bc9b5..41271814c 100644
--- a/bridge/pom.xml
+++ b/bridge/pom.xml
@@ -22,7 +22,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTbridge
diff --git a/bridge/src/test/java/com/iluwatar/bridge/AppTest.java b/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
index d3edbb27c..026f0954c 100644
--- a/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
+++ b/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
@@ -25,12 +25,22 @@ package com.iluwatar.bridge;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/builder/README.md b/builder/README.md
index bb7426e35..008854ed7 100644
--- a/builder/README.md
+++ b/builder/README.md
@@ -9,36 +9,47 @@ tags:
---
## Intent
-Separate the construction of a complex object from its
-representation so that the same construction process can create different
-representations.
+
+Separate the construction of a complex object from its representation so that the same construction
+process can create different representations.
## Explanation
Real world example
-> Imagine a character generator for a role playing game. The easiest option is to let computer create the character for you. But if you want to select the character details like profession, gender, hair color etc. the character generation becomes a step-by-step process that completes when all the selections are ready.
+> Imagine a character generator for a role-playing game. The easiest option is to let the computer
+> create the character for you. If you want to manually select the character details like
+> profession, gender, hair color etc. the character generation becomes a step-by-step process that
+> completes when all the selections are ready.
In plain words
-> Allows you to create different flavors of an object while avoiding constructor pollution. Useful when there could be several flavors of an object. Or when there are a lot of steps involved in creation of an object.
+> Allows you to create different flavors of an object while avoiding constructor pollution. Useful
+> when there could be several flavors of an object. Or when there are a lot of steps involved in
+> creation of an object.
Wikipedia says
-> The builder pattern is an object creation software design pattern with the intentions of finding a solution to the telescoping constructor anti-pattern.
+> The builder pattern is an object creation software design pattern with the intentions of finding
+> a solution to the telescoping constructor anti-pattern.
-Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point or the other we have all seen a constructor like below:
+Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point
+or the other, we have all seen a constructor like below:
```java
public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) {
}
```
-As you can see the number of constructor parameters can quickly get out of hand and it might become difficult to understand the arrangement of parameters. Plus this parameter list could keep on growing if you would want to add more options in future. This is called telescoping constructor anti-pattern.
+As you can see the number of constructor parameters can quickly get out of hand, and it may become
+difficult to understand the arrangement of parameters. Plus this parameter list could keep on
+growing if you would want to add more options in the future. This is called telescoping constructor
+anti-pattern.
**Programmatic Example**
-The sane alternative is to use the Builder pattern. First of all we have our hero that we want to create
+The sane alternative is to use the Builder pattern. First of all we have our hero that we want to
+create:
```java
public final class Hero {
@@ -60,7 +71,7 @@ public final class Hero {
}
```
-And then we have the builder
+Then we have the builder:
```java
public static class Builder {
@@ -105,20 +116,22 @@ And then we have the builder
}
```
-And then it can be used as:
+Then it can be used as:
```java
var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();
```
## Class diagram
+

## Applicability
+
Use the Builder pattern when
-* the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
-* the construction process must allow different representations for the object that's constructed
+* The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
+* The construction process must allow different representations for the object that's constructed
## Real world examples
diff --git a/builder/pom.xml b/builder/pom.xml
index dab9c66a7..6aa467f9e 100644
--- a/builder/pom.xml
+++ b/builder/pom.xml
@@ -22,7 +22,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTbuilder
diff --git a/builder/src/test/java/com/iluwatar/builder/AppTest.java b/builder/src/test/java/com/iluwatar/builder/AppTest.java
index 941f62f75..29b6ecb15 100644
--- a/builder/src/test/java/com/iluwatar/builder/AppTest.java
+++ b/builder/src/test/java/com/iluwatar/builder/AppTest.java
@@ -25,12 +25,23 @@ package com.iluwatar.builder;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml
index 26987c73a..a46e856a9 100644
--- a/business-delegate/pom.xml
+++ b/business-delegate/pom.xml
@@ -22,7 +22,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTbusiness-delegate
diff --git a/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java b/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
index 48e756acb..6c57e145e 100644
--- a/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
+++ b/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
@@ -27,13 +27,23 @@ import org.junit.jupiter.api.Test;
import java.io.IOException;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Business Delegate example runs without errors.
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- public void test() throws IOException {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/bytecode/pom.xml b/bytecode/pom.xml
index f6be69cee..d21064be4 100644
--- a/bytecode/pom.xml
+++ b/bytecode/pom.xml
@@ -20,7 +20,7 @@
java-design-patternscom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT4.0.0
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/App.java b/bytecode/src/main/java/com/iluwatar/bytecode/App.java
index 04f473cee..b85d8ef05 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/App.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/App.java
@@ -58,12 +58,14 @@ public class App {
var vm = new VirtualMachine();
vm.getWizards()[0] = wizard;
- interpretInstruction("LITERAL 0", vm);
- interpretInstruction("LITERAL 0", vm);
+ String literal = "LITERAL 0";
+
+ interpretInstruction(literal, vm);
+ interpretInstruction(literal, vm);
interpretInstruction("GET_HEALTH", vm);
- interpretInstruction("LITERAL 0", vm);
+ interpretInstruction(literal, vm);
interpretInstruction("GET_AGILITY", vm);
- interpretInstruction("LITERAL 0", vm);
+ interpretInstruction(literal, vm);
interpretInstruction("GET_WISDOM ", vm);
interpretInstruction("ADD", vm);
interpretInstruction("LITERAL 2", vm);
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
index 59962d39e..31060b683 100644
--- a/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
@@ -25,13 +25,22 @@ package com.iluwatar.bytecode;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/caching/pom.xml b/caching/pom.xml
index 704dd78d0..627f76e98 100644
--- a/caching/pom.xml
+++ b/caching/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcaching
diff --git a/caching/src/test/java/com/iluwatar/caching/AppTest.java b/caching/src/test/java/com/iluwatar/caching/AppTest.java
index 831cfe493..20a03282d 100644
--- a/caching/src/test/java/com/iluwatar/caching/AppTest.java
+++ b/caching/src/test/java/com/iluwatar/caching/AppTest.java
@@ -27,12 +27,23 @@ import org.junit.jupiter.api.Test;
import java.io.IOException;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Caching example runs without errors.
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/callback/README.md b/callback/README.md
index 78766cc15..34543f0bb 100644
--- a/callback/README.md
+++ b/callback/README.md
@@ -9,14 +9,16 @@ 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.
+> 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
@@ -24,7 +26,9 @@ In plain words
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.
+> 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**
@@ -61,7 +65,7 @@ public final class SimpleTask extends Task {
}
```
-Finally here's how we execute a task and receive a callback when it's finished.
+Finally, here's how we execute a task and receive a callback when it's finished.
```java
var task = new SimpleTask();
@@ -69,13 +73,15 @@ Finally here's how we execute a task and receive a callback when it's finished.
```
## Class diagram
+

## Applicability
+
Use the Callback pattern when
* when some arbitrary synchronous or asynchronous action must be performed after execution of some defined activity.
## Real world examples
-* [CyclicBarrier](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept callback that will be triggered every time when barrier is tripped.
+* [CyclicBarrier](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept a callback that will be triggered every time a barrier is tripped.
diff --git a/callback/etc/callback.png b/callback/etc/callback.png
index a81745871..7b499f79f 100644
Binary files a/callback/etc/callback.png and b/callback/etc/callback.png differ
diff --git a/callback/etc/callback.urm.puml b/callback/etc/callback.urm.puml
index a666a4fdb..2d213eda8 100644
--- a/callback/etc/callback.urm.puml
+++ b/callback/etc/callback.urm.puml
@@ -8,11 +8,6 @@ package com.iluwatar.callback {
interface Callback {
+ call() {abstract}
}
- class LambdasApp {
- - LOGGER : Logger {static}
- - LambdasApp()
- + main(args : String[]) {static}
- }
class SimpleTask {
- LOGGER : Logger {static}
+ SimpleTask()
diff --git a/callback/pom.xml b/callback/pom.xml
index c156527f5..a74b653e1 100644
--- a/callback/pom.xml
+++ b/callback/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcallback
diff --git a/callback/src/test/java/com/iluwatar/callback/AppTest.java b/callback/src/test/java/com/iluwatar/callback/AppTest.java
index c1f466dee..3a70df7e0 100644
--- a/callback/src/test/java/com/iluwatar/callback/AppTest.java
+++ b/callback/src/test/java/com/iluwatar/callback/AppTest.java
@@ -25,12 +25,23 @@ package com.iluwatar.callback;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Callback example runs without errors.
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/chain/README.md b/chain/README.md
index f11f0c59e..8b0508833 100644
--- a/chain/README.md
+++ b/chain/README.md
@@ -9,27 +9,32 @@ tags:
---
## Intent
-Avoid coupling the sender of a request to its receiver by giving
-more than one object a chance to handle the request. Chain the receiving
-objects and pass the request along the chain until an object handles it.
+Avoid coupling the sender of a request to its receiver by giving more than one object a chance to
+handle the request. Chain the receiving objects and pass the request along the chain until an object
+handles it.
## Explanation
Real world example
-> The Orc King gives loud orders to his army. The closest one to react is the commander, then officer and then soldier. The commander, officer and soldier here form a chain of responsibility.
+> The Orc King gives loud orders to his army. The closest one to react is the commander, then
+> officer and then soldier. The commander, officer and soldier here form a chain of responsibility.
In plain words
-> It helps building a chain of objects. Request enters from one end and keeps going from object to object till it finds the suitable handler.
+> It helps to build a chain of objects. A request enters from one end and keeps going from an object
+> to another until it finds a suitable handler.
Wikipedia says
-> In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.
+> In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of
+> a source of command objects and a series of processing objects. Each processing object contains
+> logic that defines the types of command objects that it can handle; the rest are passed to the
+> next processing object in the chain.
**Programmatic Example**
-Translating our example with orcs from above. First we have the request class
+Translating our example with the orcs from above. First we have the `Request` class:
```java
public class Request {
@@ -140,14 +145,16 @@ king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax")); // Orc so
```
## Class diagram
+

## Applicability
+
Use Chain of Responsibility when
-* more than one object may handle a request, and the handler isn't known a priori. The handler should be ascertained automatically
-* you want to issue a request to one of several objects without specifying the receiver explicitly
-* the set of objects that can handle a request should be specified dynamically
+* More than one object may handle a request, and the handler isn't known a priori. The handler should be ascertained automatically.
+* You want to issue a request to one of several objects without specifying the receiver explicitly.
+* The set of objects that can handle a request should be specified dynamically.
## Real world examples
diff --git a/chain/pom.xml b/chain/pom.xml
index cf70ad1e8..9a7097e6d 100644
--- a/chain/pom.xml
+++ b/chain/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTchain
diff --git a/chain/src/test/java/com/iluwatar/chain/AppTest.java b/chain/src/test/java/com/iluwatar/chain/AppTest.java
index 164ff9bfe..6cd696517 100644
--- a/chain/src/test/java/com/iluwatar/chain/AppTest.java
+++ b/chain/src/test/java/com/iluwatar/chain/AppTest.java
@@ -25,13 +25,23 @@ package com.iluwatar.chain;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/circuit-breaker/README.md b/circuit-breaker/README.md
index ce280a570..8d2205f2b 100644
--- a/circuit-breaker/README.md
+++ b/circuit-breaker/README.md
@@ -12,32 +12,43 @@ tags:
## Intent
-Handle costly remote *procedure/service* calls in such a way that the failure of a **single** service/component cannot bring the whole application down, and we can reconnect to the service as soon as possible.
+Handle costly remote service calls in such a way that the failure of a single service/component
+cannot bring the whole application down, and we can reconnect to the service as soon as possible.
## Explanation
Real world example
-> Imagine a Web App that has both local (example: files and images) and remote (example: database entries) to serve. The database might not be responding due to a variety of reasons, so if the application keeps trying to read from the database using multiple threads/processes, soon all of them will hang and our entire web application will crash. We should be able to detect this situation and show the user an appropriate message so that he/she can explore other parts of the app unaffected by the database failure without any problem.
+> Imagine a web application that has both local files/images and remote database entries to serve.
+> The database might not be responding due to a variety of reasons, so if the application keeps
+> trying to read from the database using multiple threads/processes, soon all of them will hang
+> causing our entire web application will crash. We should be able to detect this situation and show
+> the user an appropriate message so that he/she can explore other parts of the app unaffected by
+> the database failure.
In plain words
-> Allows us to save resources when we know a remote service failed. Useful when all parts of our application are highly decoupled from each other, and failure of one component doesn't mean the other parts will stop working.
+> Circuit Breaker allows graceful handling of failed remote services. It's especially useful when
+> all parts of our application are highly decoupled from each other, and failure of one component
+> doesn't mean the other parts will stop working.
Wikipedia says
-> **Circuit breaker** is a design pattern used in modern software development. It is used to detect failures and encapsulates the logic of preventing a failure from constantly recurring, during maintenance, temporary external system failure or unexpected system difficulties.
-
-So, how does this all come together?
+> Circuit breaker is a design pattern used in modern software development. It is used to detect
+> failures and encapsulates the logic of preventing a failure from constantly recurring, during
+> maintenance, temporary external system failure or unexpected system difficulties.
## Programmatic Example
-With the above example in mind we will imitate the functionality in a simple manner. We have two services: A *monitoring service* which will mimic the web app and will make both **local** and **remote** calls.
+
+So, how does this all come together? With the above example in mind we will imitate the
+functionality in a simple example. A monitoring service mimics the web app and makes both local and
+remote calls.
The service architecture is as follows:

-In terms of code, the End user application is:
+In terms of code, the end user application is:
```java
public class App {
@@ -62,7 +73,7 @@ public class App {
}
```
-The monitoring service is:
+The monitoring service:
``` java
public class MonitoringService {
@@ -80,7 +91,8 @@ public class MonitoringService {
}
}
```
-As it can be seen, it does the call to get local resources directly, but it wraps the call to remote (costly) service in a circuit breaker object, which prevents faults as follows:
+As it can be seen, it does the call to get local resources directly, but it wraps the call to
+remote (costly) service in a circuit breaker object, which prevents faults as follows:
```java
public class CircuitBreaker {
@@ -155,24 +167,27 @@ public class CircuitBreaker {
}
```
-How does the above pattern prevent failures? Let's understand via this finite state machine implemented by it.
+How does the above pattern prevent failures? Let's understand via this finite state machine
+implemented by it.

-- We initialize the Circuit Breaker object with certain parameters: **timeout**, **failureThreshold** and **retryTimePeriod** which help determine how resilient the API is.
-- Initially, we are in the **closed** state and the remote call to API happens.
+- We initialize the Circuit Breaker object with certain parameters: `timeout`, `failureThreshold` and `retryTimePeriod` which help determine how resilient the API is.
+- Initially, we are in the `closed` state and nos remote calls to the API have occurred.
- Every time the call succeeds, we reset the state to as it was in the beginning.
-- If the number of failures cross a certain threshold, we move to the **open** state, which acts just like an open circuit and prevents remote service calls from being made, thus saving resources. (Here, we return the response called ```stale response from API```)
-- Once we exceed the retry timeout period, we move to the **half-open** state and make another call to the remote service again to check if the service is working so that we can serve fresh content. A *failure* sets it back to **open** state and another attempt is made after retry timeout period, while a *success* sets it to **closed** state so that everything starts working normally again.
+- If the number of failures cross a certain threshold, we move to the `open` state, which acts just like an open circuit and prevents remote service calls from being made, thus saving resources. (Here, we return the response called ```stale response from API```)
+- Once we exceed the retry timeout period, we move to the `half-open` state and make another call to the remote service again to check if the service is working so that we can serve fresh content. A failure sets it back to `open` state and another attempt is made after retry timeout period, while a success sets it to `closed` state so that everything starts working normally again.
## Class diagram
+

## Applicability
+
Use the Circuit Breaker pattern when
- Building a fault-tolerant application where failure of some services shouldn't bring the entire application down.
-- Building an continuously incremental/continuous delivery application, as some of it's components can be upgraded without shutting it down entirely.
+- Building a continuously running (always-on) application, so that its components can be upgraded without shutting it down entirely.
## Related Patterns
diff --git a/circuit-breaker/pom.xml b/circuit-breaker/pom.xml
index fd9f85675..083c527fa 100644
--- a/circuit-breaker/pom.xml
+++ b/circuit-breaker/pom.xml
@@ -27,7 +27,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcircuit-breaker
diff --git a/collection-pipeline/pom.xml b/collection-pipeline/pom.xml
index 6d8d467ad..08c41880b 100644
--- a/collection-pipeline/pom.xml
+++ b/collection-pipeline/pom.xml
@@ -27,7 +27,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcollection-pipeline
diff --git a/combinator/pom.xml b/combinator/pom.xml
index 3edfa7580..4886873cd 100644
--- a/combinator/pom.xml
+++ b/combinator/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcombinator
@@ -39,6 +39,12 @@
junittest
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
diff --git a/combinator/src/test/java/com/iluwatar/combinator/CombinatorAppTest.java b/combinator/src/test/java/com/iluwatar/combinator/CombinatorAppTest.java
index f42b46c14..6e7b4f63f 100644
--- a/combinator/src/test/java/com/iluwatar/combinator/CombinatorAppTest.java
+++ b/combinator/src/test/java/com/iluwatar/combinator/CombinatorAppTest.java
@@ -25,12 +25,19 @@ package com.iluwatar.combinator;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
public class CombinatorAppTest {
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link CombinatorApp#main(String[])}
+ * throws an exception.
+ */
+
@Test
- public void main() {
- CombinatorApp.main(new String[]{});
+ public void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> CombinatorApp.main(new String[]{}));
}
}
\ No newline at end of file
diff --git a/command/README.md b/command/README.md
index b763cf4dd..28c7e88e9 100644
--- a/command/README.md
+++ b/command/README.md
@@ -9,15 +9,20 @@ tags:
---
## Also known as
+
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.
+> 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
@@ -25,11 +30,13 @@ In plain words
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.
+> 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.
+Here's the sample code with wizard and goblin. Let's start from the `Wizard` class.
```java
public class Wizard {
@@ -149,7 +156,7 @@ public class ShrinkSpell implements Command {
}
```
-And last we have the goblin who's the target of the spells.
+Finally, we have the goblin who's the target of the spells.
```java
public abstract class Target {
@@ -199,44 +206,67 @@ public class Goblin extends Target {
}
```
-Finally here's the whole example in action.
+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();
+```
+
+Here's the program output:
+
+```java
+// Goblin, [size=normal] [visibility=visible]
+// Wizard casts Shrink spell at Goblin
+// Goblin, [size=small] [visibility=visible]
+// Wizard casts Invisibility spell at Goblin
+// Goblin, [size=small] [visibility=invisible]
+// Wizard undoes Invisibility spell
// Goblin, [size=small] [visibility=visible]
```
## Class diagram
+

## Applicability
-Use the Command pattern when you want to
-* parameterize objects by an action to perform. You can express such parameterization in a procedural language with a callback function, that is, a function that's registered somewhere to be called at a later point. Commands are an object-oriented replacement for callbacks.
-* specify, queue, and execute requests at different times. A Command object can have a lifetime independent of the original request. If the receiver of a request can be represented in an address space-independent way, then you can transfer a command object for the request to a different process and fulfill the request there
-* support undo. The Command's execute operation can store state for reversing its effects in the command itself. The Command interface must have an added Unexecute operation that reverses the effects of a previous call to execute. Executed commands are stored in a history list. Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling unexecute and execute, respectively
-* support logging changes so that they can be reapplied in case of a system crash. By augmenting the Command interface with load and store operations, you can keep a persistent log of changes. Recovering from a crash involves reloading logged commands from disk and re-executing them with the execute operation
-* structure a system around high-level operations build on primitive operations. Such a structure is common in information systems that support transactions. A transaction encapsulates a set of changes to data. The Command pattern offers a way to model transactions. Commands have a common interface, letting you invoke all transactions the same way. The pattern also makes it easy to extend the system with new transactions
+Use the Command pattern when you want to:
+
+* Parameterize objects by an action to perform. You can express such parameterization in a
+procedural language with a callback function, that is, a function that's registered somewhere to be
+called at a later point. Commands are an object-oriented replacement for callbacks.
+* Specify, queue, and execute requests at different times. A Command object can have a lifetime
+independent of the original request. If the receiver of a request can be represented in an address
+space-independent way, then you can transfer a command object for the request to a different process
+and fulfill the request there.
+* Support undo. The Command's execute operation can store state for reversing its effects in the
+command itself. The Command interface must have an added un-execute operation that reverses the
+effects of a previous call to execute. The executed commands are stored in a history list.
+Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling
+un-execute and execute, respectively.
+* Support logging changes so that they can be reapplied in case of a system crash. By augmenting the
+Command interface with load and store operations, you can keep a persistent log of changes.
+Recovering from a crash involves reloading logged commands from disk and re-executing them with
+the execute operation.
+* Structure a system around high-level operations build on primitive operations. Such a structure is
+common in information systems that support transactions. A transaction encapsulates a set of changes
+to data. The Command pattern offers a way to model transactions. Commands have a common interface,
+letting you invoke all transactions the same way. The pattern also makes it easy to extend the
+system with new transactions.
## Typical Use Case
-* to keep a history of requests
-* implement callback functionality
-* implement the undo functionality
+* To keep a history of requests
+* Implement callback functionality
+* Implement the undo functionality
## Real world examples
diff --git a/command/pom.xml b/command/pom.xml
index 50a14c45f..3869d4b44 100644
--- a/command/pom.xml
+++ b/command/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcommand
diff --git a/command/src/test/java/com/iluwatar/command/AppTest.java b/command/src/test/java/com/iluwatar/command/AppTest.java
index cf691aba3..73d098fa3 100644
--- a/command/src/test/java/com/iluwatar/command/AppTest.java
+++ b/command/src/test/java/com/iluwatar/command/AppTest.java
@@ -25,12 +25,21 @@ package com.iluwatar.command;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Command example runs without errors.
*/
-public class AppTest {
+class AppTest {
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
+ * throws an exception.
+ */
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/commander/pom.xml b/commander/pom.xml
index 7ab29e421..baabc04fc 100644
--- a/commander/pom.xml
+++ b/commander/pom.xml
@@ -27,7 +27,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTcommander
diff --git a/commander/src/main/java/com/iluwatar/commander/Commander.java b/commander/src/main/java/com/iluwatar/commander/Commander.java
index 41779c076..2909f9304 100644
--- a/commander/src/main/java/com/iluwatar/commander/Commander.java
+++ b/commander/src/main/java/com/iluwatar/commander/Commander.java
@@ -36,9 +36,11 @@ import com.iluwatar.commander.queue.QueueDatabase;
import com.iluwatar.commander.queue.QueueTask;
import com.iluwatar.commander.queue.QueueTask.TaskType;
import com.iluwatar.commander.shippingservice.ShippingService;
+import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
/**
*
The Master-Worker pattern is used when the problem at hand can be solved by
- * dividing into
- * multiple parts which need to go through the same computation and may need to be aggregated to get
- * final result. Parallel processing is performed using a system consisting of a master and some
- * number of workers, where a master divides the work among the workers, gets the result back from
- * them and assimilates all the results to give final result. The only communication is between the
- * master and the worker - none of the workers communicate among one another and the user only
- * communicates with the master to get required job done.
+ * dividing into multiple parts which need to go through the same computation and may need to be
+ * aggregated to get final result. Parallel processing is performed using a system consisting of a
+ * master and some number of workers, where a master divides the work among the workers, gets the
+ * result back from them and assimilates all the results to give final result. The only
+ * communication is between the master and the worker - none of the workers communicate among one
+ * another and the user only communicates with the master to get required job done.
*
In our example, we have generic abstract classes {@link MasterWorker}, {@link Master} and
- * {@link Worker} which
- * have to be extended by the classes which will perform the specific job at hand (in this case
- * finding transpose of matrix, done by {@link ArrayTransposeMasterWorker}, {@link
- * ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work into
- * parts to be given to the workers, collects the results from the workers and aggregates it when
- * all workers have responded before returning the solution. The Worker class extends the Thread
- * class to enable parallel processing, and does the work once the data has been received from the
- * Master. The MasterWorker contains a reference to the Master class, gets the input from the App
- * and passes it on to the Master. These 3 classes define the system which computes the result. We
- * also have 2 abstract classes {@link Input} and {@link Result}, which contain the input data and
- * result data respectively. The Input class also has an abstract method divideData which defines
- * how the data is to be divided into segments. These classes are extended by {@link ArrayInput} and
- * {@link ArrayResult}.
+ * {@link Worker} which have to be extended by the classes which will perform the specific job at
+ * hand (in this case finding transpose of matrix, done by {@link ArrayTransposeMasterWorker},
+ * {@link ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work
+ * into parts to be given to the workers, collects the results from the workers and aggregates it
+ * when all workers have responded before returning the solution. The Worker class extends the
+ * Thread class to enable parallel processing, and does the work once the data has been received
+ * from the Master. The MasterWorker contains a reference to the Master class, gets the input from
+ * the App and passes it on to the Master. These 3 classes define the system which computes the
+ * result. We also have 2 abstract classes {@link Input} and {@link Result}, which contain the input
+ * data and result data respectively. The Input class also has an abstract method divideData which
+ * defines how the data is to be divided into segments. These classes are extended by {@link
+ * ArrayInput} and {@link ArrayResult}.
*/
public class App {
@@ -68,12 +66,12 @@ public class App {
*/
public static void main(String[] args) {
- ArrayTransposeMasterWorker mw = new ArrayTransposeMasterWorker();
- int rows = 10;
- int columns = 20;
- int[][] inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
- ArrayInput input = new ArrayInput(inputMatrix);
- ArrayResult result = (ArrayResult) mw.getResult(input);
+ var mw = new ArrayTransposeMasterWorker();
+ var rows = 10;
+ var columns = 20;
+ var inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
+ var input = new ArrayInput(inputMatrix);
+ var result = (ArrayResult) mw.getResult(input);
if (result != null) {
ArrayUtilityMethods.printMatrix(inputMatrix);
ArrayUtilityMethods.printMatrix(result.data);
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java
index cd03a0a21..c8e68f958 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java
@@ -25,6 +25,7 @@ package com.iluwatar.masterworker;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Class ArrayInput extends abstract class {@link Input} and contains data of type int[][].
@@ -37,12 +38,12 @@ public class ArrayInput extends Input {
}
static int[] makeDivisions(int[][] data, int num) {
- int initialDivision = data.length / num; //equally dividing
- int[] divisions = new int[num];
+ var initialDivision = data.length / num; //equally dividing
+ var divisions = new int[num];
Arrays.fill(divisions, initialDivision);
if (initialDivision * num != data.length) {
- int extra = data.length - initialDivision * num;
- int l = 0;
+ var extra = data.length - initialDivision * num;
+ var l = 0;
//equally dividing extra among all parts
while (extra > 0) {
divisions[l] = divisions[l] + 1;
@@ -58,22 +59,20 @@ public class ArrayInput extends Input {
}
@Override
- public ArrayList divideData(int num) {
+ public List> divideData(int num) {
if (this.data == null) {
return null;
} else {
- int[] divisions = makeDivisions(this.data, num);
- ArrayList result = new ArrayList(num);
- int rowsDone = 0; //number of rows divided so far
- for (int i = 0; i < num; i++) {
- int rows = divisions[i];
+ var divisions = makeDivisions(this.data, num);
+ var result = new ArrayList>(num);
+ var rowsDone = 0; //number of rows divided so far
+ for (var i = 0; i < num; i++) {
+ var rows = divisions[i];
if (rows != 0) {
- int[][] divided = new int[rows][this.data[0].length];
- for (int j = 0; j < rows; j++) {
- divided[j] = this.data[rowsDone + j];
- }
+ var divided = new int[rows][this.data[0].length];
+ System.arraycopy(this.data, rowsDone, divided, 0, rows);
rowsDone += rows;
- ArrayInput dividedInput = new ArrayInput(divided);
+ var dividedInput = new ArrayInput(divided);
result.add(dividedInput);
} else {
break; //rest of divisions will also be 0
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java
index 525bed003..5e695e5da 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java
@@ -47,8 +47,8 @@ public class ArrayUtilityMethods {
if (a1.length != a2.length) {
return false;
} else {
- boolean answer = false;
- for (int i = 0; i < a1.length; i++) {
+ var answer = false;
+ for (var i = 0; i < a1.length; i++) {
if (a1[i] == a2[i]) {
answer = true;
} else {
@@ -69,8 +69,8 @@ public class ArrayUtilityMethods {
if (m1.length != m2.length) {
return false;
} else {
- boolean answer = false;
- for (int i = 0; i < m1.length; i++) {
+ var answer = false;
+ for (var i = 0; i < m1.length; i++) {
if (arraysSame(m1[i], m2[i])) {
answer = true;
} else {
@@ -88,9 +88,9 @@ public class ArrayUtilityMethods {
* @return it (int[][]).
*/
public static int[][] createRandomIntMatrix(int rows, int columns) {
- int[][] matrix = new int[rows][columns];
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < columns; j++) {
+ var matrix = new int[rows][columns];
+ for (var i = 0; i < rows; i++) {
+ for (var j = 0; j < columns; j++) {
//filling cells in matrix
matrix[i][j] = RANDOM.nextInt(10);
}
@@ -104,9 +104,9 @@ public class ArrayUtilityMethods {
public static void printMatrix(int[][] matrix) {
//prints out int[][]
- for (int i = 0; i < matrix.length; i++) {
- for (int j = 0; j < matrix[0].length; j++) {
- LOGGER.info(matrix[i][j] + " ");
+ for (var ints : matrix) {
+ for (var j = 0; j < matrix[0].length; j++) {
+ LOGGER.info(ints[j] + " ");
}
LOGGER.info("");
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java
index 6a957ae80..8d832f6c7 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java
@@ -23,7 +23,7 @@
package com.iluwatar.masterworker;
-import java.util.ArrayList;
+import java.util.List;
/**
* The abstract Input class, having 1 public field which contains input data, and abstract method
@@ -40,5 +40,5 @@ public abstract class Input {
this.data = data;
}
- public abstract ArrayList divideData(int num);
+ public abstract List> divideData(int num);
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java
index 2b16cbf76..817fd65d3 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java
@@ -40,7 +40,7 @@ public abstract class MasterWorker {
abstract Master setMaster(int numOfWorkers);
- public Result getResult(Input input) {
+ public Result> getResult(Input> input) {
this.master.doWork(input);
return this.master.getFinalResult();
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java
index ffa64572c..9bfbf200e 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java
@@ -27,7 +27,8 @@ import com.iluwatar.masterworker.ArrayResult;
import com.iluwatar.masterworker.system.systemworkers.ArrayTransposeWorker;
import com.iluwatar.masterworker.system.systemworkers.Worker;
import java.util.ArrayList;
-import java.util.Enumeration;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Class ArrayTransposeMaster extends abstract class {@link Master} and contains definition of
@@ -41,35 +42,33 @@ public class ArrayTransposeMaster extends Master {
@Override
ArrayList setWorkers(int num) {
- ArrayList ws = new ArrayList(num);
- for (int i = 0; i < num; i++) {
- ws.add(new ArrayTransposeWorker(this, i + 1));
- //i+1 will be id
- }
- return ws;
+ //i+1 will be id
+ return IntStream.range(0, num)
+ .mapToObj(i -> new ArrayTransposeWorker(this, i + 1))
+ .collect(Collectors.toCollection(() -> new ArrayList<>(num)));
}
@Override
ArrayResult aggregateData() {
// number of rows in final result is number of rows in any of obtained results from workers
- int rows = ((ArrayResult) this.getAllResultData()
- .get(this.getAllResultData().keys().nextElement())).data.length;
- int columns =
- 0; //number of columns is sum of number of columns in all results obtained from workers
- for (Enumeration e = this.getAllResultData().keys(); e.hasMoreElements(); ) {
- columns += ((ArrayResult) this.getAllResultData().get(e.nextElement())).data[0].length;
+ var allResultData = this.getAllResultData();
+ var rows = ((ArrayResult) allResultData.elements().nextElement()).data.length;
+ var elements = allResultData.elements();
+ var columns = 0; // columns = sum of number of columns in all results obtained from workers
+ while (elements.hasMoreElements()) {
+ columns += ((ArrayResult) elements.nextElement()).data[0].length;
}
- int[][] resultData = new int[rows][columns];
- int columnsDone = 0; //columns aggregated so far
- for (int i = 0; i < this.getExpectedNumResults(); i++) {
+ var resultData = new int[rows][columns];
+ var columnsDone = 0; //columns aggregated so far
+ var workers = this.getWorkers();
+ for (var i = 0; i < this.getExpectedNumResults(); i++) {
//result obtained from ith worker
- int[][] work =
- ((ArrayResult) this.getAllResultData().get(this.getWorkers().get(i).getWorkerId())).data;
- for (int m = 0; m < work.length; m++) {
+ var worker = workers.get(i);
+ var workerId = worker.getWorkerId();
+ var work = ((ArrayResult) allResultData.get(workerId)).data;
+ for (var m = 0; m < work.length; m++) {
//m = row number, n = columns number
- for (int n = 0; n < work[0].length; n++) {
- resultData[m][columnsDone + n] = work[m][n];
- }
+ System.arraycopy(work[m], 0, resultData[m], columnsDone, work[0].length);
}
columnsDone += work[0].length;
}
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 4578752c3..06ea3a8fe 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
@@ -26,8 +26,8 @@ package com.iluwatar.masterworker.system.systemmaster;
import com.iluwatar.masterworker.Input;
import com.iluwatar.masterworker.Result;
import com.iluwatar.masterworker.system.systemworkers.Worker;
-import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.List;
/**
* The abstract Master class which contains private fields numOfWorkers (number of workers), workers
@@ -38,24 +38,24 @@ import java.util.Hashtable;
public abstract class Master {
private final int numOfWorkers;
- private final ArrayList workers;
+ private final List workers;
+ private final Hashtable> allResultData;
private int expectedNumResults;
- private final Hashtable allResultData;
- private Result finalResult;
+ private Result> finalResult;
Master(int numOfWorkers) {
this.numOfWorkers = numOfWorkers;
this.workers = setWorkers(numOfWorkers);
this.expectedNumResults = 0;
- this.allResultData = new Hashtable(numOfWorkers);
+ this.allResultData = new Hashtable<>(numOfWorkers);
this.finalResult = null;
}
- public Result getFinalResult() {
+ public Result> getFinalResult() {
return this.finalResult;
}
- Hashtable getAllResultData() {
+ Hashtable> getAllResultData() {
return this.allResultData;
}
@@ -63,34 +63,41 @@ public abstract class Master {
return this.expectedNumResults;
}
- ArrayList getWorkers() {
+ List getWorkers() {
return this.workers;
}
- abstract ArrayList setWorkers(int num);
+ abstract List setWorkers(int num);
- public void doWork(Input input) {
+ public void doWork(Input> input) {
divideWork(input);
}
- private void divideWork(Input input) {
- ArrayList dividedInput = input.divideData(numOfWorkers);
+ private void divideWork(Input> input) {
+ var dividedInput = input.divideData(numOfWorkers);
if (dividedInput != null) {
this.expectedNumResults = dividedInput.size();
- for (int i = 0; i < this.expectedNumResults; i++) {
+ 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();
+ }
+ for (var i = 0; i < this.expectedNumResults; i++) {
+ try {
+ this.workers.get(i).join();
+ } catch (InterruptedException e) {
+ System.err.println("Error while executing thread");
+ }
}
}
}
- public void receiveData(Result data, Worker w) {
+ public void receiveData(Result> data, Worker w) {
//check if can receive..if yes:
collectResult(data, w.getWorkerId());
}
- private void collectResult(Result data, int workerId) {
+ private void collectResult(Result> data, int workerId) {
this.allResultData.put(workerId, data);
if (this.allResultData.size() == this.expectedNumResults) {
//all data received
@@ -98,5 +105,5 @@ public abstract class Master {
}
}
- abstract Result aggregateData();
+ abstract Result> aggregateData();
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java
index 37d8ba005..3f2da0a0a 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java
@@ -41,12 +41,12 @@ public class ArrayTransposeWorker extends Worker {
@Override
ArrayResult executeOperation() {
//number of rows in result matrix is equal to number of columns in input matrix and vice versa
- ArrayInput arrayInput = (ArrayInput) this.getReceivedData();
- final int rows = arrayInput.data[0].length;
- final int cols = arrayInput.data.length;
- int[][] resultData = new int[rows][cols];
- for (int i = 0; i < cols; i++) {
- for (int j = 0; j < rows; j++) {
+ var arrayInput = (ArrayInput) this.getReceivedData();
+ final var rows = arrayInput.data[0].length;
+ final var cols = arrayInput.data.length;
+ var resultData = new int[rows][cols];
+ for (var i = 0; i < cols; i++) {
+ for (var j = 0; j < rows; j++) {
//flipping element positions along diagonal
resultData[j][i] = arrayInput.data[i][j];
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java
index bfe226ee0..526299645 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java
@@ -35,7 +35,7 @@ import com.iluwatar.masterworker.system.systemmaster.Master;
public abstract class Worker extends Thread {
private final Master master;
private final int workerId;
- private Input receivedData;
+ private Input> receivedData;
Worker(Master master, int id) {
this.master = master;
@@ -47,23 +47,23 @@ public abstract class Worker extends Thread {
return this.workerId;
}
- Input getReceivedData() {
+ Input> getReceivedData() {
return this.receivedData;
}
- public void setReceivedData(Master m, Input i) {
+ public void setReceivedData(Master m, Input> i) {
//check if ready to receive..if yes:
this.receivedData = i;
}
- abstract Result executeOperation();
+ abstract Result> executeOperation();
- private void sendToMaster(Result data) {
+ private void sendToMaster(Result> data) {
this.master.receiveData(data, this);
}
public void run() { //from Thread class
- Result work = executeOperation();
+ var work = executeOperation();
sendToMaster(work);
}
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java
index b5820e2af..1d3c7f0bc 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java
@@ -23,38 +23,39 @@
package com.iluwatar.masterworker;
-import static org.junit.jupiter.api.Assertions.*;
-import java.util.ArrayList;
+import static com.iluwatar.masterworker.ArrayUtilityMethods.matricesSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import java.util.Random;
import org.junit.jupiter.api.Test;
/**
-* Testing divideData method in {@link ArrayInput} class.
-*/
+ * Testing divideData method in {@link ArrayInput} class.
+ */
class ArrayInputTest {
@Test
void divideDataTest() {
- int rows = 10;
- int columns = 10;
- int[][] inputMatrix = new int[rows][columns];
- Random rand = new Random();
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < columns; j++) {
+ var rows = 10;
+ var columns = 10;
+ var inputMatrix = new int[rows][columns];
+ var rand = new Random();
+ for (var i = 0; i < rows; i++) {
+ for (var j = 0; j < columns; j++) {
inputMatrix[i][j] = rand.nextInt(10);
}
}
- ArrayInput i = new ArrayInput(inputMatrix);
- ArrayList table = i.divideData(4);
- int[][] division1 = new int[][] {inputMatrix[0], inputMatrix[1], inputMatrix[2]};
- int[][] division2 = new int[][] {inputMatrix[3], inputMatrix[4], inputMatrix[5]};
- int[][] division3 = new int[][] {inputMatrix[6], inputMatrix[7]};
- int[][] division4 = new int[][] {inputMatrix[8], inputMatrix[9]};
- assertTrue(ArrayUtilityMethods.matricesSame((int[][]) table.get(0).data, division1)
- && ArrayUtilityMethods.matricesSame((int[][]) table.get(1).data, division2)
- && ArrayUtilityMethods.matricesSame((int[][]) table.get(2).data, division3)
- && ArrayUtilityMethods.matricesSame((int[][]) table.get(3).data, division4));
+ var i = new ArrayInput(inputMatrix);
+ var table = i.divideData(4);
+ var division1 = new int[][]{inputMatrix[0], inputMatrix[1], inputMatrix[2]};
+ var division2 = new int[][]{inputMatrix[3], inputMatrix[4], inputMatrix[5]};
+ var division3 = new int[][]{inputMatrix[6], inputMatrix[7]};
+ var division4 = new int[][]{inputMatrix[8], inputMatrix[9]};
+ assertTrue(matricesSame(table.get(0).data, division1)
+ && matricesSame(table.get(1).data, division2)
+ && matricesSame(table.get(2).data, division3)
+ && matricesSame(table.get(3).data, division4));
}
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java
index aae784b52..d25276572 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java
@@ -23,27 +23,27 @@
package com.iluwatar.masterworker;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
-* Testing utility methods in {@link ArrayUtilityMethods} class.
-*/
+ * Testing utility methods in {@link ArrayUtilityMethods} class.
+ */
class ArrayUtilityMethodsTest {
@Test
void arraysSameTest() {
- int[] arr1 = new int[] {1,4,2,6};
- int[] arr2 = new int[] {1,4,2,6};
+ var arr1 = new int[]{1, 4, 2, 6};
+ var arr2 = new int[]{1, 4, 2, 6};
assertTrue(ArrayUtilityMethods.arraysSame(arr1, arr2));
}
@Test
void matricesSameTest() {
- int[][] matrix1 = new int[][] {{1,4,2,6},{5,8,6,7}};
- int[][] matrix2 = new int[][] {{1,4,2,6},{5,8,6,7}};
+ var matrix1 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
+ var matrix2 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
assertTrue(ArrayUtilityMethods.matricesSame(matrix1, matrix2));
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java
index b80d7881f..79838ed35 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java
@@ -23,25 +23,38 @@
package com.iluwatar.masterworker.system;
-import static org.junit.jupiter.api.Assertions.*;
-import org.junit.jupiter.api.Test;
-import com.iluwatar.masterworker.ArrayUtilityMethods;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import com.iluwatar.masterworker.ArrayInput;
import com.iluwatar.masterworker.ArrayResult;
+import com.iluwatar.masterworker.ArrayUtilityMethods;
+import org.junit.jupiter.api.Test;
/**
-* Testing getResult method in {@link ArrayTransposeMasterWorker} class.
-*/
+ * Testing getResult method in {@link ArrayTransposeMasterWorker} class.
+ */
class ArrayTransposeMasterWorkerTest {
@Test
void getResultTest() {
- ArrayTransposeMasterWorker atmw = new ArrayTransposeMasterWorker();
- int[][] matrix = new int[][] {{1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}};
- int[][] matrixTranspose = new int[][] {{1,1,1,1,1}, {2,2,2,2,2}, {3,3,3,3,3}, {4,4,4,4,4}, {5,5,5,5,5}};
- ArrayInput i = new ArrayInput(matrix);
- ArrayResult r = (ArrayResult) atmw.getResult(i);
+ var atmw = new ArrayTransposeMasterWorker();
+ var matrix = new int[][]{
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5}
+ };
+ var matrixTranspose = new int[][]{
+ {1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3},
+ {4, 4, 4, 4, 4},
+ {5, 5, 5, 5, 5}
+ };
+ var i = new ArrayInput(matrix);
+ var r = (ArrayResult) atmw.getResult(i);
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
- }
+ }
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java
index 3e5f581b9..c4b210643 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java
@@ -23,29 +23,29 @@
package com.iluwatar.masterworker.system.systemworkers;
-import static org.junit.jupiter.api.Assertions.*;
-import org.junit.jupiter.api.Test;
-import com.iluwatar.masterworker.ArrayUtilityMethods;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import com.iluwatar.masterworker.ArrayInput;
-import com.iluwatar.masterworker.ArrayResult;
+import com.iluwatar.masterworker.ArrayUtilityMethods;
import com.iluwatar.masterworker.system.systemmaster.ArrayTransposeMaster;
+import org.junit.jupiter.api.Test;
/**
-* Testing executeOperation method in {@link ArrayTransposeWorker} class.
-*/
+ * Testing executeOperation method in {@link ArrayTransposeWorker} class.
+ */
class ArrayTransposeWorkerTest {
@Test
void executeOperationTest() {
- ArrayTransposeMaster atm = new ArrayTransposeMaster(1);
- ArrayTransposeWorker atw = new ArrayTransposeWorker(atm, 1);
- int[][] matrix = new int[][] {{2,4}, {3,5}};
- int[][] matrixTranspose = new int[][] {{2,3}, {4,5}};
- ArrayInput i = new ArrayInput(matrix);
+ var atm = new ArrayTransposeMaster(1);
+ var atw = new ArrayTransposeWorker(atm, 1);
+ var matrix = new int[][]{{2, 4}, {3, 5}};
+ var matrixTranspose = new int[][]{{2, 3}, {4, 5}};
+ var i = new ArrayInput(matrix);
atw.setReceivedData(atm, i);
- ArrayResult r = atw.executeOperation();
+ var r = atw.executeOperation();
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
}
-
+
}
diff --git a/mediator/pom.xml b/mediator/pom.xml
index 23d28726b..ae802a349 100644
--- a/mediator/pom.xml
+++ b/mediator/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmediator
diff --git a/mediator/src/main/java/com/iluwatar/mediator/Action.java b/mediator/src/main/java/com/iluwatar/mediator/Action.java
index 17613b5ab..60ce3949a 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/Action.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/Action.java
@@ -27,7 +27,6 @@ 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"),
diff --git a/mediator/src/main/java/com/iluwatar/mediator/App.java b/mediator/src/main/java/com/iluwatar/mediator/App.java
index 9dbedb4ab..0e9021c0d 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/App.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/App.java
@@ -55,10 +55,10 @@ public class App {
// create party and members
Party party = new PartyImpl();
- Hobbit hobbit = new Hobbit();
- Wizard wizard = new Wizard();
- Rogue rogue = new Rogue();
- Hunter hunter = new Hunter();
+ var hobbit = new Hobbit();
+ var wizard = new Wizard();
+ var rogue = new Rogue();
+ var hunter = new Hunter();
// add party members
party.addMember(hobbit);
diff --git a/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java b/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
index 6384a2187..f842a0f39 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
@@ -39,7 +39,7 @@ public class PartyImpl implements Party {
@Override
public void act(PartyMember actor, Action action) {
- for (PartyMember member : members) {
+ for (var member : members) {
if (!member.equals(actor)) {
member.partyAction(action);
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
index 3a55d51d8..558ec4907 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
@@ -25,16 +25,15 @@ package com.iluwatar.mediator;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
- *
* Application test
- *
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
index 5d2446545..d25562f84 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
@@ -43,10 +43,10 @@ public class PartyImplTest {
*/
@Test
public void testPartyAction() {
- final PartyMember partyMember1 = mock(PartyMember.class);
- final PartyMember partyMember2 = mock(PartyMember.class);
+ final var partyMember1 = mock(PartyMember.class);
+ final var partyMember2 = mock(PartyMember.class);
- final PartyImpl party = new PartyImpl();
+ final var party = new PartyImpl();
party.addMember(partyMember1);
party.addMember(partyMember2);
@@ -58,7 +58,6 @@ public class PartyImplTest {
verify(partyMember2).partyAction(Action.GOLD);
verifyNoMoreInteractions(partyMember1, partyMember2);
-
}
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
index 01e855179..a0e722cfd 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
@@ -23,24 +23,24 @@
package com.iluwatar.mediator;
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.AppenderBase;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.Supplier;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.slf4j.LoggerFactory;
+
/**
* Date: 12/19/15 - 10:13 PM
*
@@ -48,12 +48,12 @@ import static org.mockito.Mockito.verify;
*/
public class PartyMemberTest {
- static Collection[]> dataProvider() {
- return List.of(
- new Supplier[]{Hobbit::new},
- new Supplier[]{Hunter::new},
- new Supplier[]{Rogue::new},
- new Supplier[]{Wizard::new}
+ static Stream dataProvider() {
+ return Stream.of(
+ Arguments.of((Supplier) Hobbit::new),
+ Arguments.of((Supplier) Hunter::new),
+ Arguments.of((Supplier) Rogue::new),
+ Arguments.of((Supplier) Wizard::new)
);
}
@@ -75,9 +75,9 @@ public class PartyMemberTest {
@ParameterizedTest
@MethodSource("dataProvider")
public void testPartyAction(Supplier memberSupplier) {
- final PartyMember member = memberSupplier.get();
+ final var member = memberSupplier.get();
- for (final Action action : Action.values()) {
+ for (final var action : Action.values()) {
member.partyAction(action);
assertEquals(member.toString() + " " + action.getDescription(), appender.getLastMessage());
}
@@ -91,16 +91,16 @@ public class PartyMemberTest {
@ParameterizedTest
@MethodSource("dataProvider")
public void testAct(Supplier memberSupplier) {
- final PartyMember member = memberSupplier.get();
+ final var member = memberSupplier.get();
member.act(Action.GOLD);
assertEquals(0, appender.getLogSize());
- final Party party = mock(Party.class);
+ final var party = mock(Party.class);
member.joinedParty(party);
assertEquals(member.toString() + " joins the party", appender.getLastMessage());
- for (final Action action : Action.values()) {
+ for (final var action : Action.values()) {
member.act(action);
assertEquals(member.toString() + " " + action.toString(), appender.getLastMessage());
verify(party).act(member, action);
@@ -114,16 +114,16 @@ public class PartyMemberTest {
*/
@ParameterizedTest
@MethodSource("dataProvider")
- public void testToString(Supplier memberSupplier) throws Exception {
- final PartyMember member = memberSupplier.get();
- final Class extends PartyMember> memberClass = member.getClass();
+ public void testToString(Supplier memberSupplier) {
+ final var member = memberSupplier.get();
+ final var memberClass = member.getClass();
assertEquals(memberClass.getSimpleName(), member.toString());
}
- private class InMemoryAppender extends AppenderBase {
+ private static class InMemoryAppender extends AppenderBase {
private final List log = new LinkedList<>();
- public InMemoryAppender(Class clazz) {
+ public InMemoryAppender(Class> clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
start();
}
diff --git a/memento/README.md b/memento/README.md
index b8d95b72a..720d0f21d 100644
--- a/memento/README.md
+++ b/memento/README.md
@@ -9,24 +9,30 @@ tags:
---
## Also known as
+
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.
+> 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.
+> 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).
+> 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**
@@ -34,24 +40,17 @@ 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;
- }
+ SUN("sun"),
+ RED_GIANT("red giant"),
+ WHITE_DWARF("white dwarf"),
+ SUPERNOVA("supernova"),
+ DEAD("dead star");
+ ...
}
```
-Next let's jump straight to the essentials. Here's the star class along with the mementos that we need manipulate.
+Next, let's jump straight to the essentials. Here's the `Star` class along with the mementos that we
+need manipulate. Especially pay attention to `getMemento` and `setMemento` methods.
```java
public interface StarMemento {
@@ -95,8 +94,7 @@ public class Star {
}
StarMemento getMemento() {
-
- StarMementoInternal state = new StarMementoInternal();
+ var state = new StarMementoInternal();
state.setAgeYears(ageYears);
state.setMassTons(massTons);
state.setType(type);
@@ -104,8 +102,7 @@ public class Star {
}
void setMemento(StarMemento memento) {
-
- StarMementoInternal state = (StarMementoInternal) memento;
+ var state = (StarMementoInternal) memento;
this.type = state.getType();
this.ageYears = state.getAgeYears();
this.massTons = state.getMassTons();
@@ -122,29 +119,8 @@ public class Star {
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;
- }
+ // setters and getters ->
+ ...
}
}
```
@@ -152,8 +128,8 @@ public class Star {
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);
+ var states = new Stack<>();
+ var star = new Star(StarType.SUN, 10000000, 500000);
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
@@ -171,27 +147,33 @@ And finally here's how we use the mementos to store and restore star states.
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
```
+Program output:
+
+```
+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
+

## Applicability
+
Use the Memento pattern when
-* a snapshot of an object's state must be saved so that it can be restored to that state later, and
-* a direct interface to obtaining the state would expose implementation details and break the object's encapsulation
+* A snapshot of an object's state must be saved so that it can be restored to that state later, and
+* A direct interface to obtaining the state would expose implementation details and break the
+object's encapsulation
## Real world examples
diff --git a/memento/pom.xml b/memento/pom.xml
index 70121cea3..596883819 100644
--- a/memento/pom.xml
+++ b/memento/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmemento
diff --git a/memento/src/main/java/com/iluwatar/memento/App.java b/memento/src/main/java/com/iluwatar/memento/App.java
index af57d8d4a..77cc0f214 100644
--- a/memento/src/main/java/com/iluwatar/memento/App.java
+++ b/memento/src/main/java/com/iluwatar/memento/App.java
@@ -52,9 +52,9 @@ public class App {
* Program entry point.
*/
public static void main(String[] args) {
- Stack states = new Stack<>();
+ var states = new Stack();
- Star star = new Star(StarType.SUN, 10000000, 500000);
+ var star = new Star(StarType.SUN, 10000000, 500000);
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
diff --git a/memento/src/main/java/com/iluwatar/memento/Star.java b/memento/src/main/java/com/iluwatar/memento/Star.java
index ebeea28f2..af1c98b04 100644
--- a/memento/src/main/java/com/iluwatar/memento/Star.java
+++ b/memento/src/main/java/com/iluwatar/memento/Star.java
@@ -70,22 +70,18 @@ public class Star {
}
StarMemento getMemento() {
-
- StarMementoInternal state = new StarMementoInternal();
+ var state = new StarMementoInternal();
state.setAgeYears(ageYears);
state.setMassTons(massTons);
state.setType(type);
return state;
-
}
void setMemento(StarMemento memento) {
-
- StarMementoInternal state = (StarMementoInternal) memento;
+ var state = (StarMementoInternal) memento;
this.type = state.getType();
this.ageYears = state.getAgeYears();
this.massTons = state.getMassTons();
-
}
@Override
diff --git a/memento/src/main/java/com/iluwatar/memento/StarType.java b/memento/src/main/java/com/iluwatar/memento/StarType.java
index 339f05f9f..58fd935f2 100644
--- a/memento/src/main/java/com/iluwatar/memento/StarType.java
+++ b/memento/src/main/java/com/iluwatar/memento/StarType.java
@@ -27,9 +27,11 @@ package com.iluwatar.memento;
* StarType enumeration.
*/
public enum StarType {
-
- SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
- "dead star"), UNDEFINED("");
+ SUN("sun"),
+ RED_GIANT("red giant"),
+ WHITE_DWARF("white dwarf"),
+ SUPERNOVA("supernova"),
+ DEAD("dead star");
private final String title;
diff --git a/memento/src/test/java/com/iluwatar/memento/AppTest.java b/memento/src/test/java/com/iluwatar/memento/AppTest.java
index 074de2c41..2d8a518e2 100644
--- a/memento/src/test/java/com/iluwatar/memento/AppTest.java
+++ b/memento/src/test/java/com/iluwatar/memento/AppTest.java
@@ -25,16 +25,15 @@ package com.iluwatar.memento;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
- *
* Application test
- *
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/memento/src/test/java/com/iluwatar/memento/StarTest.java b/memento/src/test/java/com/iluwatar/memento/StarTest.java
index 40adb99e1..aab59e9c3 100644
--- a/memento/src/test/java/com/iluwatar/memento/StarTest.java
+++ b/memento/src/test/java/com/iluwatar/memento/StarTest.java
@@ -23,10 +23,10 @@
package com.iluwatar.memento;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/20/15 - 10:08 AM
*
@@ -39,7 +39,7 @@ public class StarTest {
*/
@Test
public void testTimePasses() {
- final Star star = new Star(StarType.SUN, 1, 2);
+ final var star = new Star(StarType.SUN, 1, 2);
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
star.timePasses();
@@ -66,16 +66,16 @@ public class StarTest {
*/
@Test
public void testSetMemento() {
- final Star star = new Star(StarType.SUN, 1, 2);
- final StarMemento firstMemento = star.getMemento();
+ final var star = new Star(StarType.SUN, 1, 2);
+ final var firstMemento = star.getMemento();
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
star.timePasses();
- final StarMemento secondMemento = star.getMemento();
+ final var secondMemento = star.getMemento();
assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
star.timePasses();
- final StarMemento thirdMemento = star.getMemento();
+ final var thirdMemento = star.getMemento();
assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
star.timePasses();
diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml
index a8ef230e8..98c9dddfe 100644
--- a/model-view-controller/pom.xml
+++ b/model-view-controller/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmodel-view-controller
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java
index 4607f009d..cabc4d96f 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java
@@ -47,9 +47,9 @@ public class App {
*/
public static void main(String[] args) {
// create model, view and controller
- GiantModel giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
- GiantView view = new GiantView();
- GiantController controller = new GiantController(giant, view);
+ var giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ var view = new GiantView();
+ var controller = new GiantController(giant, view);
// initial display
controller.updateView();
// controller receives some interactions that affect the giant
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java
index 2b7ca3999..64bae6e51 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java
@@ -27,8 +27,9 @@ package com.iluwatar.model.view.controller;
* Fatigue enumeration.
*/
public enum Fatigue {
-
- ALERT("alert"), TIRED("tired"), SLEEPING("sleeping");
+ ALERT("alert"),
+ TIRED("tired"),
+ SLEEPING("sleeping");
private final String title;
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java
index 9acb49db4..f96113574 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java
@@ -36,6 +36,7 @@ public class GiantController {
this.view = view;
}
+ @SuppressWarnings("UnusedReturnValue")
public Health getHealth() {
return giant.getHealth();
}
@@ -44,6 +45,7 @@ public class GiantController {
this.giant.setHealth(health);
}
+ @SuppressWarnings("UnusedReturnValue")
public Fatigue getFatigue() {
return giant.getFatigue();
}
@@ -52,6 +54,7 @@ public class GiantController {
this.giant.setFatigue(fatigue);
}
+ @SuppressWarnings("UnusedReturnValue")
public Nourishment getNourishment() {
return giant.getNourishment();
}
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java
index a8346b9c7..f15585cdd 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java
@@ -27,8 +27,9 @@ package com.iluwatar.model.view.controller;
* Health enumeration.
*/
public enum Health {
-
- HEALTHY("healthy"), WOUNDED("wounded"), DEAD("dead");
+ HEALTHY("healthy"),
+ WOUNDED("wounded"),
+ DEAD("dead");
private final String title;
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java
index c61d2de79..ba00c38c5 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java
@@ -27,8 +27,9 @@ package com.iluwatar.model.view.controller;
* Nourishment enumeration.
*/
public enum Nourishment {
-
- SATURATED("saturated"), HUNGRY("hungry"), STARVING("starving");
+ SATURATED("saturated"),
+ HUNGRY("hungry"),
+ STARVING("starving");
private final String title;
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
index e6d2d9a0b..a0fdbf3ba 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
@@ -25,16 +25,15 @@ package com.iluwatar.model.view.controller;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
- *
* Application test
- *
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
index a2f42a80d..d106d0944 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
@@ -23,13 +23,13 @@
package com.iluwatar.model.view.controller;
-import org.junit.jupiter.api.Test;
-
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/20/15 - 2:19 PM
*
@@ -42,19 +42,20 @@ public class GiantControllerTest {
*/
@Test
public void testSetHealth() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
- for (final Health health : Health.values()) {
+ for (final var health : Health.values()) {
controller.setHealth(health);
verify(model).setHealth(health);
verifyZeroInteractions(view);
}
controller.getHealth();
+ //noinspection ResultOfMethodCallIgnored
verify(model).getHealth();
verifyNoMoreInteractions(model, view);
@@ -65,19 +66,20 @@ public class GiantControllerTest {
*/
@Test
public void testSetFatigue() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
- for (final Fatigue fatigue : Fatigue.values()) {
+ for (final var fatigue : Fatigue.values()) {
controller.setFatigue(fatigue);
verify(model).setFatigue(fatigue);
verifyZeroInteractions(view);
}
controller.getFatigue();
+ //noinspection ResultOfMethodCallIgnored
verify(model).getFatigue();
verifyNoMoreInteractions(model, view);
@@ -88,19 +90,20 @@ public class GiantControllerTest {
*/
@Test
public void testSetNourishment() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
- for (final Nourishment nourishment : Nourishment.values()) {
+ for (final var nourishment : Nourishment.values()) {
controller.setNourishment(nourishment);
verify(model).setNourishment(nourishment);
verifyZeroInteractions(view);
}
controller.getNourishment();
+ //noinspection ResultOfMethodCallIgnored
verify(model).getNourishment();
verifyNoMoreInteractions(model, view);
@@ -108,9 +111,9 @@ public class GiantControllerTest {
@Test
public void testUpdateView() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
index a566010cd..677ab436e 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
@@ -23,10 +23,10 @@
package com.iluwatar.model.view.controller;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/20/15 - 2:10 PM
*
@@ -39,12 +39,13 @@ public class GiantModelTest {
*/
@Test
public void testSetHealth() {
- final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
assertEquals(Health.HEALTHY, model.getHealth());
- for (final Health health : Health.values()) {
+ var messageFormat = "The giant looks %s, alert and saturated.";
+ for (final var health : Health.values()) {
model.setHealth(health);
assertEquals(health, model.getHealth());
- assertEquals("The giant looks " + health.toString() + ", alert and saturated.", model.toString());
+ assertEquals(String.format(messageFormat, health), model.toString());
}
}
@@ -53,12 +54,13 @@ public class GiantModelTest {
*/
@Test
public void testSetFatigue() {
- final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
assertEquals(Fatigue.ALERT, model.getFatigue());
- for (final Fatigue fatigue : Fatigue.values()) {
+ var messageFormat = "The giant looks healthy, %s and saturated.";
+ for (final var fatigue : Fatigue.values()) {
model.setFatigue(fatigue);
assertEquals(fatigue, model.getFatigue());
- assertEquals("The giant looks healthy, " + fatigue.toString() + " and saturated.", model.toString());
+ assertEquals(String.format(messageFormat, fatigue), model.toString());
}
}
@@ -67,12 +69,13 @@ public class GiantModelTest {
*/
@Test
public void testSetNourishment() {
- final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
assertEquals(Nourishment.SATURATED, model.getNourishment());
- for (final Nourishment nourishment : Nourishment.values()) {
+ var messageFormat = "The giant looks healthy, alert and %s.";
+ for (final var nourishment : Nourishment.values()) {
model.setNourishment(nourishment);
assertEquals(nourishment, model.getNourishment());
- assertEquals("The giant looks healthy, alert and " + nourishment.toString() + ".", model.toString());
+ assertEquals(String.format(messageFormat, nourishment), model.toString());
}
}
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java
index 9d6421d13..c6314c1dd 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java
@@ -31,7 +31,6 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.LinkedList;
import java.util.List;
-
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -62,9 +61,9 @@ public class GiantViewTest {
*/
@Test
public void testDisplayGiant() {
- final GiantView view = new GiantView();
+ final var view = new GiantView();
- final GiantModel model = mock(GiantModel.class);
+ final var model = mock(GiantModel.class);
view.displayGiant(model);
assertEquals(model.toString(), appender.getLastMessage());
@@ -74,10 +73,10 @@ public class GiantViewTest {
/**
* Logging Appender Implementation
*/
- public class InMemoryAppender extends AppenderBase {
+ public static class InMemoryAppender extends AppenderBase {
private final List log = new LinkedList<>();
- public InMemoryAppender(Class clazz) {
+ public InMemoryAppender(Class> clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
start();
}
diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml
index 97b47f82c..ee309f292 100644
--- a/model-view-presenter/pom.xml
+++ b/model-view-presenter/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmodel-view-presentermodel-view-presenter
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java
index 43984e847..ac3b83927 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java
@@ -44,9 +44,9 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- FileLoader loader = new FileLoader();
- FileSelectorJFrame frame = new FileSelectorJFrame();
- FileSelectorPresenter presenter = new FileSelectorPresenter(frame);
+ var loader = new FileLoader();
+ var frame = new FileSelectorJFrame();
+ var presenter = new FileSelectorPresenter(frame);
presenter.setLoader(loader);
presenter.start();
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
index 9c01b2044..7dd5dd215 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
@@ -27,6 +27,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Serializable;
+import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,18 +60,11 @@ public class FileLoader implements Serializable {
* Loads the data of the file specified.
*/
public String loadData() {
- String dataFileName = this.fileName;
- try (BufferedReader br = new BufferedReader(new FileReader(new File(dataFileName)))) {
- StringBuilder sb = new StringBuilder();
- String line;
-
- while ((line = br.readLine()) != null) {
- sb.append(line).append('\n');
- }
-
+ var dataFileName = this.fileName;
+ try (var br = new BufferedReader(new FileReader(new File(dataFileName)))) {
+ var result = br.lines().collect(Collectors.joining("\n"));
this.loaded = true;
-
- return sb.toString();
+ return result;
} catch (Exception e) {
LOGGER.error("File {} does not exist", dataFileName);
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
index 6c4df5231..f59bcdf6f 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
@@ -23,9 +23,13 @@
package com.iluwatar.model.view.presenter;
+import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
+import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
+
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
@@ -55,16 +59,6 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
*/
private final JButton cancel;
- /**
- * The information label.
- */
- private final JLabel info;
-
- /**
- * The contents label.
- */
- private final JLabel contents;
-
/**
* The text field for giving the name of the file that we want to open.
*/
@@ -75,11 +69,6 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
*/
private final JTextArea area;
- /**
- * The panel that will hold our widgets.
- */
- private final JPanel panel;
-
/**
* The Presenter component that the frame will interact with.
*/
@@ -95,14 +84,14 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
*/
public FileSelectorJFrame() {
super("File Loader");
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null);
this.setBounds(100, 100, 500, 200);
/*
* Add the panel.
*/
- this.panel = new JPanel();
+ var panel = new JPanel();
panel.setLayout(null);
this.add(panel);
panel.setBounds(0, 0, 500, 200);
@@ -111,32 +100,32 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/*
* Add the info label.
*/
- this.info = new JLabel("File Name :");
- this.panel.add(info);
+ var info = new JLabel("File Name :");
+ panel.add(info);
info.setBounds(30, 10, 100, 30);
/*
* Add the contents label.
*/
- this.contents = new JLabel("File contents :");
- this.panel.add(contents);
- this.contents.setBounds(30, 100, 120, 30);
+ var contents = new JLabel("File contents :");
+ panel.add(contents);
+ contents.setBounds(30, 100, 120, 30);
/*
* Add the text field.
*/
this.input = new JTextField(100);
- this.panel.add(input);
+ panel.add(input);
this.input.setBounds(150, 15, 200, 20);
/*
* Add the text area.
*/
this.area = new JTextArea(100, 100);
- JScrollPane pane = new JScrollPane(area);
- pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
- pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
- this.panel.add(pane);
+ var pane = new JScrollPane(area);
+ pane.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ pane.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
+ panel.add(pane);
this.area.setEditable(false);
pane.setBounds(150, 100, 250, 80);
@@ -144,7 +133,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
* Add the OK button.
*/
this.ok = new JButton("OK");
- this.panel.add(ok);
+ panel.add(ok);
this.ok.setBounds(250, 50, 100, 25);
this.ok.addActionListener(this);
@@ -152,7 +141,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
* Add the cancel button.
*/
this.cancel = new JButton("Cancel");
- this.panel.add(this.cancel);
+ panel.add(this.cancel);
this.cancel.setBounds(380, 50, 100, 25);
this.cancel.addActionListener(this);
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
index 6fa95b125..5cd6580d9 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
@@ -91,7 +91,7 @@ public class FileSelectorPresenter implements Serializable {
}
if (loader.fileExists()) {
- String data = loader.loadData();
+ var data = loader.loadData();
view.displayData(data);
} else {
view.showMessage("The file specified does not exist.");
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
index 00e35ae1b..6529cd18d 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
@@ -25,17 +25,16 @@ package com.iluwatar.model.view.presenter;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
- *
* Application test
- *
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
index a63ca5ae8..3787cd20b 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
@@ -23,10 +23,10 @@
package com.iluwatar.model.view.presenter;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertNull;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/21/15 - 12:12 PM
*
@@ -35,8 +35,8 @@ import static org.junit.jupiter.api.Assertions.assertNull;
public class FileLoaderTest {
@Test
- public void testLoadData() throws Exception {
- final FileLoader fileLoader = new FileLoader();
+ public void testLoadData() {
+ final var fileLoader = new FileLoader();
fileLoader.setFileName("non-existing-file");
assertNull(fileLoader.loadData());
}
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
index fdc19398d..238d3a135 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
@@ -23,14 +23,14 @@
package com.iluwatar.model.view.presenter;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
/**
* This test case is responsible for testing our application by taking advantage of the
* Model-View-Controller architectural pattern.
@@ -79,7 +79,7 @@ public class FileSelectorPresenterTest {
*/
@Test
public void updateFileNameToLoader() {
- String expectedFile = "Stamatis";
+ var expectedFile = "Stamatis";
stub.setFileName(expectedFile);
presenter.start();
diff --git a/module/pom.xml b/module/pom.xml
index 25ad707eb..2dc3fe340 100644
--- a/module/pom.xml
+++ b/module/pom.xml
@@ -23,38 +23,39 @@
THE SOFTWARE.
-->
-
- 4.0.0
-
- com.iluwatar
- java-design-patterns
- 1.23.0-SNAPSHOT
-
- module
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
-
-
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
-
-
-
- com.iluwatar.module.App
-
-
-
-
-
-
-
-
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.24.0-SNAPSHOT
+
+ module
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.module.App
+
+
+
+
+
+
+
+
diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java
index d50693440..0f89d8f89 100644
--- a/module/src/main/java/com/iluwatar/module/App.java
+++ b/module/src/main/java/com/iluwatar/module/App.java
@@ -67,10 +67,8 @@ public class App {
/**
* Following method is main executor.
- *
- * @param args for providing default program arguments
*/
- public static void execute(final String... args) {
+ public static void execute() {
/* Send logs on file system */
fileLoggerModule.printString(MESSAGE);
@@ -90,7 +88,7 @@ public class App {
*/
public static void main(final String... args) throws FileNotFoundException {
prepare();
- execute(args);
+ execute();
unprepare();
}
}
diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java
index 88fa4c68c..4bf72fcb0 100644
--- a/module/src/test/java/com/iluwatar/module/AppTest.java
+++ b/module/src/test/java/com/iluwatar/module/AppTest.java
@@ -23,18 +23,19 @@
package com.iluwatar.module;
-import org.junit.jupiter.api.Test;
-
import java.io.FileNotFoundException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
/**
* Tests that Module example runs without errors.
*/
-public final class AppTest {
+final class AppTest {
@Test
- public void test() throws FileNotFoundException {
- final String[] args = {};
- App.main(args);
+ void shouldExecuteWithoutException() {
+ assertDoesNotThrow((Executable) App::main);
}
}
diff --git a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java
index 646bba642..9899d4c5c 100644
--- a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java
+++ b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java
@@ -23,17 +23,16 @@
package com.iluwatar.module;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* The Module pattern can be considered a Creational pattern and a Structural pattern. It manages
@@ -58,13 +57,13 @@ public final class FileLoggerModuleTest {
/**
* This test verify that 'MESSAGE' is perfectly printed in output file
- *
+ *
* @throws IOException if program is not able to find log files (output.txt and error.txt)
*/
@Test
public void testFileMessage() throws IOException {
- /* Get singletong instance of File Logger Module */
+ /* Get singleton instance of File Logger Module */
final var fileLoggerModule = FileLoggerModule.getSingleton();
/* Prepare the essential sub modules, to perform the sequence of jobs */
@@ -82,13 +81,13 @@ public final class FileLoggerModuleTest {
/**
* This test verify that nothing is printed in output file
- *
+ *
* @throws IOException if program is not able to find log files (output.txt and error.txt)
*/
@Test
public void testNoFileMessage() throws IOException {
- /* Get singletong instance of File Logger Module */
+ /* Get singleton instance of File Logger Module */
final var fileLoggerModule = FileLoggerModule.getSingleton();
/* Prepare the essential sub modules, to perform the sequence of jobs */
@@ -103,14 +102,14 @@ public final class FileLoggerModuleTest {
/**
* This test verify that 'ERROR' is perfectly printed in error file
- *
+ *
* @throws FileNotFoundException if program is not able to find log files (output.txt and
- * error.txt)
+ * error.txt)
*/
@Test
public void testFileErrorMessage() throws FileNotFoundException {
- /* Get singletong instance of File Logger Module */
+ /* Get singleton instance of File Logger Module */
final var fileLoggerModule = FileLoggerModule.getSingleton();
/* Prepare the essential sub modules, to perform the sequence of jobs */
@@ -122,20 +121,20 @@ public final class FileLoggerModuleTest {
/* Test if 'Message' is printed in file */
assertEquals(ERROR, readFirstLine(ERROR_FILE));
- /* Unprepare to cleanup the modules */
+ /* Un-prepare to cleanup the modules */
fileLoggerModule.unprepare();
}
/**
* This test verify that nothing is printed in error file
- *
+ *
* @throws FileNotFoundException if program is not able to find log files (output.txt and
- * error.txt)
+ * error.txt)
*/
@Test
public void testNoFileErrorMessage() throws FileNotFoundException {
- /* Get singletong instance of File Logger Module */
+ /* Get singleton instance of File Logger Module */
final var fileLoggerModule = FileLoggerModule.getSingleton();
/* Prepare the essential sub modules, to perform the sequence of jobs */
@@ -150,11 +149,11 @@ public final class FileLoggerModuleTest {
/**
* Utility method to read first line of a file
- *
+ *
* @param file as file name to be read
* @return a string value as first line in file
*/
- private static final String readFirstLine(final String file) {
+ private static String readFirstLine(final String file) {
String firstLine = null;
try (var bufferedReader = new BufferedReader(new FileReader(file))) {
diff --git a/monad/pom.xml b/monad/pom.xml
index f553c3079..2c21a28b3 100644
--- a/monad/pom.xml
+++ b/monad/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmonad
diff --git a/monad/src/main/java/com/iluwatar/monad/App.java b/monad/src/main/java/com/iluwatar/monad/App.java
index ccb42edd0..bb3315064 100644
--- a/monad/src/main/java/com/iluwatar/monad/App.java
+++ b/monad/src/main/java/com/iluwatar/monad/App.java
@@ -41,9 +41,8 @@ import org.slf4j.LoggerFactory;
* instance of a plain object with {@link Validator#of(Object)} and validates it {@link
* Validator#validate(Function, Predicate, String)} against given predicates.
*
- *
As a validation result {@link Validator#get()} it either returns valid object {@link
- * Validator#t} or throws a list of exceptions {@link Validator#exceptions} collected during
- * validation.
+ *
As a validation result {@link Validator#get()} either returns valid object
+ * or throws {@link IllegalStateException} with list of exceptions collected during validation.
*/
public class App {
@@ -55,10 +54,10 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- User user = new User("user", 24, Sex.FEMALE, "foobar.com");
+ var user = new User("user", 24, Sex.FEMALE, "foobar.com");
LOGGER.info(Validator.of(user).validate(User::getName, Objects::nonNull, "name is null")
.validate(User::getName, name -> !name.isEmpty(), "name is empty")
- .validate(User::getEmail, email -> !email.contains("@"), "email doesn't containt '@'")
+ .validate(User::getEmail, email -> !email.contains("@"), "email doesn't contains '@'")
.validate(User::getAge, age -> age > 20 && age < 30, "age isn't between...").get()
.toString());
}
diff --git a/monad/src/main/java/com/iluwatar/monad/Validator.java b/monad/src/main/java/com/iluwatar/monad/Validator.java
index 2d1f1bdab..47acc8a42 100644
--- a/monad/src/main/java/com/iluwatar/monad/Validator.java
+++ b/monad/src/main/java/com/iluwatar/monad/Validator.java
@@ -85,18 +85,21 @@ public class Validator {
}
/**
- * Extension for the {@link Validator#validate(Function, Predicate, String)} method, dedicated for
- * objects, that need to be projected before requested validation.
+ * Extension for the {@link Validator#validate(Predicate, String)} method, dedicated for objects,
+ * that need to be projected before requested validation.
*
* @param projection function that gets an objects, and returns projection representing element to
* be validated.
- * @param validation see {@link Validator#validate(Function, Predicate, String)}
- * @param message see {@link Validator#validate(Function, Predicate, String)}
- * @param see {@link Validator#validate(Function, Predicate, String)}
+ * @param validation see {@link Validator#validate(Predicate, String)}
+ * @param message see {@link Validator#validate(Predicate, String)}
+ * @param see {@link Validator#validate(Predicate, String)}
* @return this
*/
- public Validator validate(Function projection, Predicate validation,
- String message) {
+ public Validator validate(
+ Function projection,
+ Predicate validation,
+ String message
+ ) {
return validate(projection.andThen(validation::test)::apply, message);
}
@@ -110,7 +113,7 @@ public class Validator {
if (exceptions.isEmpty()) {
return obj;
}
- IllegalStateException e = new IllegalStateException();
+ var e = new IllegalStateException();
exceptions.forEach(e::addSuppressed);
throw e;
}
diff --git a/monad/src/test/java/com/iluwatar/monad/AppTest.java b/monad/src/test/java/com/iluwatar/monad/AppTest.java
index f4d89a7cd..d56270173 100644
--- a/monad/src/test/java/com/iluwatar/monad/AppTest.java
+++ b/monad/src/test/java/com/iluwatar/monad/AppTest.java
@@ -32,8 +32,7 @@ public class AppTest {
@Test
public void testMain() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/monad/src/test/java/com/iluwatar/monad/MonadTest.java b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
index d1bdd7487..afd5b50f8 100644
--- a/monad/src/test/java/com/iluwatar/monad/MonadTest.java
+++ b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
@@ -23,13 +23,12 @@
package com.iluwatar.monad;
-import org.junit.jupiter.api.Test;
-
-import java.util.Objects;
-
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.util.Objects;
+import org.junit.jupiter.api.Test;
+
/**
* Test for Monad Pattern
*/
@@ -37,27 +36,33 @@ public class MonadTest {
@Test
public void testForInvalidName() {
- User tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
- assertThrows(IllegalStateException.class, () -> {
- Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null").get();
- });
+ var tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
+ assertThrows(
+ IllegalStateException.class,
+ () -> Validator.of(tom)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .get()
+ );
}
@Test
public void testForInvalidAge() {
- User john = new User("John", 17, Sex.MALE, "john@qwe.bar");
- assertThrows(IllegalStateException.class, () -> {
- Validator.of(john).validate(User::getName, Objects::nonNull, "name cannot be null")
- .validate(User::getAge, age -> age > 21, "user is underaged")
- .get();
- });
+ var john = new User("John", 17, Sex.MALE, "john@qwe.bar");
+ assertThrows(
+ IllegalStateException.class,
+ () -> Validator.of(john)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underage")
+ .get()
+ );
}
@Test
public void testForValid() {
- User sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
- User validated = Validator.of(sarah).validate(User::getName, Objects::nonNull, "name cannot be null")
- .validate(User::getAge, age -> age > 21, "user is underaged")
+ var sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
+ var validated = Validator.of(sarah)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underage")
.validate(User::getSex, sex -> sex == Sex.FEMALE, "user is not female")
.validate(User::getEmail, email -> email.contains("@"), "email does not contain @ sign")
.get();
diff --git a/monostate/pom.xml b/monostate/pom.xml
index 0e51fc700..02e271931 100644
--- a/monostate/pom.xml
+++ b/monostate/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmonostate
diff --git a/monostate/src/main/java/com/iluwatar/monostate/App.java b/monostate/src/main/java/com/iluwatar/monostate/App.java
index 64cb38461..9f5b2c173 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/App.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/App.java
@@ -30,7 +30,7 @@ package com.iluwatar.monostate;
*
*
In the following example, The {@link LoadBalancer} class represents the app's logic. It
* contains a series of Servers, which can handle requests of type {@link Request}. Two instances of
- * LoadBalacer are created. When a request is made to a server via the first LoadBalancer the state
+ * LoadBalancer are created. When a request is made to a server via the first LoadBalancer the state
* change in the first load balancer affects the second. So if the first LoadBalancer selects the
* Server 1, the second LoadBalancer on a new request will select the Second server. If a third
* LoadBalancer is created and a new request is made to it, then it will select the third server as
@@ -43,8 +43,8 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- LoadBalancer loadBalancer1 = new LoadBalancer();
- LoadBalancer loadBalancer2 = new LoadBalancer();
+ var loadBalancer1 = new LoadBalancer();
+ var loadBalancer2 = new LoadBalancer();
loadBalancer1.serverRequest(new Request("Hello"));
loadBalancer2.serverRequest(new Request("Hello World"));
}
diff --git a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
index 8546ae177..7a784f514 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
@@ -38,8 +38,8 @@ public class LoadBalancer {
private static int lastServedId;
static {
- int id = 0;
- for (int port : new int[]{8080, 8081, 8082, 8083, 8084}) {
+ var id = 0;
+ for (var port : new int[]{8080, 8081, 8082, 8083, 8084}) {
SERVERS.add(new Server("localhost", port, ++id));
}
}
@@ -69,7 +69,7 @@ public class LoadBalancer {
if (lastServedId >= SERVERS.size()) {
lastServedId = 0;
}
- Server server = SERVERS.get(lastServedId++);
+ var server = SERVERS.get(lastServedId++);
server.serve(request);
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
index c914f136e..d17a56bb9 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
@@ -32,8 +32,7 @@ public class AppTest {
@Test
public void testMain() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
index 736bf6ea6..d62c029e2 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
@@ -44,8 +44,8 @@ public class LoadBalancerTest {
@Test
public void testSameStateAmongstAllInstances() {
- final LoadBalancer firstBalancer = new LoadBalancer();
- final LoadBalancer secondBalancer = new LoadBalancer();
+ final var firstBalancer = new LoadBalancer();
+ final var secondBalancer = new LoadBalancer();
firstBalancer.addServer(new Server("localhost", 8085, 6));
// Both should have the same number of servers.
assertEquals(firstBalancer.getNoOfServers(), secondBalancer.getNoOfServers());
@@ -55,18 +55,18 @@ public class LoadBalancerTest {
@Test
public void testServe() {
- final Server server = mock(Server.class);
+ final var server = mock(Server.class);
when(server.getHost()).thenReturn("testhost");
when(server.getPort()).thenReturn(1234);
doNothing().when(server).serve(any(Request.class));
- final LoadBalancer loadBalancer = new LoadBalancer();
+ final var loadBalancer = new LoadBalancer();
loadBalancer.addServer(server);
verifyZeroInteractions(server);
- final Request request = new Request("test");
- for (int i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
+ final var request = new Request("test");
+ for (var i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
loadBalancer.serverRequest(request);
}
diff --git a/multiton/README.md b/multiton/README.md
index 85ce3acf2..07a4bf895 100644
--- a/multiton/README.md
+++ b/multiton/README.md
@@ -9,16 +9,19 @@ tags:
---
## Also known as
+
Registry
## Intent
+
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.
+> 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
@@ -26,11 +29,14 @@ In plain words
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.
+> 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.
+`Nazgul` is the multiton class.
```java
public enum NazgulName {
@@ -71,7 +77,7 @@ public final class Nazgul {
}
```
-And here's how we access the Nazgul instances.
+And here's how we access the `Nazgul` instances.
```java
LOGGER.info("KHAMUL={}", Nazgul.getInstance(NazgulName.KHAMUL));
@@ -83,22 +89,29 @@ And here's how we access the Nazgul instances.
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
+```
+
+Program output:
+
+```
+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
+

## Applicability
+
Use the Multiton pattern when
-* there must be specific number of instances of a class, and they must be accessible to clients from a well-known access point
+* There must be specific number of instances of a class, and they must be accessible to clients from
+a well-known access point.
diff --git a/multiton/pom.xml b/multiton/pom.xml
index ef1e9c892..d1e4d50d5 100644
--- a/multiton/pom.xml
+++ b/multiton/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmultiton
diff --git a/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java b/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
index ec20fbc97..bb1454b9f 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
* enum based multiton implementation.
*/
public enum NazgulEnum {
-
- KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
-
+ KHAMUL,
+ MURAZOR,
+ DWAR,
+ JI_INDUR,
+ AKHORAHIL,
+ HOARMURATH,
+ ADUNAPHEL,
+ REN,
+ UVATHA
}
diff --git a/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java b/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
index 76702c358..cce19c6ff 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
* Each Nazgul has different {@link NazgulName}.
*/
public enum NazgulName {
-
- KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
-
+ KHAMUL,
+ MURAZOR,
+ DWAR,
+ JI_INDUR,
+ AKHORAHIL,
+ HOARMURATH,
+ ADUNAPHEL,
+ REN,
+ UVATHA
}
diff --git a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
index f577b7f07..0496ebdaf 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
@@ -26,15 +26,12 @@ package com.iluwatar.multiton;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
index 6668874f4..4d107a181 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
@@ -39,10 +39,10 @@ class NazgulEnumTest {
*/
@Test
public void testTheSameObjectIsReturnedWithMultipleCalls() {
- for (int i = 0; i < NazgulEnum.values().length; i++) {
- NazgulEnum instance1 = NazgulEnum.values()[i];
- NazgulEnum instance2 = NazgulEnum.values()[i];
- NazgulEnum instance3 = NazgulEnum.values()[i];
+ for (var i = 0; i < NazgulEnum.values().length; i++) {
+ var instance1 = NazgulEnum.values()[i];
+ var instance2 = NazgulEnum.values()[i];
+ var instance3 = NazgulEnum.values()[i];
assertSame(instance1, instance2);
assertSame(instance1, instance3);
assertSame(instance2, instance3);
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
index 0429f8e29..f900659a8 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
@@ -41,8 +41,8 @@ public class NazgulTest {
*/
@Test
public void testGetInstance() {
- for (final NazgulName name : NazgulName.values()) {
- final Nazgul nazgul = Nazgul.getInstance(name);
+ for (final var name : NazgulName.values()) {
+ final var nazgul = Nazgul.getInstance(name);
assertNotNull(nazgul);
assertSame(nazgul, Nazgul.getInstance(name));
assertEquals(name, nazgul.getName());
diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml
index a32f6a3ea..2bf95f070 100644
--- a/mute-idiom/pom.xml
+++ b/mute-idiom/pom.xml
@@ -30,7 +30,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmute-idiom
diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java
index d4f140bf0..eca345014 100644
--- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java
+++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java
@@ -25,7 +25,7 @@ package com.iluwatar.mute;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.sql.SQLException;
+import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,9 +52,8 @@ public class App {
* Program entry point.
*
* @param args command line args.
- * @throws Exception if any exception occurs
*/
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
useOfLoggedMute();
@@ -68,17 +67,17 @@ public class App {
* exception occurs.
*/
private static void useOfMute() {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ var out = new ByteArrayOutputStream();
Mute.mute(() -> out.write("Hello".getBytes()));
}
- private static void useOfLoggedMute() throws SQLException {
- Resource resource = null;
+ private static void useOfLoggedMute() {
+ Optional resource = Optional.empty();
try {
- resource = acquireResource();
- utilizeResource(resource);
+ resource = Optional.of(acquireResource());
+ utilizeResource(resource.get());
} finally {
- closeResource(resource);
+ resource.ifPresent(App::closeResource);
}
}
@@ -86,14 +85,14 @@ public class App {
* All we can do while failed close of a resource is to log it.
*/
private static void closeResource(Resource resource) {
- Mute.loggedMute(() -> resource.close());
+ Mute.loggedMute(resource::close);
}
- private static void utilizeResource(Resource resource) throws SQLException {
+ private static void utilizeResource(Resource resource) {
LOGGER.info("Utilizing acquired resource: {}", resource);
}
- private static Resource acquireResource() throws SQLException {
+ private static Resource acquireResource() {
return new Resource() {
@Override
diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
index 5ca525a9d..c5ce35582 100644
--- a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
+++ b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
@@ -25,14 +25,15 @@ package com.iluwatar.mute;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Mute idiom example runs without errors.
- *
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() throws Exception {
- App.main(null);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
index f2743113b..e92b26f9b 100644
--- a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
+++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
@@ -23,46 +23,41 @@
package com.iluwatar.mute;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
/**
* Test for the mute-idiom pattern
*/
-public class MuteTest {
+class MuteTest {
private static final Logger LOGGER = LoggerFactory.getLogger(MuteTest.class);
private static final String MESSAGE = "should not occur";
@Test
- public void muteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() {
- Mute.mute(this::methodNotThrowingAnyException);
+ void muteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() {
+ assertDoesNotThrow(() -> Mute.mute(this::methodNotThrowingAnyException));
}
@Test
- public void muteShouldRethrowUnexpectedExceptionAsAssertionError() {
- assertThrows(AssertionError.class, () -> {
- Mute.mute(this::methodThrowingException);
- });
+ void muteShouldRethrowUnexpectedExceptionAsAssertionError() {
+ assertThrows(AssertionError.class, () -> Mute.mute(this::methodThrowingException));
}
@Test
- public void loggedMuteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() {
- Mute.loggedMute(this::methodNotThrowingAnyException);
+ void loggedMuteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() {
+ assertDoesNotThrow(() -> Mute.mute(this::methodNotThrowingAnyException));
}
@Test
- public void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() {
+ var stream = new ByteArrayOutputStream();
System.setErr(new PrintStream(stream));
Mute.loggedMute(this::methodThrowingException);
diff --git a/mutex/pom.xml b/mutex/pom.xml
index 9cdff25e4..84455abb1 100644
--- a/mutex/pom.xml
+++ b/mutex/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTmutex
diff --git a/mutex/src/main/java/com/iluwatar/mutex/App.java b/mutex/src/main/java/com/iluwatar/mutex/App.java
index e4a952ef9..c50acc65a 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/App.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/App.java
@@ -38,10 +38,10 @@ public class App {
* main method.
*/
public static void main(String[] args) {
- Mutex mutex = new Mutex();
- Jar jar = new Jar(1000, mutex);
- Thief peter = new Thief("Peter", jar);
- Thief john = new Thief("John", jar);
+ var mutex = new Mutex();
+ var jar = new Jar(1000, mutex);
+ var peter = new Thief("Peter", jar);
+ var john = new Thief("John", jar);
peter.start();
john.start();
}
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Jar.java b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
index f68b266ad..4a0861e1a 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Jar.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
@@ -48,7 +48,7 @@ public class Jar {
* Method for a thief to take a bean.
*/
public boolean takeBean() {
- boolean success = false;
+ var success = false;
try {
lock.acquire();
success = beans > 0;
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Thief.java b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
index 29caba540..a9a715970 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Thief.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
@@ -54,7 +54,7 @@ public class Thief extends Thread {
*/
@Override
public void run() {
- int beans = 0;
+ var beans = 0;
while (jar.takeBean()) {
beans = beans + 1;
diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
index 1793bf90b..7866b22a8 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
@@ -25,15 +25,15 @@ package com.iluwatar.mutex;
import org.junit.jupiter.api.Test;
-import java.io.IOException;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
/**
* Application Test Entrypoint
*/
-public class AppTest {
+class AppTest {
+
@Test
- public void test() throws IOException {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/JarTest.java b/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
index e0a316072..786f96e44 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
@@ -23,10 +23,11 @@
package com.iluwatar.mutex;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
/**
* Test case for taking beans from a Jar
@@ -35,12 +36,10 @@ public class JarTest {
@Test
public void testTakeBeans() {
- Mutex mutex = new Mutex();
- Jar jar = new Jar(10, mutex);
- for (int i = 0; i < 10; i++) {
- assertTrue(jar.takeBean());
- }
+ var mutex = new Mutex();
+ var jar = new Jar(10, mutex);
+ IntStream.range(0, 10).mapToObj(i -> jar.takeBean()).forEach(Assertions::assertTrue);
assertFalse(jar.takeBean());
}
-}
\ No newline at end of file
+}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java b/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
index 2e3184c51..d6d0cc1d7 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
@@ -23,12 +23,12 @@
package com.iluwatar.mutex;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.Test;
+
/**
* Test case for acquiring and releasing a Mutex
*/
@@ -36,7 +36,7 @@ public class MutexTest {
@Test
public void acquireReleaseTest() {
- Mutex mutex = new Mutex();
+ var mutex = new Mutex();
assertNull(mutex.getOwner());
try {
mutex.acquire();
diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml
index dffc1650c..1b1eb2266 100644
--- a/naked-objects/dom/pom.xml
+++ b/naked-objects/dom/pom.xml
@@ -30,7 +30,7 @@
com.iluwatarnaked-objects
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTnaked-objects-dom
@@ -127,7 +127,7 @@
-
+
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json
index 638473eee..fe39b5b42 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json
+++ b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json
@@ -1,19 +1,3 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
{
"columns": [
{
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java
index 809da6d31..43d96f280 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java
+++ b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java
@@ -50,9 +50,9 @@ import org.apache.isis.applib.util.ObjectContracts;
strategy = javax.jdo.annotations.IdGeneratorStrategy.IDENTITY, column = "id")
@javax.jdo.annotations.Version(strategy = VersionStrategy.VERSION_NUMBER, column = "version")
@javax.jdo.annotations.Queries({
- @javax.jdo.annotations.Query(name = "find", language = "JDOQL", value = "SELECT "
+ @javax.jdo.annotations.Query(name = "find", value = "SELECT "
+ "FROM domainapp.dom.modules.simple.SimpleObject "),
- @javax.jdo.annotations.Query(name = "findByName", language = "JDOQL", value = "SELECT "
+ @javax.jdo.annotations.Query(name = "findByName", value = "SELECT "
+ "FROM domainapp.dom.modules.simple.SimpleObject " + "WHERE name.indexOf(:name) >= 0 ")})
@javax.jdo.annotations.Unique(name = "SimpleObject_name_UNQ", members = {"name"})
@DomainObject
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json
index 78b2ac096..998c419f2 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json
+++ b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json
@@ -1,19 +1,3 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
{
"columns": [
{
diff --git a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java
index 03ab30f75..5435325cf 100644
--- a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java
+++ b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java
@@ -37,12 +37,12 @@ public class SimpleObjectTest {
SimpleObject simpleObject;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
simpleObject = new SimpleObject();
}
@Test
- public void testName() throws Exception {
+ public void testName() {
// given
String name = "Foobar";
assertNull(simpleObject.getName());
diff --git a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java
index a95ad5aa3..5fbcfde2b 100644
--- a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java
+++ b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java
@@ -52,13 +52,13 @@ public class SimpleObjectsTest {
SimpleObjects simpleObjects;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
simpleObjects = new SimpleObjects();
simpleObjects.container = mockContainer;
}
@Test
- public void testCreate() throws Exception {
+ public void testCreate() {
// given
final SimpleObject simpleObject = new SimpleObject();
@@ -85,7 +85,7 @@ public class SimpleObjectsTest {
}
@Test
- public void testListAll() throws Exception {
+ public void testListAll() {
// given
final List all = Lists.newArrayList();
diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml
index 3457ac0a4..a918e20de 100644
--- a/naked-objects/fixture/pom.xml
+++ b/naked-objects/fixture/pom.xml
@@ -30,7 +30,7 @@
com.iluwatarnaked-objects
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTnaked-objects-fixture
diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java
index dc19195ac..0df939678 100644
--- a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java
+++ b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java
@@ -67,8 +67,7 @@ public class SimpleObjectCreate extends FixtureScript {
@Override
protected void execute(final ExecutionContext ec) {
-
- String paramName = checkParam("name", ec, String.class);
+ var paramName = checkParam("name", ec, String.class);
this.simpleObject = wrap(simpleObjects).create(paramName);
diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java b/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java
index 847f15d01..5dc9a4785 100644
--- a/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java
+++ b/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java
@@ -27,7 +27,6 @@ import com.google.common.collect.Lists;
import domainapp.dom.modules.simple.SimpleObject;
import domainapp.fixture.modules.simple.SimpleObjectCreate;
import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
-import java.util.Collections;
import java.util.List;
import org.apache.isis.applib.fixturescripts.FixtureScript;
@@ -37,8 +36,18 @@ import org.apache.isis.applib.fixturescripts.FixtureScript;
*/
public class RecreateSimpleObjects extends FixtureScript {
- public final List names = Collections.unmodifiableList(List.of("Foo", "Bar", "Baz",
- "Frodo", "Froyo", "Fizz", "Bip", "Bop", "Bang", "Boo"));
+ public final List names = List.of(
+ "Foo",
+ "Bar",
+ "Baz",
+ "Frodo",
+ "Froyo",
+ "Fizz",
+ "Bip",
+ "Bop",
+ "Bang",
+ "Boo"
+ );
// region > number (optional input)
private Integer number;
@@ -77,7 +86,7 @@ public class RecreateSimpleObjects extends FixtureScript {
protected void execute(final ExecutionContext ec) {
// defaults
- final int paramNumber = defaultParam("number", ec, 3);
+ final var paramNumber = defaultParam("number", ec, 3);
// validate
if (paramNumber < 0 || paramNumber > names.size()) {
@@ -90,8 +99,8 @@ public class RecreateSimpleObjects extends FixtureScript {
//
ec.executeChild(this, new SimpleObjectsTearDown());
- for (int i = 0; i < paramNumber; i++) {
- final SimpleObjectCreate fs = new SimpleObjectCreate().setName(names.get(i));
+ for (var i = 0; i < paramNumber; i++) {
+ final var fs = new SimpleObjectCreate().setName(names.get(i));
ec.executeChild(this, fs.getName(), fs);
simpleObjects.add(fs.getSimpleObject());
}
diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml
index f46541f48..b9482b292 100644
--- a/naked-objects/integtests/pom.xml
+++ b/naked-objects/integtests/pom.xml
@@ -30,7 +30,7 @@
com.iluwatarnaked-objects
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTnaked-objects-integtests
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java b/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java
index f67c26876..ad186d706 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java
@@ -40,7 +40,7 @@ public final class SimpleAppSystemInitializer {
* Init test system
*/
public static void initIsft() {
- IsisSystemForTest isft = IsisSystemForTest.getElseNull();
+ var isft = IsisSystemForTest.getElseNull();
if (isft == null) {
isft = new SimpleAppSystemBuilder().build().setUpSystem();
IsisSystemForTest.set(isft);
@@ -58,8 +58,7 @@ public final class SimpleAppSystemInitializer {
}
private static IsisConfiguration testConfiguration() {
- final IsisConfigurationForJdoIntegTests testConfiguration =
- new IsisConfigurationForJdoIntegTests();
+ final var testConfiguration = new IsisConfigurationForJdoIntegTests();
testConfiguration.addRegisterEntitiesPackagePrefix("domainapp.dom.modules");
return testConfiguration;
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java
index 025c6724a..142b0e9fb 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java
@@ -23,10 +23,9 @@
package domainapp.integtests.specglue;
-import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
-
import cucumber.api.java.Before;
import domainapp.fixture.scenarios.RecreateSimpleObjects;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
/**
* Test Execution to append a fixture of SimpleObjects
@@ -34,7 +33,7 @@ import domainapp.fixture.scenarios.RecreateSimpleObjects;
public class CatalogOfFixturesGlue extends CukeGlueAbstract {
@Before(value = {"@integration", "@SimpleObjectsFixture"}, order = 20000)
- public void integrationFixtures() throws Throwable {
+ public void integrationFixtures() {
scenarioExecution().install(new RecreateSimpleObjects());
}
}
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java
index 7b508faf3..51253b667 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java
@@ -28,9 +28,7 @@ import static org.junit.Assert.assertThat;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.When;
-import domainapp.dom.modules.simple.SimpleObject;
import domainapp.dom.modules.simple.SimpleObjects;
-import java.util.List;
import java.util.UUID;
import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
@@ -40,9 +38,9 @@ import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
public class SimpleObjectGlue extends CukeGlueAbstract {
@Given("^there are.* (\\d+) simple objects$")
- public void thereAreNumSimpleObjects(int n) throws Throwable {
+ public void thereAreNumSimpleObjects(int n) {
try {
- final List findAll = service(SimpleObjects.class).listAll();
+ final var findAll = service(SimpleObjects.class).listAll();
assertThat(findAll.size(), is(n));
putVar("list", "all", findAll);
@@ -52,7 +50,7 @@ public class SimpleObjectGlue extends CukeGlueAbstract {
}
@When("^I create a new simple object$")
- public void createNewSimpleObject() throws Throwable {
+ public void createNewSimpleObject() {
service(SimpleObjects.class).create(UUID.randomUUID().toString());
}
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java
index 11ff6a47d..819220344 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java
@@ -26,8 +26,10 @@ package domainapp.integtests.tests.modules.simple;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import domainapp.dom.modules.simple.SimpleObject;
+import domainapp.fixture.scenarios.RecreateSimpleObjects;
+import domainapp.integtests.tests.SimpleAppIntegTest;
import javax.inject.Inject;
-
import org.apache.isis.applib.DomainObjectContainer;
import org.apache.isis.applib.fixturescripts.FixtureScripts;
import org.apache.isis.applib.services.wrapper.DisabledException;
@@ -35,10 +37,6 @@ import org.apache.isis.applib.services.wrapper.InvalidException;
import org.junit.Before;
import org.junit.Test;
-import domainapp.dom.modules.simple.SimpleObject;
-import domainapp.fixture.scenarios.RecreateSimpleObjects;
-import domainapp.integtests.tests.SimpleAppIntegTest;
-
/**
* Test Fixtures with Simple Objects
*/
@@ -56,7 +54,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
private static final String NEW_NAME = "new name";
@Before
- public void setUp() throws Exception {
+ public void setUp() {
// given
fs = new RecreateSimpleObjects().setNumber(1);
fixtureScripts.runFixtureScript(fs, null);
@@ -68,15 +66,15 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testNameAccessible() throws Exception {
- // when
- final String name = simpleObjectWrapped.getName();
+ public void testNameAccessible() {
+ /* when */
+ final var name = simpleObjectWrapped.getName();
// then
assertEquals(fs.names.get(0), name);
}
@Test
- public void testNameCannotBeUpdatedDirectly() throws Exception {
+ public void testNameCannotBeUpdatedDirectly() {
// expect
expectedExceptions.expect(DisabledException.class);
@@ -86,7 +84,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testUpdateName() throws Exception {
+ public void testUpdateName() {
// when
simpleObjectWrapped.updateName(NEW_NAME);
@@ -96,7 +94,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testUpdateNameFailsValidation() throws Exception {
+ public void testUpdateNameFailsValidation() {
// expect
expectedExceptions.expect(InvalidException.class);
@@ -107,13 +105,13 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testInterpolatesName() throws Exception {
+ public void testInterpolatesName() {
// given
- final String name = simpleObjectWrapped.getName();
+ final var name = simpleObjectWrapped.getName();
// when
- final String title = container.titleOf(simpleObjectWrapped);
+ final var title = container.titleOf(simpleObjectWrapped);
// then
assertEquals("Object: " + name, title);
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java
index c762dd88f..2699c5aad 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java
@@ -25,11 +25,13 @@ package domainapp.integtests.tests.modules.simple;
import static org.junit.Assert.assertEquals;
+import com.google.common.base.Throwables;
+import domainapp.dom.modules.simple.SimpleObjects;
+import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
+import domainapp.fixture.scenarios.RecreateSimpleObjects;
+import domainapp.integtests.tests.SimpleAppIntegTest;
import java.sql.SQLIntegrityConstraintViolationException;
-import java.util.List;
-
import javax.inject.Inject;
-
import org.apache.isis.applib.fixturescripts.FixtureScript;
import org.apache.isis.applib.fixturescripts.FixtureScripts;
import org.hamcrest.Description;
@@ -37,14 +39,6 @@ import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;
-import com.google.common.base.Throwables;
-
-import domainapp.dom.modules.simple.SimpleObject;
-import domainapp.dom.modules.simple.SimpleObjects;
-import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
-import domainapp.fixture.scenarios.RecreateSimpleObjects;
-import domainapp.integtests.tests.SimpleAppIntegTest;
-
/**
* Fixture Pattern Integration Test
*/
@@ -56,25 +50,25 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
SimpleObjects simpleObjects;
@Test
- public void testListAll() throws Exception {
+ public void testListAll() {
// given
- RecreateSimpleObjects fs = new RecreateSimpleObjects();
+ var fs = new RecreateSimpleObjects();
fixtureScripts.runFixtureScript(fs, null);
nextTransaction();
// when
- final List all = wrap(simpleObjects).listAll();
+ final var all = wrap(simpleObjects).listAll();
// then
assertEquals(fs.getSimpleObjects().size(), all.size());
- SimpleObject simpleObject = wrap(all.get(0));
+ var simpleObject = wrap(all.get(0));
assertEquals(fs.getSimpleObjects().get(0).getName(), simpleObject.getName());
}
-
+
@Test
- public void testListAllWhenNone() throws Exception {
+ public void testListAllWhenNone() {
// given
FixtureScript fs = new SimpleObjectsTearDown();
@@ -82,14 +76,14 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
nextTransaction();
// when
- final List all = wrap(simpleObjects).listAll();
+ final var all = wrap(simpleObjects).listAll();
// then
assertEquals(0, all.size());
}
-
+
@Test
- public void testCreate() throws Exception {
+ public void testCreate() {
// given
FixtureScript fs = new SimpleObjectsTearDown();
@@ -100,12 +94,12 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
wrap(simpleObjects).create("Faz");
// then
- final List all = wrap(simpleObjects).listAll();
+ final var all = wrap(simpleObjects).listAll();
assertEquals(1, all.size());
}
-
+
@Test
- public void testCreateWhenAlreadyExists() throws Exception {
+ public void testCreateWhenAlreadyExists() {
// given
FixtureScript fs = new SimpleObjectsTearDown();
@@ -115,24 +109,22 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
nextTransaction();
// then
- expectedExceptions.expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
+ expectedExceptions
+ .expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
// when
wrap(simpleObjects).create("Faz");
nextTransaction();
}
-
+
+ @SuppressWarnings("SameParameterValue")
private static Matcher extends Throwable> causalChainContains(final Class> cls) {
- return new TypeSafeMatcher() {
+ return new TypeSafeMatcher<>() {
@Override
+ @SuppressWarnings("UnstableApiUsage")
protected boolean matchesSafely(Throwable item) {
- final List causalChain = Throwables.getCausalChain(item);
- for (Throwable throwable : causalChain) {
- if (cls.isAssignableFrom(throwable.getClass())) {
- return true;
- }
- }
- return false;
+ final var causalChain = Throwables.getCausalChain(item);
+ return causalChain.stream().map(Throwable::getClass).anyMatch(cls::isAssignableFrom);
}
@Override
diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml
index 5b7a2e0c7..e8b9b79c5 100644
--- a/naked-objects/pom.xml
+++ b/naked-objects/pom.xml
@@ -29,7 +29,7 @@
java-design-patternscom.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTnaked-objectspom
@@ -333,17 +333,17 @@
${project.groupId}naked-objects-dom
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT${project.groupId}naked-objects-fixture
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT${project.groupId}naked-objects-webapp
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
diff --git a/naked-objects/webapp/ide/eclipse/launch/.gitignore b/naked-objects/webapp/ide/eclipse/launch/.gitignore
index 3d9734548..3cefd2567 100644
--- a/naked-objects/webapp/ide/eclipse/launch/.gitignore
+++ b/naked-objects/webapp/ide/eclipse/launch/.gitignore
@@ -2,7 +2,3 @@
/SimpleApp-PROTOTYPE-no-fixtures.launch
/SimpleApp-PROTOTYPE-with-fixtures.launch
/SimpleApp-SERVER-no-fixtures.launch
-/SimpleApp-PROTOTYPE-jrebel.launch
-/SimpleApp-PROTOTYPE-no-fixtures.launch
-/SimpleApp-PROTOTYPE-with-fixtures.launch
-/SimpleApp-SERVER-no-fixtures.launch
diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml
index bdf638cba..3a817f9e2 100644
--- a/naked-objects/webapp/pom.xml
+++ b/naked-objects/webapp/pom.xml
@@ -30,7 +30,7 @@
com.iluwatarnaked-objects
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTnaked-objects-webapp
@@ -129,7 +129,7 @@
-
+
diff --git a/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java b/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
index 8425712dc..780e4027e 100644
--- a/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
+++ b/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
@@ -31,18 +31,15 @@ import com.google.inject.name.Names;
import com.google.inject.util.Modules;
import com.google.inject.util.Providers;
import de.agilecoders.wicket.core.Bootstrap;
-import de.agilecoders.wicket.core.settings.IBootstrapSettings;
import de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchTheme;
import de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchThemeProvider;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
-import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.isis.viewer.wicket.viewer.IsisWicketApplication;
import org.apache.isis.viewer.wicket.viewer.integration.wicket.AuthenticatedWebSessionForIsis;
import org.apache.wicket.Session;
-import org.apache.wicket.request.IRequestParameters;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.http.WebRequest;
@@ -85,7 +82,7 @@ public class SimpleApplication extends IsisWicketApplication {
protected void init() {
super.init();
- IBootstrapSettings settings = Bootstrap.getSettings();
+ var settings = Bootstrap.getSettings();
settings.setThemeProvider(new BootswatchThemeProvider(BootswatchTheme.Flatly));
}
@@ -96,13 +93,10 @@ public class SimpleApplication extends IsisWicketApplication {
}
// else demo mode
- final AuthenticatedWebSessionForIsis s =
- (AuthenticatedWebSessionForIsis) super.newSession(request, response);
- IRequestParameters requestParameters = request.getRequestParameters();
- final org.apache.wicket.util.string.StringValue user =
- requestParameters.getParameterValue("user");
- final org.apache.wicket.util.string.StringValue password =
- requestParameters.getParameterValue("pass");
+ final var s = (AuthenticatedWebSessionForIsis) super.newSession(request, response);
+ var requestParameters = request.getRequestParameters();
+ final var user = requestParameters.getParameterValue("user");
+ final var password = requestParameters.getParameterValue("pass");
s.signIn(user.toString(), password.toString());
return s;
}
@@ -115,7 +109,7 @@ public class SimpleApplication extends IsisWicketApplication {
// else demo mode
try {
- String uname = servletRequest.getParameter("user");
+ var uname = servletRequest.getParameter("user");
if (uname != null) {
servletRequest.getSession().invalidate();
}
@@ -127,7 +121,7 @@ public class SimpleApplication extends IsisWicketApplication {
@Override
protected Module newIsisWicketModule() {
- final Module isisDefaults = super.newIsisWicketModule();
+ final var isisDefaults = super.newIsisWicketModule();
final Module overrides = new AbstractModule() {
@Override
@@ -148,11 +142,11 @@ public class SimpleApplication extends IsisWicketApplication {
return Modules.override(isisDefaults).with(overrides);
}
+ @SuppressWarnings({"UnstableApiUsage", "SameParameterValue"})
private static String readLines(final Class> contextClass, final String resourceName) {
try {
- List readLines =
- Resources.readLines(Resources.getResource(contextClass, resourceName),
- Charset.defaultCharset());
+ var resource = Resources.getResource(contextClass, resourceName);
+ var readLines = Resources.readLines(resource, Charset.defaultCharset());
return Joiner.on("\n").join(readLines);
} catch (IOException e) {
return "This is a simple app";
diff --git a/naked-objects/webapp/src/main/webapp/about/index.html b/naked-objects/webapp/src/main/webapp/about/index.html
index e929c5b6d..4579f3d0b 100644
--- a/naked-objects/webapp/src/main/webapp/about/index.html
+++ b/naked-objects/webapp/src/main/webapp/about/index.html
@@ -110,8 +110,8 @@ th, td {
provides access to a RESTful API conformant with the
- Restful Objects spec. This is part of Apache Isis Core. The
- implementation technology is JBoss RestEasy.
+ Restful Objects spec. This is part of Apache Isis Core.
+ The implementation technology is JBoss RestEasy.
diff --git a/null-object/README.md b/null-object/README.md
index 5b943630e..0e95453cb 100644
--- a/null-object/README.md
+++ b/null-object/README.md
@@ -9,20 +9,20 @@ tags:
---
## Intent
-In most object-oriented languages, such as Java or C#, references
-may be null. These references need to be checked to ensure they are not null
-before invoking any methods, because methods typically cannot be invoked on
-null references. Instead of using a null reference to convey absence of an
-object (for instance, a non-existent customer), one uses an object which
-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.
+
+In most object-oriented languages, such as Java or C#, references may be null. These references need
+to be checked to ensure they are not null before invoking any methods, because methods typically
+cannot be invoked on null references. Instead of using a null reference to convey absence of an
+object (for instance, a non-existent customer), one uses an object which 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.
+> 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
@@ -30,11 +30,13 @@ In plain words
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).
+> 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.
+Here's the definition of `Node` interface.
```java
public interface Node {
@@ -49,7 +51,12 @@ public interface Node {
void walk();
}
+```
+We have two implementations of `Node`. The normal implementation `NodeImpl` and `NullNode` for
+empty nodes.
+
+```java
public class NodeImpl implements Node {
private static final Logger LOGGER = LoggerFactory.getLogger(NodeImpl.class);
@@ -135,30 +142,40 @@ public final class NullNode implements Node {
// 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())));
+ var 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
+```
+
+Program output:
+
+```
+1
+11
+111
+12
+122
```
## Class diagram
+

## Applicability
+
Use the Null Object pattern when
* You want to avoid explicit null checks and keep the algorithm elegant and easy to read.
diff --git a/null-object/pom.xml b/null-object/pom.xml
index 7b88fca79..4317ee36a 100644
--- a/null-object/pom.xml
+++ b/null-object/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTnull-object
diff --git a/null-object/src/main/java/com/iluwatar/nullobject/App.java b/null-object/src/main/java/com/iluwatar/nullobject/App.java
index 2826bafd0..cd35a3042 100644
--- a/null-object/src/main/java/com/iluwatar/nullobject/App.java
+++ b/null-object/src/main/java/com/iluwatar/nullobject/App.java
@@ -37,12 +37,16 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
-
- 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())));
+ var 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();
}
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java b/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
index 97d6b5eef..27724a724 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
@@ -25,16 +25,15 @@ package com.iluwatar.nullobject;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
- *
* Application test
- *
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
index b4d9f72d0..5862d1e1a 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
@@ -35,30 +35,29 @@ import static org.junit.jupiter.api.Assertions.assertSame;
*
* @author Jeroen Meulemeester
*/
-public class NullNodeTest {
+class NullNodeTest {
/**
* Verify if {@link NullNode#getInstance()} actually returns the same object instance
*/
@Test
- public void testGetInstance() {
- final NullNode instance = NullNode.getInstance();
+ void testGetInstance() {
+ final var instance = NullNode.getInstance();
assertNotNull(instance);
assertSame(instance, NullNode.getInstance());
}
@Test
- public void testFields() {
- final NullNode node = NullNode.getInstance();
+ void testFields() {
+ final var node = NullNode.getInstance();
assertEquals(0, node.getTreeSize());
assertNull(node.getName());
assertNull(node.getLeft());
assertNull(node.getRight());
}
- @Test
- public void testWalk() {
- NullNode.getInstance().walk();
- }
+ /**
+ * Removed unnecessary test method for {@link NullNode#walk()} as the method doesn't have an implementation.
+ */
}
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 3fe584425..9a2b485d0 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
@@ -23,22 +23,21 @@
package com.iluwatar.nullobject;
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.AppenderBase;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.slf4j.LoggerFactory;
-
-import java.util.LinkedList;
-import java.util.List;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+import java.util.LinkedList;
+import java.util.List;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
/**
* Date: 12/26/15 - 11:44 PM
*
@@ -75,12 +74,12 @@ public class TreeTest {
private static final Node TREE_ROOT;
static {
- final NodeImpl level1B = new NodeImpl("level1_b", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level2B = new NodeImpl("level2_b", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level3A = new NodeImpl("level3_a", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level3B = new NodeImpl("level3_b", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level2A = new NodeImpl("level2_a", level3A, level3B);
- final NodeImpl level1A = new NodeImpl("level1_a", level2A, level2B);
+ final var level1B = new NodeImpl("level1_b", NullNode.getInstance(), NullNode.getInstance());
+ final var level2B = new NodeImpl("level2_b", NullNode.getInstance(), NullNode.getInstance());
+ final var level3A = new NodeImpl("level3_a", NullNode.getInstance(), NullNode.getInstance());
+ final var level3B = new NodeImpl("level3_b", NullNode.getInstance(), NullNode.getInstance());
+ final var level2A = new NodeImpl("level2_a", level3A, level3B);
+ final var level1A = new NodeImpl("level1_a", level2A, level2B);
TREE_ROOT = new NodeImpl("root", level1A, level1B);
}
@@ -112,17 +111,17 @@ public class TreeTest {
@Test
public void testGetLeft() {
- final Node level1 = TREE_ROOT.getLeft();
+ final var level1 = TREE_ROOT.getLeft();
assertNotNull(level1);
assertEquals("level1_a", level1.getName());
assertEquals(5, level1.getTreeSize());
- final Node level2 = level1.getLeft();
+ final var level2 = level1.getLeft();
assertNotNull(level2);
assertEquals("level2_a", level2.getName());
assertEquals(3, level2.getTreeSize());
- final Node level3 = level2.getLeft();
+ final var level3 = level2.getLeft();
assertNotNull(level3);
assertEquals("level3_a", level3.getName());
assertEquals(1, level3.getTreeSize());
@@ -132,7 +131,7 @@ public class TreeTest {
@Test
public void testGetRight() {
- final Node level1 = TREE_ROOT.getRight();
+ final var level1 = TREE_ROOT.getRight();
assertNotNull(level1);
assertEquals("level1_b", level1.getName());
assertEquals(1, level1.getTreeSize());
@@ -140,7 +139,7 @@ public class TreeTest {
assertSame(NullNode.getInstance(), level1.getLeft());
}
- private class InMemoryAppender extends AppenderBase {
+ private static class InMemoryAppender extends AppenderBase {
private final List log = new LinkedList<>();
public InMemoryAppender() {
@@ -154,7 +153,7 @@ public class TreeTest {
}
public boolean logContains(String message) {
- return log.stream().anyMatch(event -> event.getMessage().equals(message));
+ return log.stream().map(ILoggingEvent::getMessage).anyMatch(message::equals);
}
public int getLogSize() {
diff --git a/object-mother/pom.xml b/object-mother/pom.xml
index 5ac3ce410..f9ca156ad 100644
--- a/object-mother/pom.xml
+++ b/object-mother/pom.xml
@@ -30,7 +30,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTobject-mother
diff --git a/object-pool/README.md b/object-pool/README.md
index 34d216a02..6a648ca3e 100644
--- a/object-pool/README.md
+++ b/object-pool/README.md
@@ -10,16 +10,18 @@ tags:
---
## Intent
-When objects are expensive to create and they are needed only for
-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.
+
+When objects are expensive to create and they are needed only for 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 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
@@ -27,11 +29,12 @@ In plain words
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.
+> 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.
+Here's the basic `Oliphaunt` class. These giants are very expensive to create.
```java
public class Oliphaunt {
@@ -60,7 +63,7 @@ public class Oliphaunt {
}
```
-Next we present the Object Pool and more specifically Oliphaunt Pool.
+Next we present the `ObjectPool` and more specifically `OliphauntPool`.
```java
public abstract class ObjectPool {
@@ -100,7 +103,7 @@ public class OliphauntPool extends ObjectPool {
}
```
-And finally here's how we utilize the pool.
+Finally, here's how we utilize the pool.
```java
var pool = new OliphauntPool();
@@ -113,11 +116,30 @@ And finally here's how we utilize the pool.
var oliphaunt5 = pool.checkOut();
```
+Program output:
+
+```
+Pool available=0 inUse=0
+Checked out Oliphaunt id=1
+Pool available=0 inUse=1
+Checked out Oliphaunt id=2
+Checked out Oliphaunt id=3
+Pool available=0 inUse=3
+Checking in Oliphaunt id=1
+Checking in Oliphaunt id=2
+Pool available=2 inUse=1
+Checked out Oliphaunt id=2
+Checked out Oliphaunt id=1
+Pool available=0 inUse=3
+```
+
## Class diagram
+

## Applicability
+
Use the Object Pool pattern when
-* The objects are expensive to create (allocation cost)
-* You need a large number of short-lived objects (memory fragmentation)
+* The objects are expensive to create (allocation cost).
+* You need a large number of short-lived objects (memory fragmentation).
diff --git a/object-pool/pom.xml b/object-pool/pom.xml
index 2adad8942..0587c3968 100644
--- a/object-pool/pom.xml
+++ b/object-pool/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTobject-pool
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 cbfc7dea5..48957ce24 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
@@ -57,12 +57,14 @@ public class App {
var pool = new OliphauntPool();
LOGGER.info(pool.toString());
var oliphaunt1 = pool.checkOut();
- LOGGER.info("Checked out {}", oliphaunt1);
+ String checkedOut = "Checked out {}";
+
+ LOGGER.info(checkedOut, oliphaunt1);
LOGGER.info(pool.toString());
var oliphaunt2 = pool.checkOut();
- LOGGER.info("Checked out {}", oliphaunt2);
+ LOGGER.info(checkedOut, oliphaunt2);
var oliphaunt3 = pool.checkOut();
- LOGGER.info("Checked out {}", oliphaunt3);
+ LOGGER.info(checkedOut, oliphaunt3);
LOGGER.info(pool.toString());
LOGGER.info("Checking in {}", oliphaunt1);
pool.checkIn(oliphaunt1);
@@ -70,9 +72,9 @@ public class App {
pool.checkIn(oliphaunt2);
LOGGER.info(pool.toString());
var oliphaunt4 = pool.checkOut();
- LOGGER.info("Checked out {}", oliphaunt4);
+ LOGGER.info(checkedOut, oliphaunt4);
var oliphaunt5 = pool.checkOut();
- LOGGER.info("Checked out {}", oliphaunt5);
+ LOGGER.info(checkedOut, oliphaunt5);
LOGGER.info(pool.toString());
}
}
diff --git a/object-pool/src/test/java/com/iluwatar/object/pool/AppTest.java b/object-pool/src/test/java/com/iluwatar/object/pool/AppTest.java
index 7113f9304..f36563a8c 100644
--- a/object-pool/src/test/java/com/iluwatar/object/pool/AppTest.java
+++ b/object-pool/src/test/java/com/iluwatar/object/pool/AppTest.java
@@ -30,11 +30,10 @@ import org.junit.jupiter.api.Test;
* Application test
*
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ App.main(new String[]{});
}
}
diff --git a/observer/README.md b/observer/README.md
index e329a657c..cbde540ab 100644
--- a/observer/README.md
+++ b/observer/README.md
@@ -10,29 +10,35 @@ tags:
---
## Also known as
+
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 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.
+> 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.
+> 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.
+Let's first introduce the `WeatherObserver` interface and our races, `Orcs` and `Hobbits`.
```java
public interface WeatherObserver {
@@ -46,22 +52,7 @@ public class Orcs implements WeatherObserver {
@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;
- }
+ LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now");
}
}
@@ -72,26 +63,13 @@ public class Hobbits implements WeatherObserver {
@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;
+ LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
}
}
}
```
-Then here's the weather that is constantly changing.
+Then here's the `Weather` that is constantly changing.
```java
public class Weather {
@@ -138,38 +116,47 @@ Here's the full example in action.
var weather = new Weather();
weather.addObserver(new Orcs());
weather.addObserver(new Hobbits());
+ weather.timePasses();
+ weather.timePasses();
+ weather.timePasses();
+ weather.timePasses();
+```
- 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.
+Program output:
+
+```
+The weather changed to rainy.
+The orcs are facing rainy weather now
+The hobbits are facing rainy weather now
+The weather changed to windy.
+The orcs are facing windy weather now
+The hobbits are facing windy weather now
+The weather changed to cold.
+The orcs are facing cold weather now
+The hobbits are facing cold weather now
+The weather changed to sunny.
+The orcs are facing sunny weather now
+The hobbits are facing sunny weather now
```
## Class diagram
+

## Applicability
-Use the Observer pattern in any of the following situations
-* When an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects lets you vary and reuse them independently
-* When a change to one object requires changing others, and you don't know how many objects need to be changed
-* When an object should be able to notify other objects without making assumptions about who these objects are. In other words, you don't want these objects tightly coupled
+Use the Observer pattern in any of the following situations:
+
+* When an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in
+separate objects lets you vary and reuse them independently.
+* When a change to one object requires changing others, and you don't know how many objects need to
+be changed.
+* When an object should be able to notify other objects without making assumptions about who these
+objects are. In other words, you don't want these objects tightly coupled.
## Typical Use Case
-* Changing in one object leads to a change in other objects
+* Changing in one object leads to a change in other objects.
## Real world examples
diff --git a/observer/etc/observer.urm.puml b/observer/etc/observer.urm.puml
index bea9aab53..497ef5fde 100644
--- a/observer/etc/observer.urm.puml
+++ b/observer/etc/observer.urm.puml
@@ -33,7 +33,9 @@ package com.iluwatar.observer {
+ RAINY {static}
+ SUNNY {static}
+ WINDY {static}
+ + description String
+ toString() : String
+ + getDescription() : String
+ valueOf(name : String) : WeatherType {static}
+ values() : WeatherType[] {static}
}
@@ -71,10 +73,10 @@ package com.iluwatar.observer.generic {
Weather --> "-currentWeather" WeatherType
GWeather --> "-currentWeather" WeatherType
Weather --> "-observers" WeatherObserver
-Hobbits ..|> WeatherObserver
-Orcs ..|> WeatherObserver
-GHobbits ..|> Race
-GOrcs ..|> Race
-GWeather --|> Observable
-Race --|> Observer
-@enduml
\ No newline at end of file
+Hobbits ..|> WeatherObserver
+Orcs ..|> WeatherObserver
+GHobbits ..|> Race
+GOrcs ..|> Race
+GWeather --|> Observable
+Race --|> Observer
+@enduml
diff --git a/observer/etc/observer_with_generics.png b/observer/etc/observer_with_generics.png
new file mode 100644
index 000000000..06ff0d9cc
Binary files /dev/null and b/observer/etc/observer_with_generics.png differ
diff --git a/observer/pom.xml b/observer/pom.xml
index 1e48268d8..c558992ac 100644
--- a/observer/pom.xml
+++ b/observer/pom.xml
@@ -29,7 +29,7 @@
com.iluwatarjava-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOTobserver
diff --git a/observer/src/main/java/com/iluwatar/observer/Hobbits.java b/observer/src/main/java/com/iluwatar/observer/Hobbits.java
index 646ceebfd..5894c93a6 100644
--- a/observer/src/main/java/com/iluwatar/observer/Hobbits.java
+++ b/observer/src/main/java/com/iluwatar/observer/Hobbits.java
@@ -35,21 +35,6 @@ public class Hobbits implements WeatherObserver {
@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;
- }
+ LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
}
}
diff --git a/observer/src/main/java/com/iluwatar/observer/Orcs.java b/observer/src/main/java/com/iluwatar/observer/Orcs.java
index a28ffbc5b..1a955aafd 100644
--- a/observer/src/main/java/com/iluwatar/observer/Orcs.java
+++ b/observer/src/main/java/com/iluwatar/observer/Orcs.java
@@ -35,21 +35,6 @@ public class Orcs implements WeatherObserver {
@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;
- }
+ LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now");
}
}
diff --git a/observer/src/main/java/com/iluwatar/observer/WeatherType.java b/observer/src/main/java/com/iluwatar/observer/WeatherType.java
index 75ee17d60..e11317c21 100644
--- a/observer/src/main/java/com/iluwatar/observer/WeatherType.java
+++ b/observer/src/main/java/com/iluwatar/observer/WeatherType.java
@@ -28,7 +28,20 @@ package com.iluwatar.observer;
*/
public enum WeatherType {
- SUNNY, RAINY, WINDY, COLD;
+ SUNNY("Sunny"),
+ RAINY("Rainy"),
+ WINDY("Windy"),
+ COLD("Cold");
+
+ private final String description;
+
+ WeatherType(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
@Override
public String toString() {
diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java
index 7a555d850..90fd4e300 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java
@@ -36,21 +36,6 @@ public class GHobbits implements Race {
@Override
public void update(GWeather weather, WeatherType weatherType) {
- switch (weatherType) {
- 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;
- }
+ LOGGER.info("The hobbits are facing " + weatherType.getDescription() + " weather now");
}
}
diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java
index d9adbf116..bc49c4e30 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java
@@ -36,21 +36,6 @@ public class GOrcs implements Race {
@Override
public void update(GWeather weather, WeatherType weatherType) {
- switch (weatherType) {
- 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;
- }
+ LOGGER.info("The orcs are facing " + weatherType.getDescription() + " weather now");
}
}
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 fbb078941..d90219c92 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/Observable.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/Observable.java
@@ -35,7 +35,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public abstract class Observable, O extends Observer, A> {
- protected List observers;
+ protected final List observers;
public Observable() {
this.observers = new CopyOnWriteArrayList<>();
diff --git a/observer/src/test/java/com/iluwatar/observer/AppTest.java b/observer/src/test/java/com/iluwatar/observer/AppTest.java
index b557fdf7e..6b1f426d6 100644
--- a/observer/src/test/java/com/iluwatar/observer/AppTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/AppTest.java
@@ -25,16 +25,17 @@ package com.iluwatar.observer;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
*
* Application test
*
*/
-public class AppTest {
+class AppTest {
@Test
- public void test() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java b/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java
index 66ec45fdb..345b8e331 100644
--- a/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java
@@ -36,10 +36,10 @@ public class HobbitsTest extends WeatherObserverTest {
@Override
public Collection
One of the risks of this pattern is that bugs resulting from setting a singleton up in a
* distributed environment can be tricky to debug, since it will work fine if you debug with a
* single classloader. Additionally, these problems can crop up a while after the implementation of
- * a singleton, since they may start out synchronous and only become async with time, so you it may
+ * a singleton, since they may start out synchronous and only become async with time, so it may
* not be clear why you are seeing certain changes in behaviour.
In this example we will use the TS pattern to implement booking and cancellation
+ * methods for a Hotel management App. The main method will initialise an instance of
+ * {@link Hotel} and add rooms to it. After that it will book and cancel a couple of rooms
+ * and that will be printed by the logger.
+ *
+ *
The thing we have to note here is that all the operations related to booking or cancelling
+ * a room like checking the database if the room exists, checking the booking status or the
+ * room, calculating refund price are all clubbed inside a single transaction script method.