From 9b25d302b77a013b0094dd840428a6c24e035d4d Mon Sep 17 00:00:00 2001 From: Amit Garg Date: Sun, 26 Jul 2020 21:57:15 +0100 Subject: [PATCH 001/254] Fix broken logging in service layer --- service-layer/src/main/resources/logback.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/service-layer/src/main/resources/logback.xml b/service-layer/src/main/resources/logback.xml index 47fe42236..e6678aff2 100644 --- a/service-layer/src/main/resources/logback.xml +++ b/service-layer/src/main/resources/logback.xml @@ -43,6 +43,7 @@ + From a968dce586ec574d17628d99b524b285752fc15e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2020 17:08:12 +0000 Subject: [PATCH 002/254] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0801c677c..733bb5afb 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) -[![All Contributors](https://img.shields.io/badge/all_contributors-103-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-104-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -222,6 +222,7 @@ This project is licensed under the terms of the MIT license.
Yuri Orlov

💻
Varun Upadhyay

💻
Aditya Pal

💻 +
grzesiekkedzior

💻 From 46d415532831b3a534a98f2317177b57ea7fe9ed Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2020 17:08:13 +0000 Subject: [PATCH 003/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3ec5459fb..c7a0d5b48 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -938,6 +938,15 @@ "contributions": [ "code" ] + }, + { + "login": "grzesiekkedzior", + "name": "grzesiekkedzior", + "avatar_url": "https://avatars3.githubusercontent.com/u/23739158?v=4", + "profile": "https://github.com/grzesiekkedzior", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From 31471acb69bb5e41d0668cfbf10c3d8e083b1861 Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Sat, 15 Aug 2020 21:47:39 +0400 Subject: [PATCH 004/254] Fixed most reported issues by SonarCloud. --- .../iluwatar/abstractdocument/AppTest.java | 15 +- .../com/iluwatar/abstractfactory/AppTest.java | 17 +- .../com/iluwatar/acyclicvisitor/AppTest.java | 16 +- .../java/com/iluwatar/adapter/AppTest.java | 17 +- .../iluwatar/ambassador/RemoteService.java | 4 +- .../ambassador/RemoteServiceInterface.java | 1 - .../ambassador/RemoteServiceStatus.java | 23 ++ .../ambassador/ServiceAmbassador.java | 7 +- .../java/com/iluwatar/ambassador/AppTest.java | 14 +- .../com/iluwatar/ambassador/ClientTest.java | 2 +- .../ambassador/RemoteServiceTest.java | 2 +- .../ambassador/ServiceAmbassadorTest.java | 2 +- .../async/method/invocation/AppTest.java | 16 +- .../java/com/iluwatar/balking/AppTest.java | 15 +- .../java/com/iluwatar/bridge/AppTest.java | 14 +- .../java/com/iluwatar/builder/AppTest.java | 15 +- .../iluwatar/business/delegate/AppTest.java | 18 +- .../main/java/com/iluwatar/bytecode/App.java | 10 +- .../java/com/iluwatar/bytecode/AppTest.java | 15 +- .../java/com/iluwatar/caching/AppTest.java | 17 +- .../java/com/iluwatar/callback/AppTest.java | 17 +- .../test/java/com/iluwatar/chain/AppTest.java | 16 +- combinator/pom.xml | 6 + .../combinator/CombinatorAppTest.java | 13 +- .../java/com/iluwatar/command/AppTest.java | 15 +- .../com/iluwatar/commander/Commander.java | 315 ++++++++++-------- .../java/com/iluwatar/commander/Order.java | 8 +- .../messagingservice/MessagingService.java | 12 +- .../iluwatar/commander/queue/QueueTask.java | 4 +- .../java/com/iluwatar/composite/AppTest.java | 14 +- .../java/com/iluwatar/converter/AppTest.java | 16 +- .../test/java/com/iluwatar/dao/AppTest.java | 16 +- .../locality/game/component/AiComponent.java | 2 +- .../component/manager/AiComponentManager.java | 2 +- .../manager/PhysicsComponentManager.java | 2 +- .../manager/RenderComponentManager.java | 2 +- .../data/locality/ApplicationTest.java | 12 +- .../java/com/iluwatar/datamapper/AppTest.java | 17 +- .../com/iluwatar/datatransfer/AppTest.java | 16 +- .../java/com/iluwatar/decorator/AppTest.java | 15 +- .../iluwatar/delegation/simple/AppTest.java | 15 +- .../dependency/injection/AppTest.java | 15 +- .../src/test/java/org/dirty/flag/AppTest.java | 16 +- double-buffer/pom.xml | 5 + .../com/iluwatar/doublebuffer/AppTest.java | 13 +- .../doublechecked/locking/AppTest.java | 16 +- .../com/iluwatar/doubledispatch/AppTest.java | 16 +- .../com/iluwatar/eip/aggregator/AppTest.java | 15 +- .../iluwatar/eip/message/channel/AppTest.java | 15 +- .../eip/publish/subscribe/AppTest.java | 15 +- .../com/iluwatar/eip/splitter/AppTest.java | 15 +- .../com/iluwatar/eip/wiretap/AppTest.java | 15 +- .../iluwatar/event/aggregator/AppTest.java | 15 +- .../iluwatar/event/asynchronous/AppTest.java | 16 +- .../test/java/com/iluwatar/eda/AppTest.java | 16 +- .../com/iluwatar/execute/around/AppTest.java | 10 +- .../java/concreteextensions/Commander.java | 4 + .../java/concreteextensions/Sergeant.java | 6 +- .../main/java/concreteextensions/Soldier.java | 4 + extension-objects/src/test/java/AppTest.java | 9 +- .../concreteextensions/CommanderTest.java | 30 +- .../java/concreteextensions/SergeantTest.java | 28 +- .../java/concreteextensions/SoldierTest.java | 28 +- .../java/com/iluwatar/facade/AppTest.java | 8 +- .../com/iluwatar/factorykit/app/AppTest.java | 8 +- .../com/iluwatar/factory/method/AppTest.java | 9 +- .../iluwatar/fluentinterface/app/AppTest.java | 8 +- .../iluwatar/flux/dispatcher/Dispatcher.java | 13 +- .../java/com/iluwatar/flux/app/AppTest.java | 8 +- .../java/com/iluwatar/flyweight/AppTest.java | 8 +- .../iluwatar/front/controller/AppTest.java | 8 +- game-loop/pom.xml | 6 + .../java/com/iluwatar/gameloop/AppTest.java | 6 +- .../iluwatar/halfsynchalfasync/AppTest.java | 8 +- .../database/MongoTicketRepository.java | 11 +- .../hexagonal/eventlog/MongoEventLog.java | 33 +- .../java/com/iluwatar/hexagonal/AppTest.java | 7 +- .../iluwatar/intercepting/filter/AppTest.java | 8 +- .../com/iluwatar/interpreter/AppTest.java | 8 +- .../java/com/iluwatar/iterator/AppTest.java | 6 +- .../java/com/iluwatar/layers/app/App.java | 9 +- .../java/com/iluwatar/layers/app/AppTest.java | 10 +- .../com/iluwatar/lazy/loading/AppTest.java | 9 +- .../leaderelection/AbstractInstance.java | 13 +- .../leaderelection/bully/BullyInstance.java | 21 +- .../leaderelection/ring/RingInstance.java | 18 +- .../leaderelection/bully/BullyAppTest.java | 9 +- .../leaderelection/ring/RingAppTest.java | 9 +- leader-followers/pom.xml | 5 + .../iluwatar/leaderfollowers}/App.java | 0 .../iluwatar/leaderfollowers}/Task.java | 0 .../leaderfollowers}/TaskHandler.java | 0 .../iluwatar/leaderfollowers}/TaskSet.java | 0 .../iluwatar/leaderfollowers}/WorkCenter.java | 0 .../iluwatar/leaderfollowers}/Worker.java | 0 .../AppTest.java | 10 +- .../TaskHandlerTest.java | 4 +- .../TaskSetTest.java | 4 +- .../WorkCenterTest.java | 5 +- marker/src/test/java/AppTest.java | 8 +- .../java/com/iluwatar/mediator/AppTest.java | 8 +- .../java/com/iluwatar/memento/AppTest.java | 8 +- .../model/view/controller/AppTest.java | 8 +- .../view/presenter/FileSelectorJFrame.java | 10 +- .../model/view/presenter/AppTest.java | 8 +- .../java/com/iluwatar/module/AppTest.java | 9 +- .../test/java/com/iluwatar/mute/AppTest.java | 8 +- .../test/java/com/iluwatar/mute/MuteTest.java | 19 +- .../test/java/com/iluwatar/mutex/AppTest.java | 9 +- .../java/com/iluwatar/nullobject/AppTest.java | 9 +- .../com/iluwatar/nullobject/NullNodeTest.java | 13 +- .../java/com/iluwatar/object/pool/App.java | 12 +- .../com/iluwatar/object/pool/AppTest.java | 7 +- .../java/com/iluwatar/observer/AppTest.java | 9 +- partial-response/pom.xml | 5 + .../com/iluwatar/partialresponse/AppTest.java | 6 +- .../java/com/iluwatar/pipeline/AppTest.java | 8 +- .../com/iluwatar/poison/pill/AppTest.java | 8 +- .../iluwatar/privateclassdata/AppTest.java | 8 +- .../iluwatar/producer/consumer/AppTest.java | 8 +- .../java/com/iluwatar/promise/Promise.java | 1 + .../java/com/iluwatar/promise/AppTest.java | 8 +- .../com/iluwatar/promise/PromiseTest.java | 2 +- .../java/com/iluwatar/property/Character.java | 2 + .../java/com/iluwatar/property/AppTest.java | 8 +- .../java/com/iluwatar/prototype/AppTest.java | 8 +- .../test/java/com/iluwatar/proxy/AppTest.java | 8 +- .../iluwatar/queue/load/leveling/AppTest.java | 9 +- .../load/leveling/TaskGenSrvExeTest.java | 11 +- .../com/iluwatar/reactor/app/ReactorTest.java | 11 + .../iluwatar/reader/writer/lock/AppTest.java | 8 +- .../java/com/iluwatar/repository/AppTest.java | 9 +- .../is/initialization/AppTest.java | 8 +- .../src/main/java/com/iluwatar/retry/App.java | 7 +- role-object/pom.xml | 5 + .../roleobject/ApplicationRoleObjectTest.java | 6 +- saga/pom.xml | 5 + .../choreography/SagaApplicationTest.java | 6 +- .../java/com/iluwatar/semaphore/AppTest.java | 9 +- .../java/com/iluwatar/servant/AppTest.java | 8 +- .../com/iluwatar/servicelayer/app/App.java | 7 +- .../iluwatar/servicelayer/app/AppTest.java | 10 +- .../java/com/iluwatar/servicelocator/App.java | 11 +- .../com/iluwatar/servicelocator/AppTest.java | 8 +- sharding/pom.xml | 5 + .../main/java/com/iluwatar/sharding/App.java | 8 +- .../main/java/com/iluwatar/sharding/Data.java | 2 +- .../iluwatar/sharding/RangeShardManager.java | 6 +- .../java/com/iluwatar/sharding/AppTest.java | 6 +- .../sharding/HashShardManagerTest.java | 2 +- .../sharding/LookupShardManagerTest.java | 2 +- .../sharding/RangeShardManagerTest.java | 2 +- .../java/com/iluwatar/sharding/ShardTest.java | 2 +- .../java/com/iluwatar/singleton/AppTest.java | 8 +- .../com/iluwatar/spatialpartition/App.java | 7 +- .../SpatialPartitionBubbles.java | 4 +- .../iluwatar/specification/app/AppTest.java | 8 +- .../test/java/com/iluwatar/state/AppTest.java | 8 +- .../com/iluwatar/stepbuilder/AppTest.java | 8 +- .../com/iluwatar/strangler/NewSource.java | 7 +- .../java/com/iluwatar/strangler/AppTest.java | 9 +- .../java/com/iluwatar/strategy/AppTest.java | 8 +- subclass-sandbox/pom.xml | 5 + .../com/iluwatar/subclasssandbox/AppTest.java | 6 +- .../com/iluwatar/templatemethod/AppTest.java | 8 +- .../java/com/iluwatar/threadpool/AppTest.java | 8 +- .../java/com/iluwatar/throttling/AppTest.java | 8 +- .../test/java/com/iluwatar/tls/AppTest.java | 8 +- .../tolerantreader/RainbowFishSerializer.java | 13 +- .../com/iluwatar/tolerantreader/AppTest.java | 10 +- .../iluwatar/transactionscript/AppTest.java | 9 +- .../test/java/com/iluwatar/twin/AppTest.java | 8 +- .../java/com/iluwatar/typeobject/Candy.java | 4 +- .../com/iluwatar/typeobject/CandyGame.java | 6 +- .../java/com/iluwatar/typeobject/Cell.java | 4 +- .../com/iluwatar/typeobject/CellPool.java | 16 +- .../com/iluwatar/typeobject/JsonParser.java | 6 +- .../iluwatar/typeobject/CandyGameTest.java | 6 +- .../com/iluwatar/typeobject/CellTest.java | 8 +- unit-of-work/pom.xml | 5 + .../com/iluwatar/unitofwork/IUnitOfWork.java | 3 - .../unitofwork/StudentRepository.java | 18 +- .../com/iluwatar/unitofwork/UnitActions.java | 18 + .../java/com/iluwatar/unitofwork/AppTest.java | 6 +- .../unitofwork/StudentRepositoryTest.java | 24 +- update-method/pom.xml | 5 + .../java/com/iluwatar/updatemethod/World.java | 1 + .../com/iluwatar/updatemethod/AppTest.java | 7 +- .../com/iluwatar/value/object/AppTest.java | 8 +- .../java/com/iluwatar/visitor/AppTest.java | 8 +- 190 files changed, 1426 insertions(+), 661 deletions(-) create mode 100644 ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java rename leader-followers/src/main/java/{com.iluwatar.leaderfollowers => com/iluwatar/leaderfollowers}/App.java (100%) rename leader-followers/src/main/java/{com.iluwatar.leaderfollowers => com/iluwatar/leaderfollowers}/Task.java (100%) rename leader-followers/src/main/java/{com.iluwatar.leaderfollowers => com/iluwatar/leaderfollowers}/TaskHandler.java (100%) rename leader-followers/src/main/java/{com.iluwatar.leaderfollowers => com/iluwatar/leaderfollowers}/TaskSet.java (100%) rename leader-followers/src/main/java/{com.iluwatar.leaderfollowers => com/iluwatar/leaderfollowers}/WorkCenter.java (100%) rename leader-followers/src/main/java/{com.iluwatar.leaderfollowers => com/iluwatar/leaderfollowers}/Worker.java (100%) rename leader-followers/src/test/java/{com.iluwatar.leaderfollowers => com}/AppTest.java (83%) rename leader-followers/src/test/java/{com.iluwatar.leaderfollowers => com}/TaskHandlerTest.java (93%) rename leader-followers/src/test/java/{com.iluwatar.leaderfollowers => com}/TaskSetTest.java (94%) rename leader-followers/src/test/java/{com.iluwatar.leaderfollowers => com}/WorkCenterTest.java (93%) create mode 100644 unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java index aed63f303..dca4f040f 100644 --- a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java +++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java @@ -25,14 +25,23 @@ package com.iluwatar.abstractdocument; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Simple App 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 shouldExecuteAppWithoutException() { - App.main(null); + void shouldExecuteAppWithoutException() { + assertDoesNotThrow(() -> App.main(null)); } } diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java index 4036cc9b8..238ff76d0 100644 --- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java +++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java @@ -25,12 +25,23 @@ package com.iluwatar.abstractfactory; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Abstract Factory 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/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java index 4b9a7ec6c..842779fff 100644 --- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java +++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java @@ -25,13 +25,23 @@ package com.iluwatar.acyclicvisitor; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that the Acyclic Visitor 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[]{})); } } \ No newline at end of file diff --git a/adapter/src/test/java/com/iluwatar/adapter/AppTest.java b/adapter/src/test/java/com/iluwatar/adapter/AppTest.java index 3bf8e1010..3748c64f6 100644 --- a/adapter/src/test/java/com/iluwatar/adapter/AppTest.java +++ b/adapter/src/test/java/com/iluwatar/adapter/AppTest.java @@ -25,12 +25,23 @@ package com.iluwatar.adapter; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Adapter 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/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java index a80806851..42b09d617 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java @@ -62,7 +62,7 @@ public class RemoteService implements RemoteServiceInterface { * * @param value integer value to be multiplied. * @return if waitTime is less than {@link RemoteService#THRESHOLD}, it returns value * 10, - * otherwise {@link RemoteServiceInterface#FAILURE}. + * otherwise {@link RemoteServiceStatus#FAILURE}. */ @Override public long doRemoteFunction(int value) { @@ -74,6 +74,6 @@ public class RemoteService implements RemoteServiceInterface { } catch (InterruptedException e) { LOGGER.error("Thread sleep state interrupted", e); } - return waitTime <= THRESHOLD ? value * 10 : FAILURE; + return waitTime <= THRESHOLD ? value * 10 : RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue(); } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java index 5b4995134..eadb981a2 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java @@ -27,7 +27,6 @@ package com.iluwatar.ambassador; * Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}). */ interface RemoteServiceInterface { - int FAILURE = -1; long doRemoteFunction(int value); } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java new file mode 100644 index 000000000..f9faebd0e --- /dev/null +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java @@ -0,0 +1,23 @@ +package com.iluwatar.ambassador; + +/** + * Holds information regarding the status of the Remote Service. + * + * !Attention - 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/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/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/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/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/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/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/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/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/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/combinator/pom.xml b/combinator/pom.xml index 3edfa7580..c2677fcc1 100644 --- a/combinator/pom.xml +++ b/combinator/pom.xml @@ -39,6 +39,12 @@ junit test + + + 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/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/src/main/java/com/iluwatar/commander/Commander.java b/commander/src/main/java/com/iluwatar/commander/Commander.java index 41779c076..c2e124663 100644 --- a/commander/src/main/java/com/iluwatar/commander/Commander.java +++ b/commander/src/main/java/com/iluwatar/commander/Commander.java @@ -39,6 +39,8 @@ import com.iluwatar.commander.shippingservice.ShippingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + /** *

Commander pattern is used to handle all issues that can come up while making a * distributed transaction. The idea is to have a commander, which coordinates the execution of all @@ -159,8 +161,8 @@ public class Commander { private void sendPaymentRequest(Order order) { if (System.currentTimeMillis() - order.createdTime >= this.paymentTime) { - if (order.paid.equals(PaymentStatus.Trying)) { - order.paid = PaymentStatus.NotDone; + if (order.paid.equals(PaymentStatus.TRYING)) { + order.paid = PaymentStatus.NOT_DONE; sendPaymentFailureMessage(order); LOG.error("Order " + order.id + ": Payment time for order over, failed and returning.."); } //if succeeded or failed, would have been dequeued, no attempt to make payment @@ -169,53 +171,10 @@ public class Commander { var list = paymentService.exceptionsList; var t = new Thread(() -> { Retry.Operation op = (l) -> { - if (!l.isEmpty()) { - if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { - LOG.debug("Order " + order.id + ": Error in connecting to payment service," - + " trying again.."); - } else { - LOG.debug("Order " + order.id + ": Error in creating payment request.."); - } - throw l.remove(0); - } - if (order.paid.equals(PaymentStatus.Trying)) { - var transactionId = paymentService.receiveRequest(order.price); - order.paid = PaymentStatus.Done; - LOG.info("Order " + order.id + ": Payment successful, transaction Id: " + transactionId); - if (!finalSiteMsgShown) { - LOG.info("Payment made successfully, thank you for shopping with us!!"); - finalSiteMsgShown = true; - } - sendSuccessMessage(order); - } + handlePaymentRetryOperation(order, l); }; Retry.HandleErrorIssue handleError = (o, err) -> { - if (PaymentDetailsErrorException.class.isAssignableFrom(err.getClass())) { - if (!finalSiteMsgShown) { - LOG.info("There was an error in payment. Your account/card details " - + "may have been incorrect. " - + "Meanwhile, your order has been converted to COD and will be shipped."); - finalSiteMsgShown = true; - } - LOG.error("Order " + order.id + ": Payment details incorrect, failed.."); - o.paid = PaymentStatus.NotDone; - sendPaymentFailureMessage(o); - } else { - if (o.messageSent.equals(MessageSent.NoneSent)) { - if (!finalSiteMsgShown) { - LOG.info("There was an error in payment. We are on it, and will get back to you " - + "asap. Don't worry, your order has been placed and will be shipped."); - finalSiteMsgShown = true; - } - LOG.warn("Order " + order.id + ": Payment error, going to queue.."); - sendPaymentPossibleErrorMsg(o); - } - if (o.paid.equals(PaymentStatus.Trying) && System - .currentTimeMillis() - o.createdTime < paymentTime) { - var qt = new QueueTask(o, TaskType.Payment, -1); - updateQueue(qt); - } - } + handlePaymentErrorIssue(order, o, err); }; var r = new Retry<>(op, handleError, numOfRetries, retryDuration, e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass())); @@ -228,18 +187,70 @@ public class Commander { t.start(); } + private void handlePaymentRetryOperation(Order order, List l) throws Exception { + if (!l.isEmpty()) { + if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { + LOG.debug("Order " + order.id + ": Error in connecting to payment service," + + " trying again.."); + } else { + LOG.debug("Order " + order.id + ": Error in creating payment request.."); + } + throw l.remove(0); + } + if (order.paid.equals(PaymentStatus.TRYING)) { + var transactionId = paymentService.receiveRequest(order.price); + order.paid = PaymentStatus.DONE; + LOG.info("Order " + order.id + ": Payment successful, transaction Id: " + transactionId); + + if (!finalSiteMsgShown) { + LOG.info("Payment made successfully, thank you for shopping with us!!"); + finalSiteMsgShown = true; + } + sendSuccessMessage(order); + } + } + + private void handlePaymentErrorIssue(Order order, Order o, Exception err) { + if (PaymentDetailsErrorException.class.isAssignableFrom(err.getClass())) { + if (!finalSiteMsgShown) { + LOG.info("There was an error in payment. Your account/card details " + + "may have been incorrect. " + + "Meanwhile, your order has been converted to COD and will be shipped."); + finalSiteMsgShown = true; + } + LOG.error("Order " + order.id + ": Payment details incorrect, failed.."); + o.paid = PaymentStatus.NOT_DONE; + sendPaymentFailureMessage(o); + } else { + if (o.messageSent.equals(MessageSent.NONE_SENT)) { + if (!finalSiteMsgShown) { + LOG.info("There was an error in payment. We are on it, and will get back to you " + + "asap. Don't worry, your order has been placed and will be shipped."); + finalSiteMsgShown = true; + } + LOG.warn("Order " + order.id + ": Payment error, going to queue.."); + sendPaymentPossibleErrorMsg(o); + } + if (o.paid.equals(PaymentStatus.TRYING) && System + .currentTimeMillis() - o.createdTime < paymentTime) { + var qt = new QueueTask(o, TaskType.PAYMENT, -1); + updateQueue(qt); + } + } + } + private void updateQueue(QueueTask qt) { if (System.currentTimeMillis() - qt.order.createdTime >= this.queueTime) { // since payment time is lesser than queuetime it would have already failed.. // additional check not needed LOG.trace("Order " + qt.order.id + ": Queue time for order over, failed.."); return; - } else if (qt.taskType.equals(TaskType.Payment) && !qt.order.paid.equals(PaymentStatus.Trying) - || qt.taskType.equals(TaskType.Messaging) && (qt.messageType == 1 - && !qt.order.messageSent.equals(MessageSent.NoneSent) - || qt.order.messageSent.equals(MessageSent.PaymentFail) - || qt.order.messageSent.equals(MessageSent.PaymentSuccessful)) - || qt.taskType.equals(TaskType.EmployeeDb) && qt.order.addedToEmployeeHandle) { + } else if (qt.taskType.equals(TaskType.PAYMENT) && !qt.order.paid.equals(PaymentStatus.TRYING) + || qt.taskType.equals(TaskType.MESSAGING) && (qt.messageType == 1 + && !qt.order.messageSent.equals(MessageSent.NONE_SENT) + || qt.order.messageSent.equals(MessageSent.PAYMENT_FAIL) + || qt.order.messageSent.equals(MessageSent.PAYMENT_SUCCESSFUL)) + || qt.taskType.equals(TaskType.EMPLOYEE_DB) && qt.order.addedToEmployeeHandle) { LOG.trace("Order " + qt.order.id + ": Not queueing task since task already done.."); return; } @@ -256,8 +267,8 @@ public class Commander { tryDoingTasksInQueue(); }; Retry.HandleErrorIssue handleError = (qt1, err) -> { - if (qt1.taskType.equals(TaskType.Payment)) { - qt1.order.paid = PaymentStatus.NotDone; + if (qt1.taskType.equals(TaskType.PAYMENT)) { + qt1.order.paid = PaymentStatus.NOT_DONE; sendPaymentFailureMessage(qt1.order); LOG.error("Order " + qt1.order.id + ": Unable to enqueue payment task," + " payment failed.."); @@ -331,7 +342,35 @@ public class Commander { } var list = messagingService.exceptionsList; Thread t = new Thread(() -> { - Retry.Operation op = (l) -> { + Retry.Operation op = handleSuccessMessageRetryOperation(order); + Retry.HandleErrorIssue handleError = (o, err) -> { + handleSuccessMessageErrorIssue(order, o); + }; + var r = new Retry<>(op, handleError, numOfRetries, retryDuration, + e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass())); + try { + r.perform(list, order); + } catch (Exception e1) { + e1.printStackTrace(); + } + }); + t.start(); + } + + private void handleSuccessMessageErrorIssue(Order order, Order o) { + if ((o.messageSent.equals(MessageSent.NONE_SENT) || o.messageSent + .equals(MessageSent.PAYMENT_TRYING)) + && System.currentTimeMillis() - o.createdTime < messageTime) { + var qt = new QueueTask(order, TaskType.MESSAGING, 2); + updateQueue(qt); + LOG.info("Order " + order.id + ": Error in sending Payment Success message, trying to" + + " queue task and add to employee handle.."); + employeeHandleIssue(order); + } + } + + private Retry.Operation handleSuccessMessageRetryOperation(Order order) { + return (l) -> { if (!l.isEmpty()) { if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { LOG.debug("Order " + order.id + ": Error in connecting to messaging service " @@ -342,34 +381,14 @@ public class Commander { } throw l.remove(0); } - if (!order.messageSent.equals(MessageSent.PaymentFail) - && !order.messageSent.equals(MessageSent.PaymentSuccessful)) { + if (!order.messageSent.equals(MessageSent.PAYMENT_FAIL) + && !order.messageSent.equals(MessageSent.PAYMENT_SUCCESSFUL)) { var requestId = messagingService.receiveRequest(2); - order.messageSent = MessageSent.PaymentSuccessful; + order.messageSent = MessageSent.PAYMENT_SUCCESSFUL; LOG.info("Order " + order.id + ": Payment Success message sent," + " request Id: " + requestId); } }; - Retry.HandleErrorIssue handleError = (o, err) -> { - if ((o.messageSent.equals(MessageSent.NoneSent) || o.messageSent - .equals(MessageSent.PaymentTrying)) - && System.currentTimeMillis() - o.createdTime < messageTime) { - var qt = new QueueTask(order, TaskType.Messaging, 2); - updateQueue(qt); - LOG.info("Order " + order.id + ": Error in sending Payment Success message, trying to" - + " queue task and add to employee handle.."); - employeeHandleIssue(order); - } - }; - var r = new Retry<>(op, handleError, numOfRetries, retryDuration, - e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass())); - try { - r.perform(list, order); - } catch (Exception e1) { - e1.printStackTrace(); - } - }); - t.start(); } private void sendPaymentFailureMessage(Order order) { @@ -380,34 +399,10 @@ public class Commander { var list = messagingService.exceptionsList; var t = new Thread(() -> { Retry.Operation op = (l) -> { - if (!l.isEmpty()) { - if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { - LOG.debug("Order " + order.id + ": Error in connecting to messaging service " - + "(Payment Failure msg), trying again.."); - } else { - LOG.debug("Order " + order.id + ": Error in creating Payment Failure" - + " message request.."); - } - throw l.remove(0); - } - if (!order.messageSent.equals(MessageSent.PaymentFail) - && !order.messageSent.equals(MessageSent.PaymentSuccessful)) { - var requestId = messagingService.receiveRequest(0); - order.messageSent = MessageSent.PaymentFail; - LOG.info("Order " + order.id + ": Payment Failure message sent successfully," - + " request Id: " + requestId); - } + handlePaymentFailureRetryOperation(order, l); }; Retry.HandleErrorIssue handleError = (o, err) -> { - if ((o.messageSent.equals(MessageSent.NoneSent) || o.messageSent - .equals(MessageSent.PaymentTrying)) - && System.currentTimeMillis() - o.createdTime < messageTime) { - var qt = new QueueTask(order, TaskType.Messaging, 0); - updateQueue(qt); - LOG.warn("Order " + order.id + ": Error in sending Payment Failure message, " - + "trying to queue task and add to employee handle.."); - employeeHandleIssue(o); - } + handlePaymentErrorIssue(order, o); }; var r = new Retry<>(op, handleError, numOfRetries, retryDuration, e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass())); @@ -420,6 +415,38 @@ public class Commander { t.start(); } + private void handlePaymentErrorIssue(Order order, Order o) { + if ((o.messageSent.equals(MessageSent.NONE_SENT) || o.messageSent + .equals(MessageSent.PAYMENT_TRYING)) + && System.currentTimeMillis() - o.createdTime < messageTime) { + var qt = new QueueTask(order, TaskType.MESSAGING, 0); + updateQueue(qt); + LOG.warn("Order " + order.id + ": Error in sending Payment Failure message, " + + "trying to queue task and add to employee handle.."); + employeeHandleIssue(o); + } + } + + private void handlePaymentFailureRetryOperation(Order order, List l) throws Exception { + if (!l.isEmpty()) { + if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { + LOG.debug("Order " + order.id + ": Error in connecting to messaging service " + + "(Payment Failure msg), trying again.."); + } else { + LOG.debug("Order " + order.id + ": Error in creating Payment Failure" + + " message request.."); + } + throw l.remove(0); + } + if (!order.messageSent.equals(MessageSent.PAYMENT_FAIL) + && !order.messageSent.equals(MessageSent.PAYMENT_SUCCESSFUL)) { + var requestId = messagingService.receiveRequest(0); + order.messageSent = MessageSent.PAYMENT_FAIL; + LOG.info("Order " + order.id + ": Payment Failure message sent successfully," + + " request Id: " + requestId); + } + } + private void sendPaymentPossibleErrorMsg(Order order) { if (System.currentTimeMillis() - order.createdTime >= this.messageTime) { LOG.trace("Message time for order over, returning.."); @@ -428,34 +455,10 @@ public class Commander { var list = messagingService.exceptionsList; var t = new Thread(() -> { Retry.Operation op = (l) -> { - if (!l.isEmpty()) { - if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { - LOG.debug("Order " + order.id + ": Error in connecting to messaging service " - + "(Payment Error msg), trying again.."); - } else { - LOG.debug("Order " + order.id + ": Error in creating Payment Error" - + " messaging request.."); - } - throw l.remove(0); - } - if (order.paid.equals(PaymentStatus.Trying) && order.messageSent - .equals(MessageSent.NoneSent)) { - var requestId = messagingService.receiveRequest(1); - order.messageSent = MessageSent.PaymentTrying; - LOG.info("Order " + order.id + ": Payment Error message sent successfully," - + " request Id: " + requestId); - } + handlePaymentPossibleErrorMsgRetryOperation(order, l); }; Retry.HandleErrorIssue handleError = (o, err) -> { - if (o.messageSent.equals(MessageSent.NoneSent) && order.paid - .equals(PaymentStatus.Trying) - && System.currentTimeMillis() - o.createdTime < messageTime) { - var qt = new QueueTask(order, TaskType.Messaging, 1); - updateQueue(qt); - LOG.warn("Order " + order.id + ": Error in sending Payment Error message, " - + "trying to queue task and add to employee handle.."); - employeeHandleIssue(o); - } + handlePaymentPossibleErrorMsgErrorIssue(order, o); }; var r = new Retry<>(op, handleError, numOfRetries, retryDuration, e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass())); @@ -468,6 +471,38 @@ public class Commander { t.start(); } + private void handlePaymentPossibleErrorMsgErrorIssue(Order order, Order o) { + if (o.messageSent.equals(MessageSent.NONE_SENT) && order.paid + .equals(PaymentStatus.TRYING) + && System.currentTimeMillis() - o.createdTime < messageTime) { + var qt = new QueueTask(order, TaskType.MESSAGING, 1); + updateQueue(qt); + LOG.warn("Order " + order.id + ": Error in sending Payment Error message, " + + "trying to queue task and add to employee handle.."); + employeeHandleIssue(o); + } + } + + private void handlePaymentPossibleErrorMsgRetryOperation(Order order, List l) throws Exception { + if (!l.isEmpty()) { + if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { + LOG.debug("Order " + order.id + ": Error in connecting to messaging service " + + "(Payment Error msg), trying again.."); + } else { + LOG.debug("Order " + order.id + ": Error in creating Payment Error" + + " messaging request.."); + } + throw l.remove(0); + } + if (order.paid.equals(PaymentStatus.TRYING) && order.messageSent + .equals(MessageSent.NONE_SENT)) { + var requestId = messagingService.receiveRequest(1); + order.messageSent = MessageSent.PAYMENT_TRYING; + LOG.info("Order " + order.id + ": Payment Error message sent successfully," + + " request Id: " + requestId); + } + } + private void employeeHandleIssue(Order order) { if (System.currentTimeMillis() - order.createdTime >= this.employeeTime) { LOG.trace("Order " + order.id + ": Employee handle time for order over, returning.."); @@ -490,7 +525,7 @@ public class Commander { Retry.HandleErrorIssue handleError = (o, err) -> { if (!o.addedToEmployeeHandle && System .currentTimeMillis() - order.createdTime < employeeTime) { - var qt = new QueueTask(order, TaskType.EmployeeDb, -1); + var qt = new QueueTask(order, TaskType.EMPLOYEE_DB, -1); updateQueue(qt); LOG.warn("Order " + order.id + ": Error in adding to employee db," + " trying to queue task.."); @@ -520,21 +555,21 @@ public class Commander { LOG.trace("Order " + qt.order.id + ": This queue task of type " + qt.getType() + " does not need to be done anymore (timeout), dequeue.."); } else { - if (qt.taskType.equals(TaskType.Payment)) { - if (!qt.order.paid.equals(PaymentStatus.Trying)) { + if (qt.taskType.equals(TaskType.PAYMENT)) { + if (!qt.order.paid.equals(PaymentStatus.TRYING)) { tryDequeue(); LOG.trace("Order " + qt.order.id + ": This payment task already done, dequeueing.."); } else { sendPaymentRequest(qt.order); LOG.debug("Order " + qt.order.id + ": Trying to connect to payment service.."); } - } else if (qt.taskType.equals(TaskType.Messaging)) { - if (qt.order.messageSent.equals(MessageSent.PaymentFail) - || qt.order.messageSent.equals(MessageSent.PaymentSuccessful)) { + } else if (qt.taskType.equals(TaskType.MESSAGING)) { + if (qt.order.messageSent.equals(MessageSent.PAYMENT_FAIL) + || qt.order.messageSent.equals(MessageSent.PAYMENT_SUCCESSFUL)) { tryDequeue(); LOG.trace("Order " + qt.order.id + ": This messaging task already done, dequeue.."); - } else if (qt.messageType == 1 && (!qt.order.messageSent.equals(MessageSent.NoneSent) - || !qt.order.paid.equals(PaymentStatus.Trying))) { + } else if (qt.messageType == 1 && (!qt.order.messageSent.equals(MessageSent.NONE_SENT) + || !qt.order.paid.equals(PaymentStatus.TRYING))) { tryDequeue(); LOG.trace("Order " + qt.order.id + ": This messaging task does not need to be done," + " dequeue.."); @@ -548,7 +583,7 @@ public class Commander { sendSuccessMessage(qt.order); LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service.."); } - } else if (qt.taskType.equals(TaskType.EmployeeDb)) { + } else if (qt.taskType.equals(TaskType.EMPLOYEE_DB)) { if (qt.order.addedToEmployeeHandle) { tryDequeue(); LOG.trace("Order " + qt.order.id + ": This employee handle task already done," diff --git a/commander/src/main/java/com/iluwatar/commander/Order.java b/commander/src/main/java/com/iluwatar/commander/Order.java index 87a9f794a..f736aa47c 100644 --- a/commander/src/main/java/com/iluwatar/commander/Order.java +++ b/commander/src/main/java/com/iluwatar/commander/Order.java @@ -33,11 +33,11 @@ import java.util.Random; public class Order { //can store all transactions ids also enum PaymentStatus { - NotDone, Trying, Done + NOT_DONE, TRYING, DONE } enum MessageSent { - NoneSent, PaymentFail, PaymentTrying, PaymentSuccessful + NONE_SENT, PAYMENT_FAIL, PAYMENT_TRYING, PAYMENT_SUCCESSFUL } final User user; @@ -65,8 +65,8 @@ public class Order { //can store all transactions ids also } this.id = id; USED_IDS.put(this.id, true); - this.paid = PaymentStatus.Trying; - this.messageSent = MessageSent.NoneSent; + this.paid = PaymentStatus.TRYING; + this.messageSent = MessageSent.NONE_SENT; this.addedToEmployeeHandle = false; } diff --git a/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingService.java b/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingService.java index 3fb385757..e353a4c7c 100644 --- a/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingService.java +++ b/commander/src/main/java/com/iluwatar/commander/messagingservice/MessagingService.java @@ -38,7 +38,7 @@ public class MessagingService extends Service { private static final Logger LOGGER = LoggerFactory.getLogger(MessagingService.class); enum MessageToSend { - PaymentFail, PaymentTrying, PaymentSuccessful + PAYMENT_FAIL, PAYMENT_TRYING, PAYMENT_SUCCESSFUL } class MessageRequest { @@ -63,11 +63,11 @@ public class MessagingService extends Service { var id = generateId(); MessageToSend msg; if (messageToSend == 0) { - msg = MessageToSend.PaymentFail; + msg = MessageToSend.PAYMENT_FAIL; } else if (messageToSend == 1) { - msg = MessageToSend.PaymentTrying; + msg = MessageToSend.PAYMENT_TRYING; } else { //messageToSend == 2 - msg = MessageToSend.PaymentSuccessful; + msg = MessageToSend.PAYMENT_SUCCESSFUL; } var req = new MessageRequest(id, msg); return updateDb(req); @@ -84,10 +84,10 @@ public class MessagingService extends Service { } String sendMessage(MessageToSend m) { - if (m.equals(MessageToSend.PaymentSuccessful)) { + if (m.equals(MessageToSend.PAYMENT_SUCCESSFUL)) { return "Msg: Your order has been placed and paid for successfully!" + " Thank you for shopping with us!"; - } else if (m.equals(MessageToSend.PaymentTrying)) { + } else if (m.equals(MessageToSend.PAYMENT_TRYING)) { return "Msg: There was an error in your payment process," + " we are working on it and will return back to you shortly." + " Meanwhile, your order has been placed and will be shipped."; diff --git a/commander/src/main/java/com/iluwatar/commander/queue/QueueTask.java b/commander/src/main/java/com/iluwatar/commander/queue/QueueTask.java index a27dd62b8..341eb628c 100644 --- a/commander/src/main/java/com/iluwatar/commander/queue/QueueTask.java +++ b/commander/src/main/java/com/iluwatar/commander/queue/QueueTask.java @@ -36,7 +36,7 @@ public class QueueTask { */ public enum TaskType { - Messaging, Payment, EmployeeDb + MESSAGING, PAYMENT, EMPLOYEE_DB } public Order order; @@ -68,7 +68,7 @@ public class QueueTask { * @return String representing type of task */ public String getType() { - if (!this.taskType.equals(TaskType.Messaging)) { + if (!this.taskType.equals(TaskType.MESSAGING)) { return this.taskType.toString(); } else { if (this.messageType == 0) { diff --git a/composite/src/test/java/com/iluwatar/composite/AppTest.java b/composite/src/test/java/com/iluwatar/composite/AppTest.java index 5eb8c35c7..c82056a51 100644 --- a/composite/src/test/java/com/iluwatar/composite/AppTest.java +++ b/composite/src/test/java/com/iluwatar/composite/AppTest.java @@ -23,15 +23,23 @@ package com.iluwatar.composite; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * 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#main(String[])} + * throws an exception. + */ @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + Assertions.assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/converter/src/test/java/com/iluwatar/converter/AppTest.java b/converter/src/test/java/com/iluwatar/converter/AppTest.java index ed53c6863..7a99fe6ae 100644 --- a/converter/src/test/java/com/iluwatar/converter/AppTest.java +++ b/converter/src/test/java/com/iluwatar/converter/AppTest.java @@ -25,14 +25,24 @@ package com.iluwatar.converter; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * App running 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#main(String[])} + * throws an exception. + */ @Test - public void testMain() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/dao/src/test/java/com/iluwatar/dao/AppTest.java b/dao/src/test/java/com/iluwatar/dao/AppTest.java index edfcf7cd0..e6d41fc8a 100644 --- a/dao/src/test/java/com/iluwatar/dao/AppTest.java +++ b/dao/src/test/java/com/iluwatar/dao/AppTest.java @@ -25,12 +25,22 @@ package com.iluwatar.dao; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that DAO 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() throws Exception { - App.main(new String[]{}); + void shouldExecuteDaoWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/AiComponent.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/AiComponent.java index 5b1be9e35..40acb2f71 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/AiComponent.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/AiComponent.java @@ -43,6 +43,6 @@ public class AiComponent implements Component { @Override public void render() { - + // Do Nothing. } } diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java index 616ebf801..1baf99a3a 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java @@ -40,7 +40,7 @@ public class AiComponentManager { private final int numEntities; - private static final Component[] AI_COMPONENTS = new AiComponent[MAX_ENTITIES]; + private final Component[] AI_COMPONENTS = new AiComponent[MAX_ENTITIES]; public AiComponentManager(int numEntities) { this.numEntities = numEntities; diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java index 61ba4ebdd..e5917979c 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java @@ -40,7 +40,7 @@ public class PhysicsComponentManager { private final int numEntities; - private static final Component[] PHYSICS_COMPONENTS = new PhysicsComponent[MAX_ENTITIES]; + private final Component[] PHYSICS_COMPONENTS = new PhysicsComponent[MAX_ENTITIES]; public PhysicsComponentManager(int numEntities) { this.numEntities = numEntities; diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java index f8c4b3522..b3522f908 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java @@ -40,7 +40,7 @@ public class RenderComponentManager { private final int numEntities; - private static final Component[] RENDER_COMPONENTS = new RenderComponent[MAX_ENTITIES]; + private final Component[] RENDER_COMPONENTS = new RenderComponent[MAX_ENTITIES]; public RenderComponentManager(int numEntities) { this.numEntities = numEntities; diff --git a/data-locality/src/test/java/com/iluwatar/data/locality/ApplicationTest.java b/data-locality/src/test/java/com/iluwatar/data/locality/ApplicationTest.java index 3371be4c1..b7d1f8961 100644 --- a/data-locality/src/test/java/com/iluwatar/data/locality/ApplicationTest.java +++ b/data-locality/src/test/java/com/iluwatar/data/locality/ApplicationTest.java @@ -26,16 +26,22 @@ package com.iluwatar.data.locality; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Test Game Application */ class ApplicationTest { /** - * Test run + * Issue: Add at least one assertion to this test case. + * + * Solution: Inserted assertion to check whether the execution of the main method in {@link Application#main(String[])} + * throws an exception. */ + @Test - void main() { - Application.main(new String[] {}); + void shouldExecuteGameApplicationWithoutException() { + assertDoesNotThrow(() -> Application.main(new String[] {})); } } \ No newline at end of file diff --git a/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java b/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java index ec1d71be4..ab74edd6c 100644 --- a/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java +++ b/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java @@ -24,14 +24,25 @@ package com.iluwatar.datamapper; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; /** * Tests that Data-Mapper example runs without errors. */ -public final class AppTest { +final 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(); + void shouldExecuteApplicationWithoutException() { + + assertDoesNotThrow((Executable) App::main); } } diff --git a/data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java index 3a58d0c54..68a8b9444 100644 --- a/data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java +++ b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/AppTest.java @@ -25,9 +25,19 @@ package com.iluwatar.datatransfer; import org.junit.jupiter.api.Test; -public class AppTest { +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +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() throws Exception { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/decorator/src/test/java/com/iluwatar/decorator/AppTest.java b/decorator/src/test/java/com/iluwatar/decorator/AppTest.java index e8d4c8505..792d61233 100644 --- a/decorator/src/test/java/com/iluwatar/decorator/AppTest.java +++ b/decorator/src/test/java/com/iluwatar/decorator/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.decorator; 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#main(String[])} + * throws an exception. + */ @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java index 2865c76c1..8e20c9032 100644 --- a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java +++ b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java @@ -25,14 +25,23 @@ package com.iluwatar.delegation.simple; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application Test Entry */ -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/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java index 51115496d..52508814a 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.dependency.injection; 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#main(String[])} + * throws an exception. + */ @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/dirty-flag/src/test/java/org/dirty/flag/AppTest.java b/dirty-flag/src/test/java/org/dirty/flag/AppTest.java index 1b604898b..82c7fea9b 100644 --- a/dirty-flag/src/test/java/org/dirty/flag/AppTest.java +++ b/dirty-flag/src/test/java/org/dirty/flag/AppTest.java @@ -26,12 +26,22 @@ package org.dirty.flag; import com.iluwatar.dirtyflag.App; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Dirty-Flag 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/double-buffer/pom.xml b/double-buffer/pom.xml index 084cbc8c9..cb66af1cb 100644 --- a/double-buffer/pom.xml +++ b/double-buffer/pom.xml @@ -44,6 +44,11 @@ org.apache.commons commons-lang3 + + org.junit.jupiter + junit-jupiter-engine + test + diff --git a/double-buffer/src/test/java/com/iluwatar/doublebuffer/AppTest.java b/double-buffer/src/test/java/com/iluwatar/doublebuffer/AppTest.java index eb89a4044..6612d2b00 100644 --- a/double-buffer/src/test/java/com/iluwatar/doublebuffer/AppTest.java +++ b/double-buffer/src/test/java/com/iluwatar/doublebuffer/AppTest.java @@ -25,14 +25,23 @@ package com.iluwatar.doublebuffer; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * App unit test. */ public 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 testMain() { - App.main(new String[]{}); + public void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java index 6eac88fcd..e24e51094 100644 --- a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java +++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java @@ -25,13 +25,23 @@ package com.iluwatar.doublechecked.locking; 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#main(String[])} + * throws an exception. + */ + @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java index 67ca00c56..e5df7a2be 100644 --- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java +++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java @@ -25,13 +25,23 @@ package com.iluwatar.doubledispatch; 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#main(String[])} + * throws an exception. + */ + @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java index ed604e8c2..3da3b3e66 100644 --- a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java +++ b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.eip.aggregator; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Test for App class */ -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 testMain() throws Exception { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/eip-message-channel/src/test/java/com/iluwatar/eip/message/channel/AppTest.java b/eip-message-channel/src/test/java/com/iluwatar/eip/message/channel/AppTest.java index 9f11c0209..14cdc5c65 100644 --- a/eip-message-channel/src/test/java/com/iluwatar/eip/message/channel/AppTest.java +++ b/eip-message-channel/src/test/java/com/iluwatar/eip/message/channel/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.eip.message.channel; 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#main(String[])} + * throws an exception. + */ @Test - public void test() throws Exception { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/eip-publish-subscribe/src/test/java/com/iluwatar/eip/publish/subscribe/AppTest.java b/eip-publish-subscribe/src/test/java/com/iluwatar/eip/publish/subscribe/AppTest.java index 107e954ed..f910d0abe 100644 --- a/eip-publish-subscribe/src/test/java/com/iluwatar/eip/publish/subscribe/AppTest.java +++ b/eip-publish-subscribe/src/test/java/com/iluwatar/eip/publish/subscribe/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.eip.publish.subscribe; 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#main(String[])} + * throws an exception. + */ @Test - public void test() throws Exception { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java index 1a7dfcb0a..d5936282e 100644 --- a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java +++ b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.eip.splitter; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Test for App class */ -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 testMain() throws Exception { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java b/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java index 31154043c..8be8bcbe7 100644 --- a/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java +++ b/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.eip.wiretap; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Test for App class */ -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 testMain() throws Exception { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java index a65424023..e56bc9d7f 100644 --- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java +++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java @@ -25,13 +25,22 @@ package com.iluwatar.event.aggregator; 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#main(String[])} + * throws an exception. + */ @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java index 76554d6b1..638e77f87 100644 --- a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java @@ -25,12 +25,22 @@ package com.iluwatar.event.asynchronous; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that EventAsynchronous 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/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java b/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java index 0f1720363..eb944a22c 100644 --- a/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java +++ b/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java @@ -25,12 +25,22 @@ package com.iluwatar.eda; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Event Driven Architecture 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/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java index 5512ba8d2..6516ede4a 100644 --- a/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java +++ b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java @@ -29,19 +29,21 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests execute-around example. */ -public class AppTest { +class AppTest { @Test - public void test() throws IOException { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } @BeforeEach @AfterEach - public void cleanup() { + void cleanup() { var file = new File("testfile.txt"); file.delete(); } diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java index 1d8054562..ffd46dd25 100644 --- a/extension-objects/src/main/java/concreteextensions/Commander.java +++ b/extension-objects/src/main/java/concreteextensions/Commander.java @@ -45,4 +45,8 @@ public class Commander implements CommanderExtension { public void commanderReady() { LOGGER.info("[Commander] " + unit.getName() + " is ready!"); } + + public CommanderUnit getUnit() { + return unit; + } } diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java index 4f5a474b3..aea2ddaca 100644 --- a/extension-objects/src/main/java/concreteextensions/Sergeant.java +++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java @@ -43,6 +43,10 @@ public class Sergeant implements SergeantExtension { @Override public void sergeantReady() { - LOGGER.info("[Sergeant] " + unit.getName() + " is ready! "); + LOGGER.info("[Sergeant] " + unit.getName() + " is ready!"); + } + + public SergeantUnit getUnit() { + return unit; } } diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java index d500ab604..76ddbfd06 100644 --- a/extension-objects/src/main/java/concreteextensions/Soldier.java +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -44,4 +44,8 @@ public class Soldier implements SoldierExtension { public void soldierReady() { LOGGER.info("[Solider] " + unit.getName() + " is ready!"); } + + public SoldierUnit getUnit() { + return unit; + } } diff --git a/extension-objects/src/test/java/AppTest.java b/extension-objects/src/test/java/AppTest.java index 2af33e506..321bf758f 100644 --- a/extension-objects/src/test/java/AppTest.java +++ b/extension-objects/src/test/java/AppTest.java @@ -23,13 +23,16 @@ import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Created by Srdjan on 03-May-17. */ -public class AppTest { +class AppTest { + @Test - public void main() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } \ No newline at end of file diff --git a/extension-objects/src/test/java/concreteextensions/CommanderTest.java b/extension-objects/src/test/java/concreteextensions/CommanderTest.java index 60ff614e4..0c9d00baf 100644 --- a/extension-objects/src/test/java/concreteextensions/CommanderTest.java +++ b/extension-objects/src/test/java/concreteextensions/CommanderTest.java @@ -23,17 +23,43 @@ package concreteextensions; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; import units.CommanderUnit; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Created by Srdjan on 03-May-17. + * + * Modified by ToxicDreamz on 15-Aug-20 */ -public class CommanderTest { +class CommanderTest { + @Test - public void commanderReady() { + void shouldExecuteCommanderReady() { + + Logger commanderLogger = (Logger) LoggerFactory.getLogger(Commander.class); + + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); + + commanderLogger.addAppender(listAppender); + final var commander = new Commander(new CommanderUnit("CommanderUnitTest")); commander.commanderReady(); + + List logsList = listAppender.list; + assertEquals("[Commander] " + commander.getUnit().getName() + " is ready!", logsList.get(0) + .getMessage()); + assertEquals(Level.INFO, logsList.get(0) + .getLevel()); } } \ No newline at end of file diff --git a/extension-objects/src/test/java/concreteextensions/SergeantTest.java b/extension-objects/src/test/java/concreteextensions/SergeantTest.java index a5a60d914..3970a5c80 100644 --- a/extension-objects/src/test/java/concreteextensions/SergeantTest.java +++ b/extension-objects/src/test/java/concreteextensions/SergeantTest.java @@ -23,17 +23,41 @@ package concreteextensions; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; import units.SergeantUnit; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Created by Srdjan on 03-May-17. */ -public class SergeantTest { +class SergeantTest { + @Test - public void sergeantReady() { + void sergeantReady() { + + Logger sergeantLogger = (Logger) LoggerFactory.getLogger(Sergeant.class); + + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); + + sergeantLogger.addAppender(listAppender); + final var sergeant = new Sergeant(new SergeantUnit("SergeantUnitTest")); sergeant.sergeantReady(); + + List logsList = listAppender.list; + assertEquals("[Sergeant] " + sergeant.getUnit().getName() + " is ready!", logsList.get(0) + .getMessage()); + assertEquals(Level.INFO, logsList.get(0) + .getLevel()); } } \ No newline at end of file diff --git a/extension-objects/src/test/java/concreteextensions/SoldierTest.java b/extension-objects/src/test/java/concreteextensions/SoldierTest.java index 89c8c2d91..98224e848 100644 --- a/extension-objects/src/test/java/concreteextensions/SoldierTest.java +++ b/extension-objects/src/test/java/concreteextensions/SoldierTest.java @@ -23,17 +23,41 @@ package concreteextensions; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; import units.SoldierUnit; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Created by Srdjan on 03-May-17. */ -public class SoldierTest { +class SoldierTest { + @Test - public void soldierReady() { + void soldierReady() { + + Logger soldierLogger = (Logger) LoggerFactory.getLogger(Soldier.class); + + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); + + soldierLogger.addAppender(listAppender); + final var soldier = new Soldier(new SoldierUnit("SoldierUnitTest")); soldier.soldierReady(); + + List logsList = listAppender.list; + assertEquals("[Soldier] " + soldier.getUnit().getName() + " is ready!", logsList.get(0) + .getMessage()); + assertEquals(Level.INFO, logsList.get(0) + .getLevel()); } } \ No newline at end of file diff --git a/facade/src/test/java/com/iluwatar/facade/AppTest.java b/facade/src/test/java/com/iluwatar/facade/AppTest.java index b6287b02b..7e2d389dc 100644 --- a/facade/src/test/java/com/iluwatar/facade/AppTest.java +++ b/facade/src/test/java/com/iluwatar/facade/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.facade; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java index f1d3c65a2..99477aaf0 100644 --- a/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java +++ b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java @@ -26,14 +26,16 @@ package com.iluwatar.factorykit.app; import com.iluwatar.factorykit.App; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application Test Entrypoint */ -public class AppTest { +class AppTest { @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java b/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java index c23295d9a..8756ba0aa 100644 --- a/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java +++ b/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.factory.method; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Factory Method example runs without errors. */ -public class AppTest { +class AppTest { + @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java index 6f25d8416..1b6671917 100644 --- a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java +++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.fluentinterface.app; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application Test Entry */ -public class AppTest { +class AppTest { @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java index 27d374f5d..c43d87680 100644 --- a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java +++ b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java @@ -57,15 +57,10 @@ public final class Dispatcher { */ public void menuItemSelected(MenuItem menuItem) { dispatchAction(new MenuAction(menuItem)); - switch (menuItem) { - case HOME: - case PRODUCTS: - default: - dispatchAction(new ContentAction(Content.PRODUCTS)); - break; - case COMPANY: - dispatchAction(new ContentAction(Content.COMPANY)); - break; + if (menuItem == MenuItem.COMPANY) { + dispatchAction(new ContentAction(Content.COMPANY)); + } else { + dispatchAction(new ContentAction(Content.PRODUCTS)); } } diff --git a/flux/src/test/java/com/iluwatar/flux/app/AppTest.java b/flux/src/test/java/com/iluwatar/flux/app/AppTest.java index 8916ad4de..649708d8f 100644 --- a/flux/src/test/java/com/iluwatar/flux/app/AppTest.java +++ b/flux/src/test/java/com/iluwatar/flux/app/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.flux.app; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java b/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java index 3d81a6db2..5f957c794 100644 --- a/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java +++ b/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.flyweight; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java index 2ea58c6a6..cf33bfb48 100644 --- a/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java +++ b/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.front.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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/game-loop/pom.xml b/game-loop/pom.xml index 2c2908271..706d3cff4 100644 --- a/game-loop/pom.xml +++ b/game-loop/pom.xml @@ -39,6 +39,12 @@ junit junit + + + org.junit.jupiter + junit-jupiter-engine + test + diff --git a/game-loop/src/test/java/com/iluwatar/gameloop/AppTest.java b/game-loop/src/test/java/com/iluwatar/gameloop/AppTest.java index 447e4f411..0c027028d 100644 --- a/game-loop/src/test/java/com/iluwatar/gameloop/AppTest.java +++ b/game-loop/src/test/java/com/iluwatar/gameloop/AppTest.java @@ -25,14 +25,16 @@ package com.iluwatar.gameloop; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * App unit test class. */ public class AppTest { @Test - public void testMain() { - new App().main(new String[]{}); + public void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AppTest.java b/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AppTest.java index b3cf4839b..395599927 100644 --- a/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AppTest.java +++ b/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.halfsynchalfasync; 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() { - App.main(null); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(null)); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java index 96ab74ba3..6d6c33239 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java @@ -46,6 +46,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { private static final String DEFAULT_DB = "lotteryDB"; private static final String DEFAULT_TICKETS_COLLECTION = "lotteryTickets"; private static final String DEFAULT_COUNTERS_COLLECTION = "counters"; + private static final String TICKET_ID = "ticketId"; private MongoClient mongoClient; private MongoDatabase database; @@ -93,7 +94,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { } private void initCounters() { - var doc = new Document("_id", "ticketId").append("seq", 1); + var doc = new Document("_id", TICKET_ID).append("seq", 1); countersCollection.insertOne(doc); } @@ -103,7 +104,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { * @return next ticket id */ public int getNextId() { - var find = new Document("_id", "ticketId"); + var find = new Document("_id", TICKET_ID); var increase = new Document("seq", 1); var update = new Document("$inc", increase); var result = countersCollection.findOneAndUpdate(find, update); @@ -131,7 +132,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { @Override public Optional findById(LotteryTicketId id) { return ticketsCollection - .find(new Document("ticketId", id.getId())) + .find(new Document(TICKET_ID, id.getId())) .limit(1) .into(new ArrayList<>()) .stream() @@ -142,7 +143,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { @Override public Optional save(LotteryTicket ticket) { var ticketId = getNextId(); - var doc = new Document("ticketId", ticketId); + var doc = new Document(TICKET_ID, ticketId); doc.put("email", ticket.getPlayerDetails().getEmail()); doc.put("bank", ticket.getPlayerDetails().getBankAccount()); doc.put("phone", ticket.getPlayerDetails().getPhoneNumber()); @@ -173,7 +174,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { .map(Integer::parseInt) .collect(Collectors.toSet()); var lotteryNumbers = LotteryNumbers.create(numbers); - var ticketId = new LotteryTicketId(doc.getInteger("ticketId")); + var ticketId = new LotteryTicketId(doc.getInteger(TICKET_ID)); return new LotteryTicket(ticketId, playerDetails, lotteryNumbers); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java index c632debe8..62fcf32b4 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java @@ -36,6 +36,9 @@ public class MongoEventLog implements LotteryEventLog { private static final String DEFAULT_DB = "lotteryDB"; private static final String DEFAULT_EVENTS_COLLECTION = "events"; + private static final String EMAIL = "email"; + private static final String PHONE = "phone"; + public static final String MESSAGE = "message"; private MongoClient mongoClient; private MongoDatabase database; @@ -107,41 +110,41 @@ public class MongoEventLog implements LotteryEventLog { @Override public void ticketSubmitted(PlayerDetails details) { - var document = new Document("email", details.getEmail()); - document.put("phone", details.getPhoneNumber()); + var document = new Document(EMAIL, details.getEmail()); + document.put(PHONE, details.getPhoneNumber()); document.put("bank", details.getBankAccount()); document - .put("message", "Lottery ticket was submitted and bank account was charged for 3 credits."); + .put(MESSAGE, "Lottery ticket was submitted and bank account was charged for 3 credits."); eventsCollection.insertOne(document); stdOutEventLog.ticketSubmitted(details); } @Override public void ticketSubmitError(PlayerDetails details) { - var document = new Document("email", details.getEmail()); - document.put("phone", details.getPhoneNumber()); + var document = new Document(EMAIL, details.getEmail()); + document.put(PHONE, details.getPhoneNumber()); document.put("bank", details.getBankAccount()); - document.put("message", "Lottery ticket could not be submitted because lack of funds."); + document.put(MESSAGE, "Lottery ticket could not be submitted because lack of funds."); eventsCollection.insertOne(document); stdOutEventLog.ticketSubmitError(details); } @Override public void ticketDidNotWin(PlayerDetails details) { - var document = new Document("email", details.getEmail()); - document.put("phone", details.getPhoneNumber()); + var document = new Document(EMAIL, details.getEmail()); + document.put(PHONE, details.getPhoneNumber()); document.put("bank", details.getBankAccount()); - document.put("message", "Lottery ticket was checked and unfortunately did not win this time."); + document.put(MESSAGE, "Lottery ticket was checked and unfortunately did not win this time."); eventsCollection.insertOne(document); stdOutEventLog.ticketDidNotWin(details); } @Override public void ticketWon(PlayerDetails details, int prizeAmount) { - var document = new Document("email", details.getEmail()); - document.put("phone", details.getPhoneNumber()); + var document = new Document(EMAIL, details.getEmail()); + document.put(PHONE, details.getPhoneNumber()); document.put("bank", details.getBankAccount()); - document.put("message", String + document.put(MESSAGE, String .format("Lottery ticket won! The bank account was deposited with %d credits.", prizeAmount)); eventsCollection.insertOne(document); @@ -150,10 +153,10 @@ public class MongoEventLog implements LotteryEventLog { @Override public void prizeError(PlayerDetails details, int prizeAmount) { - var document = new Document("email", details.getEmail()); - document.put("phone", details.getPhoneNumber()); + var document = new Document(EMAIL, details.getEmail()); + document.put(PHONE, details.getPhoneNumber()); document.put("bank", details.getBankAccount()); - document.put("message", String + document.put(MESSAGE, String .format("Lottery ticket won! Unfortunately the bank credit transfer of %d failed.", prizeAmount)); eventsCollection.insertOne(document); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/AppTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/AppTest.java index 05d51a283..d2ad89c9b 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/AppTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/AppTest.java @@ -25,13 +25,16 @@ package com.iluwatar.hexagonal; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Unit test for simple App. */ class AppTest { @Test - void testApp() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } } diff --git a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java index 8fbe9f1d2..d8f22a478 100644 --- a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java +++ b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.intercepting.filter; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java index 505dc559c..f4fb45637 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.interpreter; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/iterator/src/test/java/com/iluwatar/iterator/AppTest.java b/iterator/src/test/java/com/iluwatar/iterator/AppTest.java index ccb33307c..2e0d28b67 100644 --- a/iterator/src/test/java/com/iluwatar/iterator/AppTest.java +++ b/iterator/src/test/java/com/iluwatar/iterator/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.iterator; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application Test */ class AppTest { @Test - void testApp() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } \ No newline at end of file diff --git a/layers/src/main/java/com/iluwatar/layers/app/App.java b/layers/src/main/java/com/iluwatar/layers/app/App.java index e5a4f9995..8574b8d02 100644 --- a/layers/src/main/java/com/iluwatar/layers/app/App.java +++ b/layers/src/main/java/com/iluwatar/layers/app/App.java @@ -81,6 +81,7 @@ import java.util.List; public class App { private static final CakeBakingService cakeBakingService = new CakeBakingServiceImpl(); + public static final String STRAWBERRY = "strawberry"; /** * Application entry point. @@ -103,10 +104,10 @@ public class App { private static void initializeData(CakeBakingService cakeBakingService) { cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200)); cakeBakingService.saveNewLayer(new CakeLayerInfo("banana", 900)); - cakeBakingService.saveNewLayer(new CakeLayerInfo("strawberry", 950)); + cakeBakingService.saveNewLayer(new CakeLayerInfo(STRAWBERRY, 950)); cakeBakingService.saveNewLayer(new CakeLayerInfo("lemon", 950)); cakeBakingService.saveNewLayer(new CakeLayerInfo("vanilla", 950)); - cakeBakingService.saveNewLayer(new CakeLayerInfo("strawberry", 950)); + cakeBakingService.saveNewLayer(new CakeLayerInfo(STRAWBERRY, 950)); cakeBakingService.saveNewTopping(new CakeToppingInfo("candies", 350)); cakeBakingService.saveNewTopping(new CakeToppingInfo("cherry", 350)); @@ -114,7 +115,7 @@ public class App { var cake1 = new CakeInfo(new CakeToppingInfo("candies", 0), List.of( new CakeLayerInfo("chocolate", 0), new CakeLayerInfo("banana", 0), - new CakeLayerInfo("strawberry", 0))); + new CakeLayerInfo(STRAWBERRY, 0))); try { cakeBakingService.bakeNewCake(cake1); } catch (CakeBakingException e) { @@ -123,7 +124,7 @@ public class App { var cake2 = new CakeInfo(new CakeToppingInfo("cherry", 0), List.of( new CakeLayerInfo("vanilla", 0), new CakeLayerInfo("lemon", 0), - new CakeLayerInfo("strawberry", 0))); + new CakeLayerInfo(STRAWBERRY, 0))); try { cakeBakingService.bakeNewCake(cake2); } catch (CakeBakingException e) { diff --git a/layers/src/test/java/com/iluwatar/layers/app/AppTest.java b/layers/src/test/java/com/iluwatar/layers/app/AppTest.java index 10d224a8e..105487683 100644 --- a/layers/src/test/java/com/iluwatar/layers/app/AppTest.java +++ b/layers/src/test/java/com/iluwatar/layers/app/AppTest.java @@ -23,19 +23,19 @@ package com.iluwatar.layers.app; -import com.iluwatar.layers.app.App; 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/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java index eeccd10ce..74c324b24 100644 --- a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java +++ b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java @@ -25,16 +25,17 @@ package com.iluwatar.lazy.loading; 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/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractInstance.java b/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractInstance.java index f30610597..94db89ef7 100644 --- a/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractInstance.java +++ b/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractInstance.java @@ -36,6 +36,7 @@ public abstract class AbstractInstance implements Instance, Runnable { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractInstance.class); protected static final int HEARTBEAT_INTERVAL = 5000; + private static final String INSTANCE = "Instance "; protected MessageManager messageManager; protected Queue messageQueue; @@ -106,27 +107,27 @@ public abstract class AbstractInstance implements Instance, Runnable { private void processMessage(Message message) { switch (message.getType()) { case ELECTION: - LOGGER.info("Instance " + localId + " - Election Message handling..."); + LOGGER.info(INSTANCE + localId + " - Election Message handling..."); handleElectionMessage(message); break; case LEADER: - LOGGER.info("Instance " + localId + " - Leader Message handling..."); + LOGGER.info(INSTANCE + localId + " - Leader Message handling..."); handleLeaderMessage(message); break; case HEARTBEAT: - LOGGER.info("Instance " + localId + " - Heartbeat Message handling..."); + LOGGER.info(INSTANCE + localId + " - Heartbeat Message handling..."); handleHeartbeatMessage(message); break; case ELECTION_INVOKE: - LOGGER.info("Instance " + localId + " - Election Invoke Message handling..."); + LOGGER.info(INSTANCE + localId + " - Election Invoke Message handling..."); handleElectionInvokeMessage(); break; case LEADER_INVOKE: - LOGGER.info("Instance " + localId + " - Leader Invoke Message handling..."); + LOGGER.info(INSTANCE + localId + " - Leader Invoke Message handling..."); handleLeaderInvokeMessage(); break; case HEARTBEAT_INVOKE: - LOGGER.info("Instance " + localId + " - Heartbeat Invoke Message handling..."); + LOGGER.info(INSTANCE + localId + " - Heartbeat Invoke Message handling..."); handleHeartbeatInvokeMessage(); break; default: diff --git a/leader-election/src/main/java/com/iluwatar/leaderelection/bully/BullyInstance.java b/leader-election/src/main/java/com/iluwatar/leaderelection/bully/BullyInstance.java index 92cb18ab4..3181791d4 100644 --- a/leader-election/src/main/java/com/iluwatar/leaderelection/bully/BullyInstance.java +++ b/leader-election/src/main/java/com/iluwatar/leaderelection/bully/BullyInstance.java @@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory; public class BullyInstance extends AbstractInstance { private static final Logger LOGGER = LoggerFactory.getLogger(BullyInstance.class); + private static final String INSTANCE = "Instance "; /** * Constructor of BullyInstance. @@ -59,20 +60,20 @@ public class BullyInstance extends AbstractInstance { try { boolean isLeaderAlive = messageManager.sendHeartbeatMessage(leaderId); if (isLeaderAlive) { - LOGGER.info("Instance " + localId + "- Leader is alive."); + LOGGER.info(INSTANCE + localId + "- Leader is alive."); Thread.sleep(HEARTBEAT_INTERVAL); messageManager.sendHeartbeatInvokeMessage(localId); } else { - LOGGER.info("Instance " + localId + "- Leader is not alive. Start election."); + LOGGER.info(INSTANCE + localId + "- Leader is not alive. Start election."); boolean electionResult = messageManager.sendElectionMessage(localId, String.valueOf(localId)); if (electionResult) { - LOGGER.info("Instance " + localId + "- Succeed in election. Start leader notification."); + LOGGER.info(INSTANCE + localId + "- Succeed in election. Start leader notification."); messageManager.sendLeaderMessage(localId, localId); } } } catch (InterruptedException e) { - LOGGER.info("Instance " + localId + "- Interrupted."); + LOGGER.info(INSTANCE + localId + "- Interrupted."); } } @@ -84,10 +85,10 @@ public class BullyInstance extends AbstractInstance { @Override protected void handleElectionInvokeMessage() { if (!isLeader()) { - LOGGER.info("Instance " + localId + "- Start election."); + LOGGER.info(INSTANCE + localId + "- Start election."); boolean electionResult = messageManager.sendElectionMessage(localId, String.valueOf(localId)); if (electionResult) { - LOGGER.info("Instance " + localId + "- Succeed in election. Start leader notification."); + LOGGER.info(INSTANCE + localId + "- Succeed in election. Start leader notification."); leaderId = localId; messageManager.sendLeaderMessage(localId, localId); messageManager.sendHeartbeatInvokeMessage(localId); @@ -101,25 +102,25 @@ public class BullyInstance extends AbstractInstance { @Override protected void handleLeaderMessage(Message message) { leaderId = Integer.valueOf(message.getContent()); - LOGGER.info("Instance " + localId + " - Leader update done."); + LOGGER.info(INSTANCE + localId + " - Leader update done."); } private boolean isLeader() { return localId == leaderId; } - /** - * Not used in Bully instance. - */ @Override protected void handleLeaderInvokeMessage() { + // Not used in Bully Instance } @Override protected void handleHeartbeatMessage(Message message) { + // Not used in Bully Instance } @Override protected void handleElectionMessage(Message message) { + // Not used in Bully Instance } } diff --git a/leader-election/src/main/java/com/iluwatar/leaderelection/ring/RingInstance.java b/leader-election/src/main/java/com/iluwatar/leaderelection/ring/RingInstance.java index d4a3075d8..2d2d0ae1a 100644 --- a/leader-election/src/main/java/com/iluwatar/leaderelection/ring/RingInstance.java +++ b/leader-election/src/main/java/com/iluwatar/leaderelection/ring/RingInstance.java @@ -46,6 +46,7 @@ import org.slf4j.LoggerFactory; public class RingInstance extends AbstractInstance { private static final Logger LOGGER = LoggerFactory.getLogger(RingInstance.class); + private static final String INSTANCE = "Instance "; /** * Constructor of RingInstance. @@ -64,15 +65,15 @@ public class RingInstance extends AbstractInstance { try { var isLeaderAlive = messageManager.sendHeartbeatMessage(this.leaderId); if (isLeaderAlive) { - LOGGER.info("Instance " + localId + "- Leader is alive. Start next heartbeat in 5 second."); + LOGGER.info(INSTANCE + localId + "- Leader is alive. Start next heartbeat in 5 second."); Thread.sleep(HEARTBEAT_INTERVAL); messageManager.sendHeartbeatInvokeMessage(this.localId); } else { - LOGGER.info("Instance " + localId + "- Leader is not alive. Start election."); + LOGGER.info(INSTANCE + localId + "- Leader is not alive. Start election."); messageManager.sendElectionMessage(this.localId, String.valueOf(this.localId)); } } catch (InterruptedException e) { - LOGGER.info("Instance " + localId + "- Interrupted."); + LOGGER.info(INSTANCE + localId + "- Interrupted."); } } @@ -85,14 +86,14 @@ public class RingInstance extends AbstractInstance { @Override protected void handleElectionMessage(Message message) { var content = message.getContent(); - LOGGER.info("Instance " + localId + " - Election Message: " + content); + LOGGER.info(INSTANCE + localId + " - Election Message: " + content); var candidateList = Arrays.stream(content.trim().split(",")) .map(Integer::valueOf) .sorted() .collect(Collectors.toList()); if (candidateList.contains(localId)) { var newLeaderId = candidateList.get(0); - LOGGER.info("Instance " + localId + " - New leader should be " + newLeaderId + "."); + LOGGER.info(INSTANCE + localId + " - New leader should be " + newLeaderId + "."); messageManager.sendLeaderMessage(localId, newLeaderId); } else { content += "," + localId; @@ -108,11 +109,11 @@ public class RingInstance extends AbstractInstance { protected void handleLeaderMessage(Message message) { var newLeaderId = Integer.valueOf(message.getContent()); if (this.leaderId != newLeaderId) { - LOGGER.info("Instance " + localId + " - Update leaderID"); + LOGGER.info(INSTANCE + localId + " - Update leaderID"); this.leaderId = newLeaderId; messageManager.sendLeaderMessage(localId, newLeaderId); } else { - LOGGER.info("Instance " + localId + " - Leader update done. Start heartbeat."); + LOGGER.info(INSTANCE + localId + " - Leader update done. Start heartbeat."); messageManager.sendHeartbeatInvokeMessage(localId); } } @@ -122,14 +123,17 @@ public class RingInstance extends AbstractInstance { */ @Override protected void handleLeaderInvokeMessage() { + // Not used in Ring instance. } @Override protected void handleHeartbeatMessage(Message message) { + // Not used in Ring instance. } @Override protected void handleElectionInvokeMessage() { + // Not used in Ring instance. } } diff --git a/leader-election/src/test/java/com/iluwatar/leaderelection/bully/BullyAppTest.java b/leader-election/src/test/java/com/iluwatar/leaderelection/bully/BullyAppTest.java index 3ef36f758..19497a32c 100644 --- a/leader-election/src/test/java/com/iluwatar/leaderelection/bully/BullyAppTest.java +++ b/leader-election/src/test/java/com/iluwatar/leaderelection/bully/BullyAppTest.java @@ -25,15 +25,16 @@ package com.iluwatar.leaderelection.bully; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * BullyApp unit test. */ -public class BullyAppTest { +class BullyAppTest { @Test - public void test() { - String[] args = {}; - BullyApp.main(args); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> BullyApp.main(new String[]{})); } } diff --git a/leader-election/src/test/java/com/iluwatar/leaderelection/ring/RingAppTest.java b/leader-election/src/test/java/com/iluwatar/leaderelection/ring/RingAppTest.java index ec3851d9b..ce5c59aa7 100644 --- a/leader-election/src/test/java/com/iluwatar/leaderelection/ring/RingAppTest.java +++ b/leader-election/src/test/java/com/iluwatar/leaderelection/ring/RingAppTest.java @@ -25,15 +25,16 @@ package com.iluwatar.leaderelection.ring; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * RingApp unit test. */ -public class RingAppTest { +class RingAppTest { @Test - public void test() { - String[] args = {}; - RingApp.main(args); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> RingApp.main(new String[]{})); } } diff --git a/leader-followers/pom.xml b/leader-followers/pom.xml index 4efdbf3ac..c0f27d051 100644 --- a/leader-followers/pom.xml +++ b/leader-followers/pom.xml @@ -37,6 +37,11 @@ junit test + + org.junit.jupiter + junit-jupiter-engine + test + org.mockito mockito-core diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/App.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java similarity index 100% rename from leader-followers/src/main/java/com.iluwatar.leaderfollowers/App.java rename to leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/Task.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/Task.java similarity index 100% rename from leader-followers/src/main/java/com.iluwatar.leaderfollowers/Task.java rename to leader-followers/src/main/java/com/iluwatar/leaderfollowers/Task.java diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskHandler.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/TaskHandler.java similarity index 100% rename from leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskHandler.java rename to leader-followers/src/main/java/com/iluwatar/leaderfollowers/TaskHandler.java diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/TaskSet.java similarity index 100% rename from leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java rename to leader-followers/src/main/java/com/iluwatar/leaderfollowers/TaskSet.java diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/WorkCenter.java similarity index 100% rename from leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java rename to leader-followers/src/main/java/com/iluwatar/leaderfollowers/WorkCenter.java diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/Worker.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/Worker.java similarity index 100% rename from leader-followers/src/main/java/com.iluwatar.leaderfollowers/Worker.java rename to leader-followers/src/main/java/com/iluwatar/leaderfollowers/Worker.java diff --git a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/AppTest.java b/leader-followers/src/test/java/com/AppTest.java similarity index 83% rename from leader-followers/src/test/java/com.iluwatar.leaderfollowers/AppTest.java rename to leader-followers/src/test/java/com/AppTest.java index 00fbfe4d2..3d0588fef 100644 --- a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/AppTest.java +++ b/leader-followers/src/test/java/com/AppTest.java @@ -21,10 +21,13 @@ * THE SOFTWARE. */ -package com.iluwatar.leaderfollowers; +package com; +import com.iluwatar.leaderfollowers.App; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * * Application test @@ -33,9 +36,8 @@ import org.junit.Test; public class AppTest { @Test - public void test() throws InterruptedException { - String[] args = {}; - App.main(args); + public void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/TaskHandlerTest.java b/leader-followers/src/test/java/com/TaskHandlerTest.java similarity index 93% rename from leader-followers/src/test/java/com.iluwatar.leaderfollowers/TaskHandlerTest.java rename to leader-followers/src/test/java/com/TaskHandlerTest.java index 9fb39c922..7dc44c04f 100644 --- a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/TaskHandlerTest.java +++ b/leader-followers/src/test/java/com/TaskHandlerTest.java @@ -21,8 +21,10 @@ * THE SOFTWARE. */ -package com.iluwatar.leaderfollowers; +package com; +import com.iluwatar.leaderfollowers.Task; +import com.iluwatar.leaderfollowers.TaskHandler; import org.junit.Assert; import org.junit.Test; diff --git a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/TaskSetTest.java b/leader-followers/src/test/java/com/TaskSetTest.java similarity index 94% rename from leader-followers/src/test/java/com.iluwatar.leaderfollowers/TaskSetTest.java rename to leader-followers/src/test/java/com/TaskSetTest.java index 53cb31deb..e3691d220 100644 --- a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/TaskSetTest.java +++ b/leader-followers/src/test/java/com/TaskSetTest.java @@ -21,8 +21,10 @@ * THE SOFTWARE. */ -package com.iluwatar.leaderfollowers; +package com; +import com.iluwatar.leaderfollowers.Task; +import com.iluwatar.leaderfollowers.TaskSet; import org.junit.Assert; import org.junit.Test; diff --git a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/WorkCenterTest.java b/leader-followers/src/test/java/com/WorkCenterTest.java similarity index 93% rename from leader-followers/src/test/java/com.iluwatar.leaderfollowers/WorkCenterTest.java rename to leader-followers/src/test/java/com/WorkCenterTest.java index 045d8c3dc..41e9ff43f 100644 --- a/leader-followers/src/test/java/com.iluwatar.leaderfollowers/WorkCenterTest.java +++ b/leader-followers/src/test/java/com/WorkCenterTest.java @@ -21,8 +21,11 @@ * THE SOFTWARE. */ -package com.iluwatar.leaderfollowers; +package com; +import com.iluwatar.leaderfollowers.TaskHandler; +import com.iluwatar.leaderfollowers.TaskSet; +import com.iluwatar.leaderfollowers.WorkCenter; import org.junit.Assert; import org.junit.Test; diff --git a/marker/src/test/java/AppTest.java b/marker/src/test/java/AppTest.java index 13295a9e5..17a13c167 100644 --- a/marker/src/test/java/AppTest.java +++ b/marker/src/test/java/AppTest.java @@ -23,13 +23,15 @@ 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java index 23f2a72f2..558ec4907 100644 --- a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java +++ b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java @@ -25,13 +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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/memento/src/test/java/com/iluwatar/memento/AppTest.java b/memento/src/test/java/com/iluwatar/memento/AppTest.java index e0448c289..2d8a518e2 100644 --- a/memento/src/test/java/com/iluwatar/memento/AppTest.java +++ b/memento/src/test/java/com/iluwatar/memento/AppTest.java @@ -25,13 +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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } 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 69dc19f1c..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,13 +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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } 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 1d59b5d8c..1dd1bf818 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 @@ -35,6 +35,10 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; +import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED; +import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED; +import static javax.swing.WindowConstants.EXIT_ON_CLOSE; + /** * This class is the GUI implementation of the View component in the Model-View-Presenter pattern. */ @@ -80,7 +84,7 @@ 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); @@ -119,8 +123,8 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti */ this.area = new JTextArea(100, 100); var pane = new JScrollPane(area); - pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + 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); 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 4db990a2d..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,14 +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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java index 8dcfd565e..4bf72fcb0 100644 --- a/module/src/test/java/com/iluwatar/module/AppTest.java +++ b/module/src/test/java/com/iluwatar/module/AppTest.java @@ -25,14 +25,17 @@ package com.iluwatar.module; 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 { - App.main(); + void shouldExecuteWithoutException() { + assertDoesNotThrow((Executable) App::main); } } 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 5883812c7..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,13 +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() { - App.main(new String[]{}); + 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 33d104ffc..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,41 +23,40 @@ package com.iluwatar.mute; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +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() { + 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() { + void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() { var stream = new ByteArrayOutputStream(); System.setErr(new PrintStream(stream)); diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java index 0bee249a6..7866b22a8 100644 --- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java +++ b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.mutex; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application Test Entrypoint */ -public class AppTest { +class AppTest { + @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } 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 754aadc80..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,12 +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() { - App.main(new String[]{}); + 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 aeec371ff..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,20 +35,20 @@ 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() { + void testGetInstance() { final var instance = NullNode.getInstance(); assertNotNull(instance); assertSame(instance, NullNode.getInstance()); } @Test - public void testFields() { + void testFields() { final var node = NullNode.getInstance(); assertEquals(0, node.getTreeSize()); assertNull(node.getName()); @@ -56,9 +56,8 @@ public class NullNodeTest { 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/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/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/partial-response/pom.xml b/partial-response/pom.xml index 83d81bf82..eb094874f 100644 --- a/partial-response/pom.xml +++ b/partial-response/pom.xml @@ -44,6 +44,11 @@ junit-vintage-engine test + + org.junit.jupiter + junit-jupiter-engine + test + org.mockito mockito-core diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java index d50084a36..b00ee6861 100644 --- a/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java +++ b/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java @@ -25,14 +25,16 @@ package com.iluwatar.partialresponse; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application test */ public class AppTest { @Test - public void main() throws Exception { - App.main(new String[]{}); + public void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } \ No newline at end of file diff --git a/pipeline/src/test/java/com/iluwatar/pipeline/AppTest.java b/pipeline/src/test/java/com/iluwatar/pipeline/AppTest.java index 8ea6a4c60..1316491ad 100644 --- a/pipeline/src/test/java/com/iluwatar/pipeline/AppTest.java +++ b/pipeline/src/test/java/com/iluwatar/pipeline/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.pipeline; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/poison-pill/src/test/java/com/iluwatar/poison/pill/AppTest.java b/poison-pill/src/test/java/com/iluwatar/poison/pill/AppTest.java index c23fe5563..50d7a90c9 100644 --- a/poison-pill/src/test/java/com/iluwatar/poison/pill/AppTest.java +++ b/poison-pill/src/test/java/com/iluwatar/poison/pill/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.poison.pill; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/AppTest.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/AppTest.java index 166ddbdee..d551614cf 100644 --- a/private-class-data/src/test/java/com/iluwatar/privateclassdata/AppTest.java +++ b/private-class-data/src/test/java/com/iluwatar/privateclassdata/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.privateclassdata; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java index bf4b6cc66..0a436bd02 100644 --- a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java +++ b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java @@ -25,14 +25,16 @@ package com.iluwatar.producer.consumer; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 9eecf00eb..e81cccb58 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -47,6 +47,7 @@ public class Promise extends PromiseSupport { * Creates a promise that will be fulfilled in future. */ public Promise() { + // Empty constructor } /** diff --git a/promise/src/test/java/com/iluwatar/promise/AppTest.java b/promise/src/test/java/com/iluwatar/promise/AppTest.java index 63ac06aec..bf2f264c0 100644 --- a/promise/src/test/java/com/iluwatar/promise/AppTest.java +++ b/promise/src/test/java/com/iluwatar/promise/AppTest.java @@ -26,13 +26,15 @@ package com.iluwatar.promise; import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application test. */ -public class AppTest { +class AppTest { @Test - public void testApp() throws InterruptedException, ExecutionException { - App.main(null); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(null)); } } diff --git a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java index a72faf01e..3b6d43be2 100644 --- a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java +++ b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java @@ -67,7 +67,7 @@ public class PromiseTest { @Test public void promiseIsFulfilledWithAnExceptionIfTaskThrowsAnException() - throws InterruptedException, TimeoutException { + throws InterruptedException { testWaitingForeverForPromiseToBeFulfilled(); testWaitingSomeTimeForPromiseToBeFulfilled(); } diff --git a/property/src/main/java/com/iluwatar/property/Character.java b/property/src/main/java/com/iluwatar/property/Character.java index afe9fe16c..3d3813e5f 100644 --- a/property/src/main/java/com/iluwatar/property/Character.java +++ b/property/src/main/java/com/iluwatar/property/Character.java @@ -61,10 +61,12 @@ public class Character implements Prototype { @Override public void set(Stats stat, Integer val) { + // Does Nothing } @Override public void remove(Stats stat) { + // Does Nothing. } }; } diff --git a/property/src/test/java/com/iluwatar/property/AppTest.java b/property/src/test/java/com/iluwatar/property/AppTest.java index 89c0dcbf6..38c5cb4d5 100644 --- a/property/src/test/java/com/iluwatar/property/AppTest.java +++ b/property/src/test/java/com/iluwatar/property/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.property; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/prototype/src/test/java/com/iluwatar/prototype/AppTest.java b/prototype/src/test/java/com/iluwatar/prototype/AppTest.java index 489b6365c..d82568ddf 100644 --- a/prototype/src/test/java/com/iluwatar/prototype/AppTest.java +++ b/prototype/src/test/java/com/iluwatar/prototype/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.prototype; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/proxy/src/test/java/com/iluwatar/proxy/AppTest.java b/proxy/src/test/java/com/iluwatar/proxy/AppTest.java index 2fdd5253e..dde0bbe57 100644 --- a/proxy/src/test/java/com/iluwatar/proxy/AppTest.java +++ b/proxy/src/test/java/com/iluwatar/proxy/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.proxy; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java index 55c9528e6..2adc15011 100644 --- a/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java +++ b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.queue.load.leveling; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } \ No newline at end of file diff --git a/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java index 1e81c5d11..3d12e6abf 100644 --- a/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java +++ b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java @@ -25,14 +25,17 @@ package com.iluwatar.queue.load.leveling; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * Test case for submitting Message to Blocking Queue by TaskGenerator and retrieve the message by * ServiceExecutor. */ -public class TaskGenSrvExeTest { +class TaskGenSrvExeTest { @Test - public void taskGeneratorTest() { + void taskGeneratorTest() { var msgQueue = new MessageQueue(); // Create a task generator thread with 1 job to submit. @@ -40,10 +43,14 @@ public class TaskGenSrvExeTest { var taskGenThr = new Thread(taskRunnable); taskGenThr.start(); + assertNotNull(taskGenThr); + // Create a service executor thread. var srvRunnable = new ServiceExecutor(msgQueue); var srvExeThr = new Thread(srvRunnable); srvExeThr.start(); + + assertNotNull(srvExeThr); } } diff --git a/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java b/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java index 76ddfbdba..1d7faab7e 100644 --- a/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java +++ b/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java @@ -30,6 +30,9 @@ import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * This class tests the Distributed Logging service by starting a Reactor and then sending it * concurrent logging requests using multiple clients. @@ -50,9 +53,13 @@ public class ReactorTest { var app = new App(new ThreadPoolDispatcher(2)); app.start(); + assertNotNull(app); + var client = new AppClient(); client.start(); + assertNotNull(client); + // allow clients to send requests. Artificial delay. try { Thread.sleep(2000); @@ -78,9 +85,13 @@ public class ReactorTest { var app = new App(new SameThreadDispatcher()); app.start(); + assertNotNull(app); + var client = new AppClient(); client.start(); + assertNotNull(client); + // allow clients to send requests. Artificial delay. try { Thread.sleep(2000); diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java index a0175e259..63f4c764d 100644 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java +++ b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java @@ -25,14 +25,16 @@ package com.iluwatar.reader.writer.lock; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/repository/src/test/java/com/iluwatar/repository/AppTest.java b/repository/src/test/java/com/iluwatar/repository/AppTest.java index b12f03d8c..d44af23db 100644 --- a/repository/src/test/java/com/iluwatar/repository/AppTest.java +++ b/repository/src/test/java/com/iluwatar/repository/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.repository; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Repository example runs without errors. */ -public class AppTest { +class AppTest { + @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java index dedeee7e0..057a85500 100644 --- a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java +++ b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.resource.acquisition.is.initialization; 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() throws Exception { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/retry/src/main/java/com/iluwatar/retry/App.java b/retry/src/main/java/com/iluwatar/retry/App.java index 06f43c29f..7d6e6faec 100644 --- a/retry/src/main/java/com/iluwatar/retry/App.java +++ b/retry/src/main/java/com/iluwatar/retry/App.java @@ -59,6 +59,7 @@ import org.slf4j.LoggerFactory; */ public final class App { private static final Logger LOG = LoggerFactory.getLogger(App.class); + public static final String NOT_FOUND = "not found"; private static BusinessOperation op; /** @@ -81,7 +82,7 @@ public final class App { } private static void errorNoRetry() throws Exception { - op = new FindCustomer("123", new CustomerNotFoundException("not found")); + op = new FindCustomer("123", new CustomerNotFoundException(NOT_FOUND)); try { op.perform(); } catch (CustomerNotFoundException e) { @@ -91,7 +92,7 @@ public final class App { private static void errorWithRetry() throws Exception { final var retry = new Retry<>( - new FindCustomer("123", new CustomerNotFoundException("not found")), + new FindCustomer("123", new CustomerNotFoundException(NOT_FOUND)), 3, //3 attempts 100, //100 ms delay between attempts e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass()) @@ -106,7 +107,7 @@ public final class App { private static void errorWithRetryExponentialBackoff() throws Exception { final var retry = new RetryExponentialBackoff<>( - new FindCustomer("123", new CustomerNotFoundException("not found")), + new FindCustomer("123", new CustomerNotFoundException(NOT_FOUND)), 6, //6 attempts 30000, //30 s max delay between attempts e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass()) diff --git a/role-object/pom.xml b/role-object/pom.xml index ccb8219eb..c980adc2c 100644 --- a/role-object/pom.xml +++ b/role-object/pom.xml @@ -39,6 +39,11 @@ junit test + + org.junit.jupiter + junit-jupiter-engine + test + diff --git a/role-object/src/test/java/com/iluwatar/roleobject/ApplicationRoleObjectTest.java b/role-object/src/test/java/com/iluwatar/roleobject/ApplicationRoleObjectTest.java index eb8d57f4f..01535f477 100644 --- a/role-object/src/test/java/com/iluwatar/roleobject/ApplicationRoleObjectTest.java +++ b/role-object/src/test/java/com/iluwatar/roleobject/ApplicationRoleObjectTest.java @@ -24,10 +24,12 @@ package com.iluwatar.roleobject; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + public class ApplicationRoleObjectTest { @Test - public void mainTest() { - ApplicationRoleObject.main(new String[]{}); + public void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> ApplicationRoleObject.main(new String[]{})); } } \ No newline at end of file diff --git a/saga/pom.xml b/saga/pom.xml index 08a5cdc77..1971ae6cf 100644 --- a/saga/pom.xml +++ b/saga/pom.xml @@ -40,6 +40,11 @@ junit test + + org.junit.jupiter + junit-jupiter-engine + test + diff --git a/saga/src/test/java/com/iluwatar/saga/choreography/SagaApplicationTest.java b/saga/src/test/java/com/iluwatar/saga/choreography/SagaApplicationTest.java index d7a2a34b2..5d73a9fa3 100644 --- a/saga/src/test/java/com/iluwatar/saga/choreography/SagaApplicationTest.java +++ b/saga/src/test/java/com/iluwatar/saga/choreography/SagaApplicationTest.java @@ -25,13 +25,15 @@ package com.iluwatar.saga.choreography; import com.iluwatar.saga.orchestration.SagaApplication; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /*** * empty test */ public class SagaApplicationTest { @Test - public void mainTest() { - SagaApplication.main(new String[]{}); + public void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> SagaApplication.main(new String[]{})); } } \ No newline at end of file diff --git a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java b/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java index f450c0593..302796238 100644 --- a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java +++ b/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.semaphore; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application Test Entrypoint */ -public class AppTest { +class AppTest { + @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/servant/src/test/java/com/iluwatar/servant/AppTest.java b/servant/src/test/java/com/iluwatar/servant/AppTest.java index ab1e99e55..d05c22eeb 100644 --- a/servant/src/test/java/com/iluwatar/servant/AppTest.java +++ b/servant/src/test/java/com/iluwatar/servant/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.servant; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java index ea660f01e..e360e5c94 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java @@ -55,6 +55,7 @@ import org.slf4j.LoggerFactory; public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + public static final String BOOK_OF_IDORES = "Book of Idores"; /** * Program entry point. @@ -135,7 +136,7 @@ public class App { spellbook4.addSpell(spell11); spellbook4.addSpell(spell12); spellbookDao.merge(spellbook4); - var spellbook5 = new Spellbook("Book of Idores"); + var spellbook5 = new Spellbook(BOOK_OF_IDORES); spellbookDao.persist(spellbook5); spellbook5.addSpell(spell13); spellbookDao.merge(spellbook5); @@ -164,7 +165,7 @@ public class App { wizardDao.merge(wizard2); var wizard3 = new Wizard("Xuban Munoa"); wizardDao.persist(wizard3); - wizard3.addSpellbook(spellbookDao.findByName("Book of Idores")); + wizard3.addSpellbook(spellbookDao.findByName(BOOK_OF_IDORES)); wizard3.addSpellbook(spellbookDao.findByName("Book of Opaen")); wizardDao.merge(wizard3); var wizard4 = new Wizard("Blasius Dehooge"); @@ -188,7 +189,7 @@ public class App { LOGGER.info("Enumerating all spells"); service.findAllSpells().stream().map(Spell::getName).forEach(LOGGER::info); LOGGER.info("Find wizards with spellbook 'Book of Idores'"); - var wizardsWithSpellbook = service.findWizardsWithSpellbook("Book of Idores"); + var wizardsWithSpellbook = service.findWizardsWithSpellbook(BOOK_OF_IDORES); wizardsWithSpellbook.forEach(w -> LOGGER.info("{} has 'Book of Idores'", w.getName())); LOGGER.info("Find wizards with spell 'Fireball'"); var wizardsWithSpell = service.findWizardsWithSpell("Fireball"); diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java index 26aa2b168..5cc1ccfff 100644 --- a/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java +++ b/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java @@ -27,18 +27,20 @@ import com.iluwatar.servicelayer.hibernate.HibernateUtil; import org.junit.jupiter.api.AfterEach; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } @AfterEach - public void tearDown() { + void tearDown() { HibernateUtil.dropSession(); } diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/App.java b/service-locator/src/main/java/com/iluwatar/servicelocator/App.java index efc25bd89..85419b603 100644 --- a/service-locator/src/main/java/com/iluwatar/servicelocator/App.java +++ b/service-locator/src/main/java/com/iluwatar/servicelocator/App.java @@ -37,19 +37,22 @@ package com.iluwatar.servicelocator; */ public class App { + public static final String JNDI_SERVICE_A = "jndi/serviceA"; + public static final String JNDI_SERVICE_B = "jndi/serviceB"; + /** * Program entry point. * * @param args command line args */ public static void main(String[] args) { - var service = ServiceLocator.getService("jndi/serviceA"); + var service = ServiceLocator.getService(JNDI_SERVICE_A); service.execute(); - service = ServiceLocator.getService("jndi/serviceB"); + service = ServiceLocator.getService(JNDI_SERVICE_B); service.execute(); - service = ServiceLocator.getService("jndi/serviceA"); + service = ServiceLocator.getService(JNDI_SERVICE_A); service.execute(); - service = ServiceLocator.getService("jndi/serviceA"); + service = ServiceLocator.getService(JNDI_SERVICE_A); service.execute(); } } diff --git a/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java b/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java index cb4c98c07..75d6f8b05 100644 --- a/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java +++ b/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.servicelocator; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/sharding/pom.xml b/sharding/pom.xml index a641ce375..2d00629bc 100644 --- a/sharding/pom.xml +++ b/sharding/pom.xml @@ -40,6 +40,11 @@ junit junit + + org.junit.jupiter + junit-jupiter-engine + test + diff --git a/sharding/src/main/java/com/iluwatar/sharding/App.java b/sharding/src/main/java/com/iluwatar/sharding/App.java index fe3cb7923..109f88cf8 100644 --- a/sharding/src/main/java/com/iluwatar/sharding/App.java +++ b/sharding/src/main/java/com/iluwatar/sharding/App.java @@ -36,10 +36,10 @@ public class App { */ public static void main(String[] args) { - var data1 = new Data(1, "data1", Data.DataType.type1); - var data2 = new Data(2, "data2", Data.DataType.type2); - var data3 = new Data(3, "data3", Data.DataType.type3); - var data4 = new Data(4, "data4", Data.DataType.type1); + var data1 = new Data(1, "data1", Data.DataType.TYPE_1); + var data2 = new Data(2, "data2", Data.DataType.TYPE_2); + var data3 = new Data(3, "data3", Data.DataType.TYPE_3); + var data4 = new Data(4, "data4", Data.DataType.TYPE_1); var shard1 = new Shard(1); var shard2 = new Shard(2); diff --git a/sharding/src/main/java/com/iluwatar/sharding/Data.java b/sharding/src/main/java/com/iluwatar/sharding/Data.java index 92e84e93a..abe49f15d 100644 --- a/sharding/src/main/java/com/iluwatar/sharding/Data.java +++ b/sharding/src/main/java/com/iluwatar/sharding/Data.java @@ -71,7 +71,7 @@ public class Data { } enum DataType { - type1, type2, type3 + TYPE_1, TYPE_2, TYPE_3 } @Override diff --git a/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java b/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java index bdb862571..d06cd51da 100644 --- a/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java +++ b/sharding/src/main/java/com/iluwatar/sharding/RangeShardManager.java @@ -47,11 +47,11 @@ public class RangeShardManager extends ShardManager { protected int allocateShard(Data data) { var type = data.getType(); switch (type) { - case type1: + case TYPE_1: return 1; - case type2: + case TYPE_2: return 2; - case type3: + case TYPE_3: return 3; default: return -1; diff --git a/sharding/src/test/java/com/iluwatar/sharding/AppTest.java b/sharding/src/test/java/com/iluwatar/sharding/AppTest.java index 40e6391bf..f23b71d1e 100644 --- a/sharding/src/test/java/com/iluwatar/sharding/AppTest.java +++ b/sharding/src/test/java/com/iluwatar/sharding/AppTest.java @@ -25,14 +25,16 @@ package com.iluwatar.sharding; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Unit tests for App class. */ public class AppTest { @Test - public void testMain() { - App.main(new String[]{}); + public void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java index 6418cf0c4..e19de75d2 100644 --- a/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java +++ b/sharding/src/test/java/com/iluwatar/sharding/HashShardManagerTest.java @@ -56,7 +56,7 @@ public class HashShardManagerTest { @Test public void testStoreData() { - var data = new Data(1, "test", Data.DataType.type1); + var data = new Data(1, "test", Data.DataType.TYPE_1); hashShardManager.storeData(data); Assert.assertEquals(data, hashShardManager.getShardById(1).getDataById(1)); } diff --git a/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java index 70650bb50..c6ce5851d 100644 --- a/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java +++ b/sharding/src/test/java/com/iluwatar/sharding/LookupShardManagerTest.java @@ -52,7 +52,7 @@ public class LookupShardManagerTest { @Test public void testStoreData() { try { - var data = new Data(1, "test", Data.DataType.type1); + var data = new Data(1, "test", Data.DataType.TYPE_1); lookupShardManager.storeData(data); var field = LookupShardManager.class.getDeclaredField("lookupMap"); field.setAccessible(true); diff --git a/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java b/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java index 997687dfc..9ea4a2d86 100644 --- a/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java +++ b/sharding/src/test/java/com/iluwatar/sharding/RangeShardManagerTest.java @@ -50,7 +50,7 @@ public class RangeShardManagerTest { @Test public void testStoreData() { - var data = new Data(1, "test", Data.DataType.type1); + var data = new Data(1, "test", Data.DataType.TYPE_1); rangeShardManager.storeData(data); Assert.assertEquals(data, rangeShardManager.getShardById(1).getDataById(1)); } diff --git a/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java b/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java index a747933af..a12ab3a97 100644 --- a/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java +++ b/sharding/src/test/java/com/iluwatar/sharding/ShardTest.java @@ -42,7 +42,7 @@ public class ShardTest { @Before public void setup() { - data = new Data(1, "test", Data.DataType.type1); + data = new Data(1, "test", Data.DataType.TYPE_1); shard = new Shard(1); } diff --git a/singleton/src/test/java/com/iluwatar/singleton/AppTest.java b/singleton/src/test/java/com/iluwatar/singleton/AppTest.java index b7c55ddea..5d3f247de 100644 --- a/singleton/src/test/java/com/iluwatar/singleton/AppTest.java +++ b/singleton/src/test/java/com/iluwatar/singleton/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.singleton; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java index 8a0e2383c..083d6a019 100644 --- a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java +++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/App.java @@ -59,6 +59,7 @@ import org.slf4j.LoggerFactory; public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private static final String BUBBLE = "Bubble "; static void noSpatialPartition(int numOfMovements, Hashtable bubbles) { //all bubbles have to be checked for collision for all bubbles @@ -76,7 +77,7 @@ public class App { numOfMovements--; } //bubbles not popped - bubbles.keySet().stream().map(key -> "Bubble " + key + " not popped").forEach(LOGGER::info); + bubbles.keySet().stream().map(key -> BUBBLE + key + " not popped").forEach(LOGGER::info); } static void withSpatialPartition( @@ -99,7 +100,7 @@ public class App { numOfMovements--; } //bubbles not popped - bubbles.keySet().stream().map(key -> "Bubble " + key + " not popped").forEach(LOGGER::info); + bubbles.keySet().stream().map(key -> BUBBLE + key + " not popped").forEach(LOGGER::info); } /** @@ -116,7 +117,7 @@ public class App { var b = new Bubble(rand.nextInt(300), rand.nextInt(300), i, rand.nextInt(2) + 1); bubbles1.put(i, b); bubbles2.put(i, b); - LOGGER.info("Bubble " + i + " with radius " + b.radius + LOGGER.info(BUBBLE + i + " with radius " + b.radius + " added at (" + b.coordinateX + "," + b.coordinateY + ")"); } diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java index b3f60632f..c0eb5ecde 100644 --- a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java +++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java @@ -34,8 +34,8 @@ import java.util.Hashtable; public class SpatialPartitionBubbles extends SpatialPartitionGeneric { - final Hashtable bubbles; - final QuadTree quadTree; + private final Hashtable bubbles; + private final QuadTree quadTree; SpatialPartitionBubbles(Hashtable bubbles, QuadTree quadTree) { this.bubbles = bubbles; diff --git a/specification/src/test/java/com/iluwatar/specification/app/AppTest.java b/specification/src/test/java/com/iluwatar/specification/app/AppTest.java index bc6f2226f..4b29e11e8 100644 --- a/specification/src/test/java/com/iluwatar/specification/app/AppTest.java +++ b/specification/src/test/java/com/iluwatar/specification/app/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.specification.app; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/state/src/test/java/com/iluwatar/state/AppTest.java b/state/src/test/java/com/iluwatar/state/AppTest.java index 9f7b65ff2..90beddb33 100644 --- a/state/src/test/java/com/iluwatar/state/AppTest.java +++ b/state/src/test/java/com/iluwatar/state/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.state; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java b/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java index 1f3fc6238..20119b41b 100644 --- a/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java +++ b/step-builder/src/test/java/com/iluwatar/stepbuilder/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.stepbuilder; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/strangler/src/main/java/com/iluwatar/strangler/NewSource.java b/strangler/src/main/java/com/iluwatar/strangler/NewSource.java index f53a31bd8..8cc1822fe 100644 --- a/strangler/src/main/java/com/iluwatar/strangler/NewSource.java +++ b/strangler/src/main/java/com/iluwatar/strangler/NewSource.java @@ -34,9 +34,10 @@ import org.slf4j.LoggerFactory; public class NewSource { private static final Logger LOGGER = LoggerFactory.getLogger(NewSource.class); private static final String VERSION = "2.0"; + public static final String SOURCE_MODULE = "Source module {}"; public int accumulateSum(int... nums) { - LOGGER.info("Source module {}", VERSION); + LOGGER.info(SOURCE_MODULE, VERSION); return Arrays.stream(nums).reduce(0, Integer::sum); } @@ -45,12 +46,12 @@ public class NewSource { * Replace old one in {@link OldSource} */ public int accumulateMul(int... nums) { - LOGGER.info("Source module {}", VERSION); + LOGGER.info(SOURCE_MODULE, VERSION); return Arrays.stream(nums).reduce(1, (a, b) -> a * b); } public boolean ifNonZero(int... nums) { - LOGGER.info("Source module {}", VERSION); + LOGGER.info(SOURCE_MODULE, VERSION); return Arrays.stream(nums).allMatch(num -> num != 0); } } diff --git a/strangler/src/test/java/com/iluwatar/strangler/AppTest.java b/strangler/src/test/java/com/iluwatar/strangler/AppTest.java index a9e878a94..7e45d63ec 100644 --- a/strangler/src/test/java/com/iluwatar/strangler/AppTest.java +++ b/strangler/src/test/java/com/iluwatar/strangler/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.strangler; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/strategy/src/test/java/com/iluwatar/strategy/AppTest.java b/strategy/src/test/java/com/iluwatar/strategy/AppTest.java index f1137c4c5..174334f51 100644 --- a/strategy/src/test/java/com/iluwatar/strategy/AppTest.java +++ b/strategy/src/test/java/com/iluwatar/strategy/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.strategy; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index 264343b00..ac718291e 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -44,6 +44,11 @@ com.github.stefanbirkner system-rules + + org.junit.jupiter + junit-jupiter-engine + test + \ No newline at end of file diff --git a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/AppTest.java b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/AppTest.java index 83ba5315f..8d4865f6b 100644 --- a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/AppTest.java +++ b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.subclasssandbox; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * App unit tests. */ public class AppTest { @Test - public void testMain() { - App.main(new String[]{}); + public void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java index e70e8a78f..32f09242e 100644 --- a/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java +++ b/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.templatemethod; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java index ca6dc30e4..4c1cf90d6 100644 --- a/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java +++ b/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java @@ -25,15 +25,17 @@ package com.iluwatar.threadpool; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Application test * * @author ilkka */ -public class AppTest { +class AppTest { @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/throttling/src/test/java/com/iluwatar/throttling/AppTest.java b/throttling/src/test/java/com/iluwatar/throttling/AppTest.java index daf8c2f21..dcabb02b3 100644 --- a/throttling/src/test/java/com/iluwatar/throttling/AppTest.java +++ b/throttling/src/test/java/com/iluwatar/throttling/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.throttling; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/tls/src/test/java/com/iluwatar/tls/AppTest.java b/tls/src/test/java/com/iluwatar/tls/AppTest.java index bae673b97..ba3774b3e 100644 --- a/tls/src/test/java/com/iluwatar/tls/AppTest.java +++ b/tls/src/test/java/com/iluwatar/tls/AppTest.java @@ -25,14 +25,16 @@ package com.iluwatar.tls; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that thread local storage example runs without errors. * * @author Thomas Bauer, January 2017 */ -public class AppTest { +class AppTest { @Test - public void test() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java index f6a9e6a0e..98ad31fe5 100644 --- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java +++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java @@ -38,6 +38,9 @@ import java.util.Map; */ public final class RainbowFishSerializer { + public static final String LENGTH_METERS = "lengthMeters"; + public static final String WEIGHT_TONS = "weightTons"; + private RainbowFishSerializer() { } @@ -48,8 +51,8 @@ public final class RainbowFishSerializer { var map = Map.of( "name", rainbowFish.getName(), "age", String.format("%d", rainbowFish.getAge()), - "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()), - "weightTons", String.format("%d", rainbowFish.getWeightTons()) + LENGTH_METERS, String.format("%d", rainbowFish.getLengthMeters()), + WEIGHT_TONS, String.format("%d", rainbowFish.getWeightTons()) ); try (var fileOut = new FileOutputStream(filename); @@ -65,8 +68,8 @@ public final class RainbowFishSerializer { var map = Map.of( "name", rainbowFish.getName(), "age", String.format("%d", rainbowFish.getAge()), - "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()), - "weightTons", String.format("%d", rainbowFish.getWeightTons()), + "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()), + WEIGHT_TONS, String.format("%d", rainbowFish.getWeightTons()), "angry", Boolean.toString(rainbowFish.getAngry()), "hungry", Boolean.toString(rainbowFish.getHungry()), "sleeping", Boolean.toString(rainbowFish.getSleeping()) @@ -93,7 +96,7 @@ public final class RainbowFishSerializer { map.get("name"), Integer.parseInt(map.get("age")), Integer.parseInt(map.get("lengthMeters")), - Integer.parseInt(map.get("weightTons")) + Integer.parseInt(map.get(WEIGHT_TONS)) ); } } diff --git a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java index d28e118d2..4b9432408 100644 --- a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java +++ b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java @@ -29,19 +29,21 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; 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() throws ClassNotFoundException, IOException { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } @BeforeEach @AfterEach - public void cleanup() { + void cleanup() { var file1 = new File("fish1.out"); file1.delete(); var file2 = new File("fish2.out"); diff --git a/transaction-script/src/test/java/com/iluwatar/transactionscript/AppTest.java b/transaction-script/src/test/java/com/iluwatar/transactionscript/AppTest.java index 425d6e153..eb819cabe 100644 --- a/transaction-script/src/test/java/com/iluwatar/transactionscript/AppTest.java +++ b/transaction-script/src/test/java/com/iluwatar/transactionscript/AppTest.java @@ -25,12 +25,15 @@ package com.iluwatar.transactionscript; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * Tests that Transaction script example runs without errors. */ -public class AppTest { +class AppTest { + @Test - public void test() throws Exception { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/twin/src/test/java/com/iluwatar/twin/AppTest.java b/twin/src/test/java/com/iluwatar/twin/AppTest.java index 50b787eeb..38a3208ad 100644 --- a/twin/src/test/java/com/iluwatar/twin/AppTest.java +++ b/twin/src/test/java/com/iluwatar/twin/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.twin; 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() throws Exception { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Candy.java b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Candy.java index 88bfe0ada..7183c99df 100644 --- a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Candy.java +++ b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Candy.java @@ -30,8 +30,8 @@ package com.iluwatar.typeobject; public class Candy { enum Type { - crushableCandy, - rewardFruit + CRUSHABLE_CANDY, + REWARD_FRUIT } String name; diff --git a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CandyGame.java b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CandyGame.java index 04e281a99..ab175e660 100644 --- a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CandyGame.java +++ b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CandyGame.java @@ -104,13 +104,13 @@ public class CandyGame { boolean continueRound() { for (var i = 0; i < this.cells.length; i++) { - if (this.cells[cells.length - 1][i].candy.getType().equals(Type.rewardFruit)) { + if (this.cells[cells.length - 1][i].candy.getType().equals(Type.REWARD_FRUIT)) { return true; } } for (var i = 0; i < this.cells.length; i++) { for (var j = 0; j < this.cells.length; j++) { - if (!this.cells[i][j].candy.getType().equals(Type.rewardFruit)) { + if (!this.cells[i][j].candy.getType().equals(Type.REWARD_FRUIT)) { var adj = adjacentCells(i, j); for (Cell cell : adj) { if (this.cells[i][j].candy.name.equals(cell.candy.name)) { @@ -136,7 +136,7 @@ public class CandyGame { for (var i = 0; i < this.cells.length; i++) { var points = 0; var j = this.cells.length - 1; - while (this.cells[j][i].candy.getType().equals(Type.rewardFruit)) { + while (this.cells[j][i].candy.getType().equals(Type.REWARD_FRUIT)) { points = this.cells[j][i].candy.getPoints(); this.cells[j][i].crush(pool, this.cells); handleChange(points); diff --git a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Cell.java b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Cell.java index e4d9d497f..76629b9dd 100644 --- a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Cell.java +++ b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/Cell.java @@ -74,8 +74,8 @@ public class Cell { } int interact(Cell c, CellPool pool, Cell[][] cellMatrix) { - if (this.candy.getType().equals(Type.rewardFruit) || c.candy.getType() - .equals(Type.rewardFruit)) { + if (this.candy.getType().equals(Type.REWARD_FRUIT) || c.candy.getType() + .equals(Type.REWARD_FRUIT)) { return 0; } else { if (this.candy.name.equals(c.candy.name)) { diff --git a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CellPool.java b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CellPool.java index f33640f2a..923a5c403 100644 --- a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CellPool.java +++ b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/CellPool.java @@ -24,7 +24,7 @@ package com.iluwatar.typeobject; import com.iluwatar.typeobject.Candy.Type; -import java.io.FileNotFoundException; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -39,6 +39,8 @@ import org.json.simple.parser.ParseException; public class CellPool { private static final Random RANDOM = new Random(); + public static final String FRUIT = "fruit"; + public static final String CANDY = "candy"; List pool; int pointer; Candy[] randomCode; @@ -51,11 +53,11 @@ public class CellPool { e.printStackTrace(); //manually initialising this.randomCode this.randomCode = new Candy[5]; - randomCode[0] = new Candy("cherry", "fruit", Type.rewardFruit, 20); - randomCode[1] = new Candy("mango", "fruit", Type.rewardFruit, 20); - randomCode[2] = new Candy("purple popsicle", "candy", Type.crushableCandy, 10); - randomCode[3] = new Candy("green jellybean", "candy", Type.crushableCandy, 10); - randomCode[4] = new Candy("orange gum", "candy", Type.crushableCandy, 10); + randomCode[0] = new Candy("cherry", FRUIT, Type.REWARD_FRUIT, 20); + randomCode[1] = new Candy("mango", FRUIT, Type.REWARD_FRUIT, 20); + randomCode[2] = new Candy("purple popsicle", CANDY, Type.CRUSHABLE_CANDY, 10); + randomCode[3] = new Candy("green jellybean", CANDY, Type.CRUSHABLE_CANDY, 10); + randomCode[4] = new Candy("orange gum", CANDY, Type.CRUSHABLE_CANDY, 10); } for (int i = 0; i < num; i++) { var c = new Cell(); @@ -84,7 +86,7 @@ public class CellPool { var i = 0; for (var e = jp.candies.keys(); e.hasMoreElements(); ) { var s = e.nextElement(); - if (!s.equals("fruit") && !s.equals("candy")) { + if (!s.equals(FRUIT) && !s.equals(CANDY)) { //not generic randomCode[i] = jp.candies.get(s); i++; diff --git a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/JsonParser.java b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/JsonParser.java index 01e709c8f..150c648d3 100644 --- a/typeobjectpattern/src/main/java/com/iluwatar/typeobject/JsonParser.java +++ b/typeobjectpattern/src/main/java/com/iluwatar/typeobject/JsonParser.java @@ -29,7 +29,7 @@ import java.io.FileReader; import java.io.IOException; import java.util.Hashtable; import java.util.List; -import java.util.stream.Collectors; + import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; @@ -58,9 +58,9 @@ public class JsonParser { var name = (String) candy.get("name"); var parentName = (String) candy.get("parent"); var t = (String) candy.get("type"); - var type = Type.crushableCandy; + var type = Type.CRUSHABLE_CANDY; if (t.equals("rewardFruit")) { - type = Type.rewardFruit; + type = Type.REWARD_FRUIT; } var points = Integer.parseInt((String) candy.get("points")); var c = new Candy(name, parentName, type, points); diff --git a/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CandyGameTest.java b/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CandyGameTest.java index 8175d1dd0..69bcc67c5 100644 --- a/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CandyGameTest.java +++ b/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CandyGameTest.java @@ -46,9 +46,9 @@ class CandyGameTest { @Test void continueRoundTest() { var matrix = new Cell[2][2]; - var c1 = new Candy("green jelly", "jelly", Type.crushableCandy, 5); - var c2 = new Candy("purple jelly", "jelly", Type.crushableCandy, 5); - var c3 = new Candy("green apple", "apple", Type.rewardFruit, 10); + var c1 = new Candy("green jelly", "jelly", Type.CRUSHABLE_CANDY, 5); + var c2 = new Candy("purple jelly", "jelly", Type.CRUSHABLE_CANDY, 5); + var c3 = new Candy("green apple", "apple", Type.REWARD_FRUIT, 10); matrix[0][0] = new Cell(c1, 0, 0); matrix[0][1] = new Cell(c2, 1, 0); matrix[1][0] = new Cell(c3, 0, 1); diff --git a/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CellTest.java b/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CellTest.java index 18bca62bb..6d910e47c 100644 --- a/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CellTest.java +++ b/typeobjectpattern/src/test/java/com/iluwatar/typeobject/CellTest.java @@ -36,8 +36,8 @@ class CellTest { @Test void interactTest() { - var c1 = new Candy("green jelly", "jelly", Type.crushableCandy, 5); - var c2 = new Candy("green apple", "apple", Type.rewardFruit, 10); + var c1 = new Candy("green jelly", "jelly", Type.CRUSHABLE_CANDY, 5); + var c2 = new Candy("green apple", "apple", Type.REWARD_FRUIT, 10); var matrix = new Cell[4][4]; matrix[0][0] = new Cell(c1, 0, 0); matrix[0][1] = new Cell(c1, 1, 0); @@ -51,8 +51,8 @@ class CellTest { @Test void crushTest() { - var c1 = new Candy("green jelly", "jelly", Type.crushableCandy, 5); - var c2 = new Candy("purple candy", "candy", Type.crushableCandy, 5); + var c1 = new Candy("green jelly", "jelly", Type.CRUSHABLE_CANDY, 5); + var c2 = new Candy("purple candy", "candy", Type.CRUSHABLE_CANDY, 5); var matrix = new Cell[4][4]; matrix[0][0] = new Cell(c1, 0, 0); matrix[1][0] = new Cell(c2, 0, 1); diff --git a/unit-of-work/pom.xml b/unit-of-work/pom.xml index cd6ce06f1..1fab10186 100644 --- a/unit-of-work/pom.xml +++ b/unit-of-work/pom.xml @@ -44,6 +44,11 @@ junit-vintage-engine test + + org.junit.jupiter + junit-jupiter-engine + test + org.mockito mockito-core diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java index c44a696e3..e5e24817f 100644 --- a/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java @@ -29,9 +29,6 @@ package com.iluwatar.unitofwork; * @param Any generic entity */ public interface IUnitOfWork { - String INSERT = "INSERT"; - String DELETE = "DELETE"; - String MODIFY = "MODIFY"; /** * Any register new operation occurring on UnitOfWork is only going to be performed on commit. diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java index 73c1068b3..70433ed98 100644 --- a/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java @@ -52,20 +52,20 @@ public class StudentRepository implements IUnitOfWork { @Override public void registerNew(Student student) { LOGGER.info("Registering {} for insert in context.", student.getName()); - register(student, IUnitOfWork.INSERT); + register(student, UnitActions.INSERT.getActionValue()); } @Override public void registerModified(Student student) { LOGGER.info("Registering {} for modify in context.", student.getName()); - register(student, IUnitOfWork.MODIFY); + register(student, UnitActions.MODIFY.getActionValue()); } @Override public void registerDeleted(Student student) { LOGGER.info("Registering {} for delete in context.", student.getName()); - register(student, IUnitOfWork.DELETE); + register(student, UnitActions.DELETE.getActionValue()); } private void register(Student student, String operation) { @@ -86,21 +86,21 @@ public class StudentRepository implements IUnitOfWork { return; } LOGGER.info("Commit started"); - if (context.containsKey(IUnitOfWork.INSERT)) { + if (context.containsKey(UnitActions.INSERT.getActionValue())) { commitInsert(); } - if (context.containsKey(IUnitOfWork.MODIFY)) { + if (context.containsKey(UnitActions.MODIFY.getActionValue())) { commitModify(); } - if (context.containsKey(IUnitOfWork.DELETE)) { + if (context.containsKey(UnitActions.DELETE.getActionValue())) { commitDelete(); } LOGGER.info("Commit finished."); } private void commitInsert() { - var studentsToBeInserted = context.get(IUnitOfWork.INSERT); + var studentsToBeInserted = context.get(UnitActions.INSERT.getActionValue()); for (var student : studentsToBeInserted) { LOGGER.info("Saving {} to database.", student.getName()); studentDatabase.insert(student); @@ -108,7 +108,7 @@ public class StudentRepository implements IUnitOfWork { } private void commitModify() { - var modifiedStudents = context.get(IUnitOfWork.MODIFY); + var modifiedStudents = context.get(UnitActions.MODIFY.getActionValue()); for (var student : modifiedStudents) { LOGGER.info("Modifying {} to database.", student.getName()); studentDatabase.modify(student); @@ -116,7 +116,7 @@ public class StudentRepository implements IUnitOfWork { } private void commitDelete() { - var deletedStudents = context.get(IUnitOfWork.DELETE); + var deletedStudents = context.get(UnitActions.DELETE.getActionValue()); for (var student : deletedStudents) { LOGGER.info("Deleting {} to database.", student.getName()); studentDatabase.delete(student); diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java new file mode 100644 index 000000000..b00d015a3 --- /dev/null +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java @@ -0,0 +1,18 @@ +package com.iluwatar.unitofwork; + +public enum UnitActions { + INSERT("INSERT"), + DELETE("DELETE"), + MODIFY("MODIFY") + ; + + private final String actionValue; + + UnitActions(String actionValue) { + this.actionValue = actionValue; + } + + public String getActionValue() { + return actionValue; + } +} diff --git a/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java b/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java index ecbe5fc53..2fbe37ccf 100644 --- a/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java +++ b/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java @@ -25,12 +25,14 @@ package com.iluwatar.unitofwork; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + /** * AppTest */ public class AppTest { @Test - public void test() { - App.main(new String[]{}); + public void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java b/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java index cda2f6fca..6cf1e6e16 100644 --- a/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java +++ b/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java @@ -63,7 +63,7 @@ public class StudentRepositoryTest { studentRepository.registerNew(student1); studentRepository.registerNew(student2); - assertEquals(2, context.get(IUnitOfWork.INSERT).size()); + assertEquals(2, context.get(UnitActions.INSERT.getActionValue()).size()); verifyNoMoreInteractions(studentDatabase); } @@ -72,7 +72,7 @@ public class StudentRepositoryTest { studentRepository.registerDeleted(student1); studentRepository.registerDeleted(student2); - assertEquals(2, context.get(IUnitOfWork.DELETE).size()); + assertEquals(2, context.get(UnitActions.DELETE.getActionValue()).size()); verifyNoMoreInteractions(studentDatabase); } @@ -81,15 +81,15 @@ public class StudentRepositoryTest { studentRepository.registerModified(student1); studentRepository.registerModified(student2); - assertEquals(2, context.get(IUnitOfWork.MODIFY).size()); + assertEquals(2, context.get(UnitActions.MODIFY.getActionValue()).size()); verifyNoMoreInteractions(studentDatabase); } @Test public void shouldSaveAllLocalChangesToDb() { - context.put(IUnitOfWork.INSERT, List.of(student1)); - context.put(IUnitOfWork.MODIFY, List.of(student1)); - context.put(IUnitOfWork.DELETE, List.of(student1)); + context.put(UnitActions.INSERT.getActionValue(), List.of(student1)); + context.put(UnitActions.MODIFY.getActionValue(), List.of(student1)); + context.put(UnitActions.DELETE.getActionValue(), List.of(student1)); studentRepository.commit(); @@ -118,8 +118,8 @@ public class StudentRepositoryTest { @Test public void shouldNotInsertToDbIfNoRegisteredStudentsToBeCommitted() { - context.put(IUnitOfWork.MODIFY, List.of(student1)); - context.put(IUnitOfWork.DELETE, List.of(student1)); + context.put(UnitActions.MODIFY.getActionValue(), List.of(student1)); + context.put(UnitActions.DELETE.getActionValue(), List.of(student1)); studentRepository.commit(); @@ -128,8 +128,8 @@ public class StudentRepositoryTest { @Test public void shouldNotModifyToDbIfNotRegisteredStudentsToBeCommitted() { - context.put(IUnitOfWork.INSERT, List.of(student1)); - context.put(IUnitOfWork.DELETE, List.of(student1)); + context.put(UnitActions.INSERT.getActionValue(), List.of(student1)); + context.put(UnitActions.DELETE.getActionValue(), List.of(student1)); studentRepository.commit(); @@ -138,8 +138,8 @@ public class StudentRepositoryTest { @Test public void shouldNotDeleteFromDbIfNotRegisteredStudentsToBeCommitted() { - context.put(IUnitOfWork.INSERT, List.of(student1)); - context.put(IUnitOfWork.MODIFY, List.of(student1)); + context.put(UnitActions.INSERT.getActionValue(), List.of(student1)); + context.put(UnitActions.MODIFY.getActionValue(), List.of(student1)); studentRepository.commit(); diff --git a/update-method/pom.xml b/update-method/pom.xml index a89364328..78b89555a 100644 --- a/update-method/pom.xml +++ b/update-method/pom.xml @@ -38,6 +38,11 @@ junit junit + + org.junit.jupiter + junit-jupiter-engine + test + diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/World.java b/update-method/src/main/java/com/iluwatar/updatemethod/World.java index 5b99050c8..37211abb1 100644 --- a/update-method/src/main/java/com/iluwatar/updatemethod/World.java +++ b/update-method/src/main/java/com/iluwatar/updatemethod/World.java @@ -88,6 +88,7 @@ public class World { * pattern. */ private void render() { + // Does Nothing } /** diff --git a/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java b/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java index 75c30470d..4849c4e62 100644 --- a/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java +++ b/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java @@ -25,11 +25,12 @@ package com.iluwatar.updatemethod; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + public class AppTest { @Test - public void testMain() { - String[] args = {}; - App.main(args); + public void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/value-object/src/test/java/com/iluwatar/value/object/AppTest.java b/value-object/src/test/java/com/iluwatar/value/object/AppTest.java index c0e680ec4..39eaef28c 100644 --- a/value-object/src/test/java/com/iluwatar/value/object/AppTest.java +++ b/value-object/src/test/java/com/iluwatar/value/object/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.value.object; 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() { - App.main(new String[]{}); + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/visitor/src/test/java/com/iluwatar/visitor/AppTest.java b/visitor/src/test/java/com/iluwatar/visitor/AppTest.java index c16f31195..45f7006a7 100644 --- a/visitor/src/test/java/com/iluwatar/visitor/AppTest.java +++ b/visitor/src/test/java/com/iluwatar/visitor/AppTest.java @@ -25,13 +25,15 @@ package com.iluwatar.visitor; 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() { - App.main(new String[]{}); + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); } } From 133ef52898287827ff6648e3a9261560cee258b0 Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Sat, 15 Aug 2020 22:19:27 +0400 Subject: [PATCH 005/254] Fixed an issue with the order of imports that was causing build failures. --- .../iluwatar/model/view/presenter/FileSelectorJFrame.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 1dd1bf818..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; @@ -35,10 +39,6 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; -import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED; -import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED; -import static javax.swing.WindowConstants.EXIT_ON_CLOSE; - /** * This class is the GUI implementation of the View component in the Model-View-Presenter pattern. */ From 00d06871f4841b676467bb933d7859713de0f306 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sun, 16 Aug 2020 12:42:08 +0530 Subject: [PATCH 006/254] updated workflows --- .github/workflows/{maven.yml => maven-ci.yml} | 10 ++- .github/workflows/maven-pr-builder.yml | 64 +++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) rename .github/workflows/{maven.yml => maven-ci.yml} (91%) create mode 100644 .github/workflows/maven-pr-builder.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven-ci.yml similarity index 91% rename from .github/workflows/maven.yml rename to .github/workflows/maven-ci.yml index d18cad280..914db3f4d 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven-ci.yml @@ -24,13 +24,11 @@ # This workflow will build a Java project with Maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven -name: Java CI with Maven +name: Java CI on: push: branches: [ master ] - pull_request: - branches: [ master ] jobs: build: @@ -43,6 +41,12 @@ jobs: uses: actions/setup-java@v1 with: java-version: 11 + - uses: actions/cache@v1 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- # Some tests need screen access - name: Install xvfb run: sudo apt-get install xvfb diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml new file mode 100644 index 000000000..ea5d3d703 --- /dev/null +++ b/.github/workflows/maven-pr-builder.yml @@ -0,0 +1,64 @@ +# +# The MIT License +# Copyright © 2014-2019 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java PR Builder + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-18.04 + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - uses: actions/cache@v1 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + # Some tests need screen access + - name: Install xvfb + run: sudo apt-get install xvfb + # SonarQube scan does not work for forked repositories + # See https://jira.sonarsource.com/browse/MMF-1371 + - name: Build with Maven + if: github.ref != 'refs/heads/master' + run: xvfb-run mvn clean verify + - name: Build with Maven and run SonarQube analysis + if: github.ref == 'refs/heads/master' + run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + env: + # These two env variables are needed for sonar analysis + GITHUB_TOKEN: ${{ secrets.REPOSITORY_ACCESS_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 79a6af703ec94e3719c05122e0c1c08768a877d6 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sun, 16 Aug 2020 12:49:21 +0530 Subject: [PATCH 007/254] updated copyright year to 2020 --- .github/workflows/maven-ci.yml | 2 +- .github/workflows/maven-pr-builder.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 914db3f4d..a04b0021e 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -1,6 +1,6 @@ # # The MIT License -# Copyright © 2014-2019 Ilkka Seppälä +# Copyright © 2014-2020 Ilkka Seppälä # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index ea5d3d703..0384c326c 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -1,6 +1,6 @@ # # The MIT License -# Copyright © 2014-2019 Ilkka Seppälä +# Copyright © 2014-2020 Ilkka Seppälä # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From 57e45a329f23571544663a6e7b9c7133a4dcc731 Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Sun, 16 Aug 2020 22:35:15 +0400 Subject: [PATCH 008/254] Fixed a whitespace and spelling issue that was causing the test case to fail. --- extension-objects/src/main/java/concreteextensions/Soldier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java index 76ddbfd06..3ceaa7880 100644 --- a/extension-objects/src/main/java/concreteextensions/Soldier.java +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -42,7 +42,7 @@ public class Soldier implements SoldierExtension { @Override public void soldierReady() { - LOGGER.info("[Solider] " + unit.getName() + " is ready!"); + LOGGER.info("[Soldier] " + unit.getName() + " is ready!"); } public SoldierUnit getUnit() { From 241f93f3ccd6d83b16006ede3c5241f5feae480a Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Mon, 17 Aug 2020 11:28:33 +0530 Subject: [PATCH 009/254] updated cache to v2 and removed SQ analysis --- .github/workflows/maven-ci.yml | 2 +- .github/workflows/maven-pr-builder.yml | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index a04b0021e..8a7f7a0bb 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -41,7 +41,7 @@ jobs: uses: actions/setup-java@v1 with: java-version: 11 - - uses: actions/cache@v1 + - uses: actions/cache@v2 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 0384c326c..1bdad0621 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -41,7 +41,7 @@ jobs: uses: actions/setup-java@v1 with: java-version: 11 - - uses: actions/cache@v1 + - uses: actions/cache@v2 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -55,10 +55,3 @@ jobs: - name: Build with Maven if: github.ref != 'refs/heads/master' run: xvfb-run mvn clean verify - - name: Build with Maven and run SonarQube analysis - if: github.ref == 'refs/heads/master' - run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar - env: - # These two env variables are needed for sonar analysis - GITHUB_TOKEN: ${{ secrets.REPOSITORY_ACCESS_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 8c5740563dc5c1eb01c55bdcc919a70bb880d99d Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Mon, 17 Aug 2020 19:12:54 +0530 Subject: [PATCH 010/254] reverted the copyright year back to 2019 --- .github/workflows/maven-ci.yml | 2 +- .github/workflows/maven-pr-builder.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 8a7f7a0bb..be0a74e9f 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -1,6 +1,6 @@ # # The MIT License -# Copyright © 2014-2020 Ilkka Seppälä +# Copyright © 2014-2019 Ilkka Seppälä # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 1bdad0621..7e4f3670f 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -1,6 +1,6 @@ # # The MIT License -# Copyright © 2014-2020 Ilkka Seppälä +# Copyright © 2014-2019 Ilkka Seppälä # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From 95e513b6ecffbc7a1fbd194c1908e0f9f9adf2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Mon, 17 Aug 2020 19:49:00 +0300 Subject: [PATCH 011/254] Edit readme --- visitor/README.md | 48 ++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/visitor/README.md b/visitor/README.md index c97e97120..75a032a47 100644 --- a/visitor/README.md +++ b/visitor/README.md @@ -9,13 +9,17 @@ tags: --- ## Intent -Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. + +Represent an operation to be performed on the elements of an object structure. Visitor lets you +define a new operation without changing the classes of the elements on which it operates. ## Explanation Real world example -> Consider a tree structure with army units. Commander has two sergeants under it and each sergeant has three soldiers under them. Given that the hierarchy implements the visitor pattern, we can easily create new objects that interact with the commander, sergeants, soldiers or all of them. +> Consider a tree structure with army units. Commander has two sergeants under it and each sergeant +> has three soldiers under them. Given that the hierarchy implements the visitor pattern, we can +> easily create new objects that interact with the commander, sergeants, soldiers or all of them. In plain words @@ -23,7 +27,10 @@ In plain words Wikipedia says -> In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. +> In object-oriented programming and software engineering, the visitor design pattern is a way of +> separating an algorithm from an object structure on which it operates. A practical result of this +> separation is the ability to add new operations to existing object structures without modifying +> the structures. **Programmatic Example** @@ -111,7 +118,7 @@ public class Soldier extends Unit { } ``` -And then some concrete visitors. +Here are then some concrete visitors. ```java public class CommanderVisitor implements UnitVisitor { @@ -175,32 +182,39 @@ public class SoldierVisitor implements UnitVisitor { } ``` -Finally we can show the power of visitors in action. +Finally, we can show the power of visitors in action. ```java commander.accept(new SoldierVisitor()); -// Greetings soldier -// Greetings soldier -// Greetings soldier -// Greetings soldier -// Greetings soldier -// Greetings soldier commander.accept(new SergeantVisitor()); -// Hello sergeant -// Hello sergeant commander.accept(new CommanderVisitor()); -// Good to see you commander +``` + +Program output: + +``` +Greetings soldier +Greetings soldier +Greetings soldier +Greetings soldier +Greetings soldier +Greetings soldier +Hello sergeant +Hello sergeant +Good to see you commander ``` ## Class diagram + ![alt text](./etc/visitor_1.png "Visitor") ## Applicability + Use the Visitor pattern when -* An object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes -* Many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them -* The classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes +* An object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes. +* Many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them. +* The classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes. ## Real world examples From ef43af3b2372026214512fa486c758ce98721567 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2020 16:42:02 +0000 Subject: [PATCH 012/254] docs: update README.md [skip ci] --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 36094b1db..225f14709 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) -[![All Contributors](https://img.shields.io/badge/all_contributors-124-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-125-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -254,6 +254,9 @@ This project is licensed under the terms of the MIT license.
xdvrx1

👀 🤔
Subhrodip Mohanta

💻 + +
Bethan Palmer

💻 + From 6c7715ace6b15cf010a4540b862d2b961c6e91c9 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2020 16:42:03 +0000 Subject: [PATCH 013/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 6ea5a5de6..712ae41c2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1130,6 +1130,15 @@ "contributions": [ "code" ] + }, + { + "login": "nahteb", + "name": "Bethan Palmer", + "avatar_url": "https://avatars3.githubusercontent.com/u/13121570?v=4", + "profile": "https://github.com/nahteb", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From 847585334c4edea23aa675cc6b18c40db14982e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 18 Aug 2020 20:07:47 +0300 Subject: [PATCH 014/254] Update README.md --- unit-of-work/README.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/unit-of-work/README.md b/unit-of-work/README.md index 590f718d3..01aa8e5d7 100644 --- a/unit-of-work/README.md +++ b/unit-of-work/README.md @@ -11,21 +11,27 @@ tags: --- ## Intent -When a business transaction is completed, all the the updates are sent as one big unit of work to be persisted -in one go to minimize database round-trips. + +When a business transaction is completed, all the the updates are sent as one big unit of work to be +persisted in one go to minimize database round-trips. ## Explanation + Real world example -> We have a database containing student information. Administrators all over the country are constantly updating this information and it causes high load on the database server. To make the load more manageable we apply to Unit of Work pattern to send many small updates in batches. +> We have a database containing student information. Administrators all over the country are +> constantly updating this information and it causes high load on the database server. To make the +> load more manageable we apply to Unit of Work pattern to send many small updates in batches. In plain words -> Unit of Work merges many small database updates in single batch to optimize the number of round-trips. +> Unit of Work merges many small database updates in single batch to optimize the number of +> round-trips. [MartinFowler.com](https://martinfowler.com/eaaCatalog/unitOfWork.html) says -> Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. +> Maintains a list of objects affected by a business transaction and coordinates the writing out of +> changes and the resolution of concurrency problems. **Programmatic Example** @@ -57,8 +63,9 @@ public class Student { } ``` -The essence of the implementation is the `StudentRepository` implementing the Unit of Work pattern. It maintains a map -of database operations (`context`) that need to be done and when `commit` is called it applies them in single batch. +The essence of the implementation is the `StudentRepository` implementing the Unit of Work pattern. +It maintains a map of database operations (`context`) that need to be done and when `commit` is +called it applies them in single batch. ```java public interface IUnitOfWork { @@ -160,7 +167,7 @@ public class StudentRepository implements IUnitOfWork { } ``` -Finally here's how we use the `StudentRepository` and `commit` the transaction. +Finally, here's how we use the `StudentRepository` and `commit` the transaction. ```java studentRepository.registerNew(ram); @@ -170,9 +177,11 @@ Finally here's how we use the `StudentRepository` and `commit` the transaction. ``` ## Class diagram + ![alt text](etc/unit-of-work.urm.png "unit-of-work") ## Applicability + Use the Unit Of Work pattern when * To optimize the time taken for database transactions. From 1e385056fc2a0ffefe15eab840bf250652bac2d7 Mon Sep 17 00:00:00 2001 From: Mike Liu <657829312@qq.com> Date: Wed, 19 Aug 2020 17:10:14 +0800 Subject: [PATCH 015/254] finish translate adapter pattern into chinese --- zh/adapter/README.md | 138 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 zh/adapter/README.md diff --git a/zh/adapter/README.md b/zh/adapter/README.md new file mode 100644 index 000000000..b00d757a6 --- /dev/null +++ b/zh/adapter/README.md @@ -0,0 +1,138 @@ +--- +layout: pattern +title: Adapter +folder: adapter +permalink: /patterns/adapter/ +categories: Structural +tags: + - Gang of Four +--- + +## 又被称为 +包装器 + +## 目的 +将一个接口转换成另一个客户所期望的接口。适配器让那些本来因为接口不兼容的类可以合作无间。 + +## 解释 + +现实世界例子 + +> 考虑有这么一种情况,在你的存储卡中有一些照片,你想将其传到你的电脑中。为了传送数据,你需要某种能够兼容你电脑接口的适配器以便你的储存卡能连上你的电脑。在这种情况下,读卡器就是一个适配器。 +> 另一个例子就是注明的电源适配器;三脚插头不能插在两脚插座上,需要一个电源适配器来使其能够插在两脚插座上。 +> 还有一个例子就是翻译官,他翻译一个人对另一个人说的话。 + +用直白的话来说 + +> 适配器模式让你可以把不兼容的对象包在适配器中,以让其兼容其他类。 + +维基百科中说 + +> 在软件工程中,适配器模式是一种可以让现有类的接口把其作为其他接口来使用的设计模式。它经常用来使现有的类和其他类能够工作并且不用修改其他类的源代码。 + +**编程样例(对象适配器)** + +假如有一个船长他只会划船,但不会航行。 + +首先我们有接口`RowingBoat`和`FishingBoat` + +```java +public interface RowingBoat { + void row(); +} + +public class FishingBoat { + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class); + public void sail() { + LOGGER.info("The fishing boat is sailing"); + } +} +``` +船长希望有一个`RowingBoat`接口的实现,这样就可以移动 + +```java +public class Captain { + + private final RowingBoat rowingBoat; + // default constructor and setter for rowingBoat + public Captain(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; + } + + public void row() { + rowingBoat.row(); + } +} +``` + +现在海盗来了,我们的船长需要逃跑但是只有一个渔船可用。我们需要创建一个可以让船长使用其划船技能来操作渔船的适配器。 + +```java +public class FishingBoatAdapter implements RowingBoat { + + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class); + + private final FishingBoat boat; + + public FishingBoatAdapter() { + boat = new FishingBoat(); + } + + @Override + public void row() { + boat.sail(); + } +} + +``` + +现在 `船长` 可以使用`FishingBoat`接口来逃离海盗了。 + +```java +var captain = new Captain(new FishingBoatAdapter()); +captain.row(); +``` + +## 类图 +![alt text](../../adapter/etc/adapter.urm.png "Adapter class diagram") + + +## 应用 +使用适配器模式当 + +* 你想使用一个已有类,但是它的接口不能和你需要的所匹配 +* 你需要创建一个可重用类,该类与不相关或不可预见的类进行协作,即不一定具有兼容接口的类 +* 你需要使用一些现有的子类,但是子类化他们每一个的子类来进行接口的适配是不现实的。一个对象适配器可以适配他们父类的接口。 +* 大多数使用第三方类库的应用使用适配器作为一个在应用和第三方类库间的中间层来使应用和类库解耦。如果必须使用另一个库,则只需使用一个新库的适配器而无需改变应用程序的代码。 + +## 后果: +类和对象适配器有不同的权衡取舍。一个类适配器 + +* 适配被适配者到目标接口,需要保证只有一个具体的被适配者类。作为结果,当我们想适配一个类和它所有的子类时,类适配器将不会起作用。 +* 可以让适配器重写一些被适配者的行为,因为适配器是被适配者的子类。 +* 只引入了一个对象,并且不需要其他指针间接访问被适配者。 + +对象适配器 + +* 一个适配器可以和许多被适配者工作,也就是被适配者自己和所有它的子类。适配器同时可以为所有被适配者添加功能。 +* 覆盖被适配者的行为变得更难。需要子类化被适配者然后让适配器引用这个子类不是被适配者。 + + +## 现实世界的案例 + +* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) +* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-) +* [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-) +* [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-) + + +## 鸣谢 + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) + +``` + +``` \ No newline at end of file From 6921b0dce0b503529a6bd8983bde91279487522c Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Wed, 19 Aug 2020 13:27:08 +0400 Subject: [PATCH 016/254] Fixed checkstyle errors causing build failures. --- .../iluwatar/ambassador/RemoteService.java | 3 +- .../ambassador/RemoteServiceStatus.java | 47 ++++-- .../com/iluwatar/commander/Commander.java | 138 +++++++++--------- .../component/manager/AiComponentManager.java | 8 +- .../manager/PhysicsComponentManager.java | 8 +- .../manager/RenderComponentManager.java | 8 +- unit-of-work/pom.xml | 1 + .../java/com/iluwatar/unitofwork/App.java | 1 + .../com/iluwatar/unitofwork/UnitActions.java | 44 ++++-- .../java/com/iluwatar/unitofwork/AppTest.java | 1 + 10 files changed, 151 insertions(+), 108 deletions(-) diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java index 42b09d617..e2877b683 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java @@ -74,6 +74,7 @@ public class RemoteService implements RemoteServiceInterface { } catch (InterruptedException e) { LOGGER.error("Thread sleep state interrupted", e); } - return waitTime <= THRESHOLD ? value * 10 : RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue(); + return waitTime <= THRESHOLD ? value * 10 + : RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue(); } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java index f9faebd0e..5d830e0fc 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java @@ -1,23 +1,48 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.ambassador; /** * Holds information regarding the status of the Remote Service. * - * !Attention - 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. + *

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) - ; + FAILURE(-1) + ; - private final long remoteServiceStatusValue; + private final long remoteServiceStatusValue; - RemoteServiceStatus(long remoteServiceStatusValue) { - this.remoteServiceStatusValue = remoteServiceStatusValue; - } + RemoteServiceStatus(long remoteServiceStatusValue) { + this.remoteServiceStatusValue = remoteServiceStatusValue; + } - public long getRemoteServiceStatusValue() { - return remoteServiceStatusValue; - } + public long getRemoteServiceStatusValue() { + return remoteServiceStatusValue; + } } diff --git a/commander/src/main/java/com/iluwatar/commander/Commander.java b/commander/src/main/java/com/iluwatar/commander/Commander.java index c2e124663..2909f9304 100644 --- a/commander/src/main/java/com/iluwatar/commander/Commander.java +++ b/commander/src/main/java/com/iluwatar/commander/Commander.java @@ -36,10 +36,10 @@ 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; -import java.util.List; /** *

Commander pattern is used to handle all issues that can come up while making a @@ -171,10 +171,53 @@ public class Commander { var list = paymentService.exceptionsList; var t = new Thread(() -> { Retry.Operation op = (l) -> { - handlePaymentRetryOperation(order, l); + if (!l.isEmpty()) { + if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { + LOG.debug("Order " + order.id + ": Error in connecting to payment service," + + " trying again.."); + } else { + LOG.debug("Order " + order.id + ": Error in creating payment request.."); + } + throw l.remove(0); + } + if (order.paid.equals(PaymentStatus.TRYING)) { + var transactionId = paymentService.receiveRequest(order.price); + order.paid = PaymentStatus.DONE; + LOG.info("Order " + order.id + ": Payment successful, transaction Id: " + transactionId); + if (!finalSiteMsgShown) { + LOG.info("Payment made successfully, thank you for shopping with us!!"); + finalSiteMsgShown = true; + } + sendSuccessMessage(order); + } }; Retry.HandleErrorIssue handleError = (o, err) -> { - handlePaymentErrorIssue(order, o, err); + if (PaymentDetailsErrorException.class.isAssignableFrom(err.getClass())) { + if (!finalSiteMsgShown) { + LOG.info("There was an error in payment. Your account/card details " + + "may have been incorrect. " + + "Meanwhile, your order has been converted to COD and will be shipped."); + finalSiteMsgShown = true; + } + LOG.error("Order " + order.id + ": Payment details incorrect, failed.."); + o.paid = PaymentStatus.NOT_DONE; + sendPaymentFailureMessage(o); + } else { + if (o.messageSent.equals(MessageSent.NONE_SENT)) { + if (!finalSiteMsgShown) { + LOG.info("There was an error in payment. We are on it, and will get back to you " + + "asap. Don't worry, your order has been placed and will be shipped."); + finalSiteMsgShown = true; + } + LOG.warn("Order " + order.id + ": Payment error, going to queue.."); + sendPaymentPossibleErrorMsg(o); + } + if (o.paid.equals(PaymentStatus.TRYING) && System + .currentTimeMillis() - o.createdTime < paymentTime) { + var qt = new QueueTask(o, TaskType.PAYMENT, -1); + updateQueue(qt); + } + } }; var r = new Retry<>(op, handleError, numOfRetries, retryDuration, e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass())); @@ -187,58 +230,6 @@ public class Commander { t.start(); } - private void handlePaymentRetryOperation(Order order, List l) throws Exception { - if (!l.isEmpty()) { - if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { - LOG.debug("Order " + order.id + ": Error in connecting to payment service," - + " trying again.."); - } else { - LOG.debug("Order " + order.id + ": Error in creating payment request.."); - } - throw l.remove(0); - } - if (order.paid.equals(PaymentStatus.TRYING)) { - var transactionId = paymentService.receiveRequest(order.price); - order.paid = PaymentStatus.DONE; - LOG.info("Order " + order.id + ": Payment successful, transaction Id: " + transactionId); - - if (!finalSiteMsgShown) { - LOG.info("Payment made successfully, thank you for shopping with us!!"); - finalSiteMsgShown = true; - } - sendSuccessMessage(order); - } - } - - private void handlePaymentErrorIssue(Order order, Order o, Exception err) { - if (PaymentDetailsErrorException.class.isAssignableFrom(err.getClass())) { - if (!finalSiteMsgShown) { - LOG.info("There was an error in payment. Your account/card details " - + "may have been incorrect. " - + "Meanwhile, your order has been converted to COD and will be shipped."); - finalSiteMsgShown = true; - } - LOG.error("Order " + order.id + ": Payment details incorrect, failed.."); - o.paid = PaymentStatus.NOT_DONE; - sendPaymentFailureMessage(o); - } else { - if (o.messageSent.equals(MessageSent.NONE_SENT)) { - if (!finalSiteMsgShown) { - LOG.info("There was an error in payment. We are on it, and will get back to you " - + "asap. Don't worry, your order has been placed and will be shipped."); - finalSiteMsgShown = true; - } - LOG.warn("Order " + order.id + ": Payment error, going to queue.."); - sendPaymentPossibleErrorMsg(o); - } - if (o.paid.equals(PaymentStatus.TRYING) && System - .currentTimeMillis() - o.createdTime < paymentTime) { - var qt = new QueueTask(o, TaskType.PAYMENT, -1); - updateQueue(qt); - } - } - } - private void updateQueue(QueueTask qt) { if (System.currentTimeMillis() - qt.order.createdTime >= this.queueTime) { // since payment time is lesser than queuetime it would have already failed.. @@ -371,24 +362,24 @@ public class Commander { private Retry.Operation handleSuccessMessageRetryOperation(Order order) { return (l) -> { - if (!l.isEmpty()) { - if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { - LOG.debug("Order " + order.id + ": Error in connecting to messaging service " - + "(Payment Success msg), trying again.."); - } else { - LOG.debug("Order " + order.id + ": Error in creating Payment Success" - + " messaging request.."); - } - throw l.remove(0); + if (!l.isEmpty()) { + if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { + LOG.debug("Order " + order.id + ": Error in connecting to messaging service " + + "(Payment Success msg), trying again.."); + } else { + LOG.debug("Order " + order.id + ": Error in creating Payment Success" + + " messaging request.."); } - if (!order.messageSent.equals(MessageSent.PAYMENT_FAIL) - && !order.messageSent.equals(MessageSent.PAYMENT_SUCCESSFUL)) { - var requestId = messagingService.receiveRequest(2); - order.messageSent = MessageSent.PAYMENT_SUCCESSFUL; - LOG.info("Order " + order.id + ": Payment Success message sent," - + " request Id: " + requestId); - } - }; + throw l.remove(0); + } + if (!order.messageSent.equals(MessageSent.PAYMENT_FAIL) + && !order.messageSent.equals(MessageSent.PAYMENT_SUCCESSFUL)) { + var requestId = messagingService.receiveRequest(2); + order.messageSent = MessageSent.PAYMENT_SUCCESSFUL; + LOG.info("Order " + order.id + ": Payment Success message sent," + + " request Id: " + requestId); + } + }; } private void sendPaymentFailureMessage(Order order) { @@ -483,7 +474,8 @@ public class Commander { } } - private void handlePaymentPossibleErrorMsgRetryOperation(Order order, List l) throws Exception { + private void handlePaymentPossibleErrorMsgRetryOperation(Order order, List l) + throws Exception { if (!l.isEmpty()) { if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) { LOG.debug("Order " + order.id + ": Error in connecting to messaging service " diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java index 1baf99a3a..c85bd1e68 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/AiComponentManager.java @@ -40,7 +40,7 @@ public class AiComponentManager { private final int numEntities; - private final Component[] AI_COMPONENTS = new AiComponent[MAX_ENTITIES]; + private final Component[] aiComponents = new AiComponent[MAX_ENTITIES]; public AiComponentManager(int numEntities) { this.numEntities = numEntities; @@ -51,7 +51,7 @@ public class AiComponentManager { */ public void start() { LOGGER.info("Start AI Game Component"); - IntStream.range(0, numEntities).forEach(i -> AI_COMPONENTS[i] = new AiComponent()); + IntStream.range(0, numEntities).forEach(i -> aiComponents[i] = new AiComponent()); } /** @@ -60,7 +60,7 @@ public class AiComponentManager { public void update() { LOGGER.info("Update AI Game Component"); IntStream.range(0, numEntities) - .filter(i -> AI_COMPONENTS.length > i && AI_COMPONENTS[i] != null) - .forEach(i -> AI_COMPONENTS[i].update()); + .filter(i -> aiComponents.length > i && aiComponents[i] != null) + .forEach(i -> aiComponents[i].update()); } } diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java index e5917979c..155793c88 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/PhysicsComponentManager.java @@ -40,7 +40,7 @@ public class PhysicsComponentManager { private final int numEntities; - private final Component[] PHYSICS_COMPONENTS = new PhysicsComponent[MAX_ENTITIES]; + private final Component[] physicsComponents = new PhysicsComponent[MAX_ENTITIES]; public PhysicsComponentManager(int numEntities) { this.numEntities = numEntities; @@ -51,7 +51,7 @@ public class PhysicsComponentManager { */ public void start() { LOGGER.info("Start Physics Game Component "); - IntStream.range(0, numEntities).forEach(i -> PHYSICS_COMPONENTS[i] = new PhysicsComponent()); + IntStream.range(0, numEntities).forEach(i -> physicsComponents[i] = new PhysicsComponent()); } @@ -62,7 +62,7 @@ public class PhysicsComponentManager { LOGGER.info("Update Physics Game Component "); // Process physics. IntStream.range(0, numEntities) - .filter(i -> PHYSICS_COMPONENTS.length > i && PHYSICS_COMPONENTS[i] != null) - .forEach(i -> PHYSICS_COMPONENTS[i].update()); + .filter(i -> physicsComponents.length > i && physicsComponents[i] != null) + .forEach(i -> physicsComponents[i].update()); } } diff --git a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java index b3522f908..be1d3c2e9 100644 --- a/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java +++ b/data-locality/src/main/java/com/iluwatar/data/locality/game/component/manager/RenderComponentManager.java @@ -40,7 +40,7 @@ public class RenderComponentManager { private final int numEntities; - private final Component[] RENDER_COMPONENTS = new RenderComponent[MAX_ENTITIES]; + private final Component[] renderComponents = new RenderComponent[MAX_ENTITIES]; public RenderComponentManager(int numEntities) { this.numEntities = numEntities; @@ -51,7 +51,7 @@ public class RenderComponentManager { */ public void start() { LOGGER.info("Start Render Game Component "); - IntStream.range(0, numEntities).forEach(i -> RENDER_COMPONENTS[i] = new RenderComponent()); + IntStream.range(0, numEntities).forEach(i -> renderComponents[i] = new RenderComponent()); } @@ -62,7 +62,7 @@ public class RenderComponentManager { LOGGER.info("Update Render Game Component "); // Process Render. IntStream.range(0, numEntities) - .filter(i -> RENDER_COMPONENTS.length > i && RENDER_COMPONENTS[i] != null) - .forEach(i -> RENDER_COMPONENTS[i].render()); + .filter(i -> renderComponents.length > i && renderComponents[i] != null) + .forEach(i -> renderComponents[i].render()); } } diff --git a/unit-of-work/pom.xml b/unit-of-work/pom.xml index 1fab10186..0f8f0b21a 100644 --- a/unit-of-work/pom.xml +++ b/unit-of-work/pom.xml @@ -47,6 +47,7 @@ org.junit.jupiter junit-jupiter-engine + 5.0.0 test diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java index a9e41dd7c..6caf1de49 100644 --- a/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java @@ -35,6 +35,7 @@ public class App { * * @param args no argument sent */ + public static void main(String[] args) { var ram = new Student(1, "Ram", "Street 9, Cupertino"); var shyam = new Student(2, "Shyam", "Z bridge, Pune"); diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java index b00d015a3..36e738626 100644 --- a/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/UnitActions.java @@ -1,18 +1,40 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.unitofwork; public enum UnitActions { - INSERT("INSERT"), - DELETE("DELETE"), - MODIFY("MODIFY") - ; + INSERT("INSERT"), + DELETE("DELETE"), + MODIFY("MODIFY"); - private final String actionValue; + private final String actionValue; - UnitActions(String actionValue) { - this.actionValue = actionValue; - } + UnitActions(String actionValue) { + this.actionValue = actionValue; + } - public String getActionValue() { - return actionValue; - } + public String getActionValue() { + return actionValue; + } } diff --git a/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java b/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java index 2fbe37ccf..630bb1392 100644 --- a/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java +++ b/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java @@ -31,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; * AppTest */ public class AppTest { + @Test public void shouldExecuteWithoutException() { assertDoesNotThrow(() -> App.main(new String[]{})); From 860453b46b73d7e977196a28439f1c4b4dca3c64 Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Wed, 19 Aug 2020 23:14:37 +0400 Subject: [PATCH 017/254] Fixed JUnit tests causing build issues due to mixing JUnit 4 & JUnit 5 --- .../java/org/dirty/flag/DirtyFlagTest.java | 14 +++---- partial-response/pom.xml | 14 +++---- .../com/iluwatar/partialresponse/AppTest.java | 11 +++--- .../partialresponse/FieldJsonMapperTest.java | 19 +++++---- .../partialresponse/VideoResourceTest.java | 39 +++++++++---------- pom.xml | 7 ++++ 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java b/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java index 6a3274a45..d0c9079a6 100644 --- a/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java +++ b/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java @@ -23,29 +23,27 @@ package org.dirty.flag; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import com.iluwatar.dirtyflag.DataFetcher; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Application test */ -public class DirtyFlagTest { +class DirtyFlagTest { @Test - public void testIsDirty() { + void testIsDirty() { var df = new DataFetcher(); var countries = df.fetch(); - assertFalse(countries.isEmpty()); + Assertions.assertTrue(countries.isEmpty()); } @Test - public void testIsNotDirty() { + void testIsNotDirty() { var df = new DataFetcher(); df.fetch(); var countries = df.fetch(); - assertTrue(countries.isEmpty()); + Assertions.assertTrue(countries.isEmpty()); } } diff --git a/partial-response/pom.xml b/partial-response/pom.xml index eb094874f..fad5450d9 100644 --- a/partial-response/pom.xml +++ b/partial-response/pom.xml @@ -35,13 +35,15 @@ partial-response - - junit - junit - org.junit.vintage junit-vintage-engine + 5.4.0 + test + + + org.mockito + mockito-junit-jupiter test @@ -49,10 +51,6 @@ junit-jupiter-engine test - - org.mockito - mockito-core - diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java index b00ee6861..c423355f5 100644 --- a/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java +++ b/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java @@ -23,18 +23,17 @@ package com.iluwatar.partialresponse; -import org.junit.Test; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; /** * Application test */ -public class AppTest { +class AppTest { @Test - public void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); + void shouldExecuteApplicationWithoutException() { + Assertions.assertDoesNotThrow(() -> App.main(new String[]{})); } } \ No newline at end of file diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java index 57741c1d7..6bf5bf190 100644 --- a/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java +++ b/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java @@ -23,24 +23,23 @@ package com.iluwatar.partialresponse; -import static org.junit.Assert.assertEquals; - -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * tests {@link FieldJsonMapper}. */ -public class FieldJsonMapperTest { - private FieldJsonMapper mapper; +class FieldJsonMapperTest { + private static FieldJsonMapper mapper; - @Before - public void setUp() { + @BeforeAll + static void setUp() { mapper = new FieldJsonMapper(); } @Test - public void shouldReturnJsonForSpecifiedFieldsInVideo() throws Exception { + void shouldReturnJsonForSpecifiedFieldsInVideo() throws Exception { var fields = new String[]{"id", "title", "length"}; var video = new Video( 2, "Godzilla Resurgence", 120, @@ -50,6 +49,6 @@ public class FieldJsonMapperTest { var jsonFieldResponse = mapper.toJson(video, fields); var expectedDetails = "{\"id\": 2,\"title\": \"Godzilla Resurgence\",\"length\": 120}"; - assertEquals(expectedDetails, jsonFieldResponse); + Assertions.assertEquals(expectedDetails, jsonFieldResponse); } } \ No newline at end of file diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java index 252499803..dbd8e78dd 100644 --- a/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java +++ b/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java @@ -23,30 +23,29 @@ package com.iluwatar.partialresponse; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; /** * tests {@link VideoResource}. */ -@RunWith(MockitoJUnitRunner.class) -public class VideoResourceTest { +@ExtendWith(MockitoExtension.class) +class VideoResourceTest { @Mock - private FieldJsonMapper fieldJsonMapper; + private static FieldJsonMapper fieldJsonMapper; - private VideoResource resource; + private static VideoResource resource; - @Before - public void setUp() { + @BeforeAll + static void setUp() { var videos = Map.of( 1, new Video(1, "Avatar", 178, "epic science fiction film", "James Cameron", "English"), @@ -58,23 +57,23 @@ public class VideoResourceTest { } @Test - public void shouldGiveVideoDetailsById() throws Exception { + void shouldGiveVideoDetailsById() throws Exception { var actualDetails = resource.getDetails(1); var expectedDetails = "{\"id\": 1,\"title\": \"Avatar\",\"length\": 178,\"description\": " + "\"epic science fiction film\",\"director\": \"James Cameron\",\"language\": \"English\",}"; - assertEquals(expectedDetails, actualDetails); + Assertions.assertEquals(expectedDetails, actualDetails); } @Test - public void shouldGiveSpecifiedFieldsInformationOfVideo() throws Exception { + void shouldGiveSpecifiedFieldsInformationOfVideo() throws Exception { var fields = new String[]{"id", "title", "length"}; var expectedDetails = "{\"id\": 1,\"title\": \"Avatar\",\"length\": 178}"; - when(fieldJsonMapper.toJson(any(Video.class), eq(fields))).thenReturn(expectedDetails); + Mockito.when(fieldJsonMapper.toJson(Matchers.any(Video.class), Matchers.eq(fields))).thenReturn(expectedDetails); var actualFieldsDetails = resource.getDetails(2, fields); - assertEquals(expectedDetails, actualFieldsDetails); + Assertions.assertEquals(expectedDetails, actualFieldsDetails); } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9b3382795..e917304a8 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ 1.3.2 1.19.0 1.4.8 + 3.5.0 https://sonarcloud.io iluwatar @@ -226,6 +227,12 @@ spring-webmvc ${spring.version} + + org.mockito + mockito-junit-jupiter + ${mockito-junit-jupiter.version} + test + com.h2database h2 From c35b98b4d74a17211850c42cf507bdd49eb39769 Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Thu, 20 Aug 2020 01:01:03 +0400 Subject: [PATCH 018/254] Fixed pom.xml issues within the dirty-flag and partial-response modules that were causing build failures. --- dirty-flag/pom.xml | 7 ++++++- partial-response/pom.xml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dirty-flag/pom.xml b/dirty-flag/pom.xml index c014cd41e..372a637f1 100644 --- a/dirty-flag/pom.xml +++ b/dirty-flag/pom.xml @@ -31,7 +31,6 @@ java-design-patterns 1.23.0-SNAPSHOT - com.iluwatar dirty-flag 1.23.0-SNAPSHOT dirty-flag @@ -45,6 +44,12 @@ junit-jupiter-engine test + + org.mockito + mockito-junit-jupiter + 3.5.0 + test + diff --git a/partial-response/pom.xml b/partial-response/pom.xml index fad5450d9..d10a496dd 100644 --- a/partial-response/pom.xml +++ b/partial-response/pom.xml @@ -44,6 +44,7 @@ org.mockito mockito-junit-jupiter + 3.5.0 test From 885c8a6765b37f3a403b63b993d1996ae2a31e1b Mon Sep 17 00:00:00 2001 From: Toxic Dreamz Date: Thu, 20 Aug 2020 01:21:03 +0400 Subject: [PATCH 019/254] Fixed a test-case issue within the dirty-flag module. --- dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java b/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java index d0c9079a6..9af9664d6 100644 --- a/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java +++ b/dirty-flag/src/test/java/org/dirty/flag/DirtyFlagTest.java @@ -36,7 +36,7 @@ class DirtyFlagTest { void testIsDirty() { var df = new DataFetcher(); var countries = df.fetch(); - Assertions.assertTrue(countries.isEmpty()); + Assertions.assertFalse(countries.isEmpty()); } @Test From 905b5dc6d86d0e346d6336a2c4e7dcea9e622a71 Mon Sep 17 00:00:00 2001 From: Michal Krzywanski Date: Fri, 21 Aug 2020 11:07:23 +0200 Subject: [PATCH 020/254] Implemented filterer pattern --- filterer/README.MD | 45 ++++++ filterer/etc/filterer.png | Bin 0 -> 141773 bytes filterer/etc/filterer.urm.puml | 132 ++++++++++++++++++ filterer/pom.xml | 76 ++++++++++ .../iluwatar/filterer/domain/Filterer.java | 36 +++++ .../com/iluwatar/filterer/issue/Issue.java | 49 +++++++ .../filterer/issue/IssueAwareText.java | 55 ++++++++ .../filterer/issue/IssuePosition.java | 76 ++++++++++ .../iluwatar/filterer/issue/IssueType.java | 26 ++++ .../issue/ProbabilisticIssueAwareText.java | 49 +++++++ .../filterer/issue/ProbableIssue.java | 35 +++++ .../iluwatar/filterer/issue/SimpleIssue.java | 79 +++++++++++ .../filterer/issue/SimpleIssueAwareText.java | 98 +++++++++++++ .../SimpleProbabilisticIssueAwareText.java | 101 ++++++++++++++ .../filterer/issue/SimpleProbableIssue.java | 70 ++++++++++ .../issue/SimpleIssueAwareTextTest.java | 52 +++++++ ...SimpleProbabilisticIssueAwareTextTest.java | 52 +++++++ pom.xml | 1 + 18 files changed, 1032 insertions(+) create mode 100644 filterer/README.MD create mode 100644 filterer/etc/filterer.png create mode 100644 filterer/etc/filterer.urm.puml create mode 100644 filterer/pom.xml create mode 100644 filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java create mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java create mode 100644 filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java create mode 100644 filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java diff --git a/filterer/README.MD b/filterer/README.MD new file mode 100644 index 000000000..8a2526048 --- /dev/null +++ b/filterer/README.MD @@ -0,0 +1,45 @@ +--- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ +layout: pattern +title: Filterer Pattern +folder: filterer +permalink: /patterns/filterer/ +description: Design pattern that helps container-like objects to return filtered version of themselves.# short meta description that shows in Google search results +categories: + - Functional +tags: + - Extensibility +--- + +## Name / classification +Filterer Pattern + +## Intent +The intent of this design pattern is to to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. + +## Explanation +The container-like object needs to have a method that returns an instance of `Filterer`. This helper interface gives +ability to covariantly specify a lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the container-like objects. + +## Class diagram +![Filterer](./etc/filterer.png "Filterer") + +## Applicability +Pattern can be used when working with container-like objects that use subtyping, instead of parametrizing(generics) for extensible class structure. +It enables you to easily extend filtering ability of container-like objects as business requirements change. + +## Tutorials +* [Article about Filterer pattern posted on it's author's blog](https://blog.tlinkowski.pl/2018/filterer-pattern/) +* [Application of Filterer pattern in domain of text analysis](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) + +## Known uses +One of the uses is present on the blog presented in this link. It presents how to use `Filterer` pattern to create text issue anaylyzer with support for test cases used for unit testing. + +## Consequences (the good and the bad, add criticism here) +Good : + * you can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes. + +Bad : + * covariant return types mixed with generics can be sometimes tricky + +## Credits +* Author of the pattern : [Tomasz Linkowski](https://tlinkowski.pl/) \ No newline at end of file diff --git a/filterer/etc/filterer.png b/filterer/etc/filterer.png new file mode 100644 index 0000000000000000000000000000000000000000..f86764aa32aa18b063105c8ab529c2d04747326c GIT binary patch literal 141773 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%0ALv#igQ8NZ|3?qHU^qD?G%J=d~i5NG+tY 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

pY19!`Gaxytl%FiSo0r1}x?B$#Xwa2HWdQ5vi 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 literal 0 HcmV?d00001 diff --git a/filterer/etc/filterer.urm.puml b/filterer/etc/filterer.urm.puml new file mode 100644 index 000000000..24060b6aa --- /dev/null +++ b/filterer/etc/filterer.urm.puml @@ -0,0 +1,132 @@ +@startuml +package com.iluwatar.filterer.domain { + interface Filterer { + + by(Predicate) : G {abstract} + } +} +package com.iluwatar.filterer.issue { + interface Issue { + + endOffset() : int {abstract} + + startOffset() : int {abstract} + + type() : IssueType {abstract} + } + interface IssueAwareText { + + filtered() : Filterer {abstract} + + issues() : List {abstract} + + text() : String {abstract} + } + class IssuePosition { + - endOffset : int + - startOffset : int + - IssuePosition(startOffset : int, endOffset : int) + ~ endOffset() : int + + equals(o : Object) : boolean + + hashCode() : int + + of(startOffset : int, endOffset : int) : IssuePosition {static} + ~ startOffset() : int + } + ~enum IssueType { + + GRAMMAR {static} + + SPELLING {static} + + valueOf(name : String) : IssueType {static} + + values() : IssueType[] {static} + } + interface IssueWiseText { + + filtered() : Filterer {abstract} + + issues() : List {abstract} + + text() : String {abstract} + } + interface ProbabilisticIssueAwareText { + + filtered() : Filterer {abstract} + + issues() : List {abstract} + } + interface ProbabilisticIssueWiseText { + + filtered() : Filterer {abstract} + + issues() : List {abstract} + } + interface ProbableIssue { + + probability() : double {abstract} + } + class SimpleIssue { + - issuePosition : IssuePosition + - issueType : IssueType + ~ SimpleIssue(issuePosition : IssuePosition, issueType : IssueType) + + endOffset() : int + + equals(o : Object) : boolean + + hashCode() : int + + startOffset() : int + + type() : IssueType + } + class SimpleIssueAwareText { + - issues : ImmutableList + - text : String + ~ SimpleIssueAwareText(text : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : IssueAwareText + - filteredItems(predicate : Predicate) : ImmutableList + + hashCode() : int + + issues() : List + + text() : String + } + class SimpleIssueWiseText { + - issues : ImmutableList + - text : String + + SimpleIssueWiseText(text : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : IssueWiseText + - filteredItems(predicate : Predicate) : ImmutableList + + hashCode() : int + + issues() : List + + text() : String + } + class SimpleProbabilisticIssueAwareText { + - issues : ImmutableList + - text : String + ~ SimpleProbabilisticIssueAwareText(text : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ProbabilisticIssueAwareText + - filteredItems(predicate : Predicate) : ImmutableList + + hashCode() : int + + issues() : List + + text() : String + } + class SimpleProbabilisticIssueWiseText { + - issues : ImmutableList + - text : String + + SimpleProbabilisticIssueWiseText(text : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ProbabilisticIssueWiseText + - filteredItems(predicate : Predicate) : ImmutableList + + hashCode() : int + + issues() : List + + text() : String + } + class SimpleProbableIssue { + - probability : double + ~ SimpleProbableIssue(issuePosition : IssuePosition, issueType : IssueType, probability : double) + + equals(o : Object) : boolean + + hashCode() : int + + probability() : double + } +} +SimpleIssueWiseText --> "-issues" Issue +SimpleProbabilisticIssueAwareText --> "-issues" ProbableIssue +SimpleIssue --> "-issueType" IssueType +SimpleIssueAwareText --> "-issues" Issue +SimpleProbabilisticIssueWiseText --> "-issues" ProbableIssue +SimpleIssue --> "-issuePosition" IssuePosition +ProbabilisticIssueAwareText --|> IssueAwareText +ProbabilisticIssueWiseText --|> IssueWiseText +ProbableIssue --|> Issue +SimpleIssue ..|> Issue +SimpleIssueAwareText ..|> IssueAwareText +SimpleIssueWiseText ..|> IssueWiseText +SimpleProbabilisticIssueAwareText ..|> ProbabilisticIssueAwareText +SimpleProbabilisticIssueWiseText ..|> ProbabilisticIssueWiseText +SimpleProbableIssue ..|> ProbableIssue +SimpleProbableIssue --|> SimpleIssue +@enduml \ No newline at end of file diff --git a/filterer/pom.xml b/filterer/pom.xml new file mode 100644 index 000000000..24dae571e --- /dev/null +++ b/filterer/pom.xml @@ -0,0 +1,76 @@ + + + + + java-design-patterns + com.iluwatar + 1.23.0-SNAPSHOT + + 4.0.0 + + filterer + + + + com.google.guava + guava + 29.0-jre + + + org.junit.jupiter + junit-jupiter-api + 5.6.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.6.2 + test + + + org.assertj + assertj-core + 3.16.1 + test + + + + + + + maven-surefire-plugin + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 + + + + \ No newline at end of file diff --git a/filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java b/filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java new file mode 100644 index 000000000..17970c115 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java @@ -0,0 +1,36 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.domain; + +import java.util.function.Predicate; + +/** + * Filterer helper interface. + * @param type of the container-like object. + * @param type of the elements contained within this container-like object. + */ +@FunctionalInterface +public interface Filterer { + G by(Predicate predicate); +} \ No newline at end of file diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java b/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java new file mode 100644 index 000000000..957ade6e5 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java @@ -0,0 +1,49 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +/** + * Represents an issue that can be detected in given text. + */ +public interface Issue { + /** + * Returns starting position where the issue begins. + * + * @return value representing starting position of the issue. + */ + int startOffset(); + + /** + * Returns ending position where the issue ends. + * + * @return value representing ending position of the issue. + */ + int endOffset(); + + /** + * Returns issue type. + * @return {@link IssueType} + */ + IssueType type(); +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java new file mode 100644 index 000000000..8141ae849 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java @@ -0,0 +1,55 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import com.iluwatar.filterer.domain.Filterer; + +import java.util.List; + +/** + * Represents text that is aware of issues that are present in it. + */ +public interface IssueAwareText { + + /** + * Returns the analyzed text. + * + * @return the analyzed text. + */ + String text(); + + /** + * Returns list of issues for this text. + * @return list of issues for this text. + */ + List issues(); + + /** + * Returns the instance of {@link Filterer} helper interface that allows to covariantly + * specify lower bound for predicate that we want to filter by. + * @return an instance of {@link Filterer} helper interface. + */ + Filterer filtered(); + +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java b/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java new file mode 100644 index 000000000..a771c1a82 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java @@ -0,0 +1,76 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import java.util.Objects; + +/** + * Represents position of an issue. Takes starting and ending offset of issue in given text. + */ +public final class IssuePosition { + + private final int startOffset; + private final int endOffset; + + /** + * Factory method for constructing `IssuePosition` instances. + * @param startOffset starting offset of where the issue begins. + * @param endOffset ending offset of where the issue ends. + * @return new IssuePosition instance. + */ + public static IssuePosition of(final int startOffset, final int endOffset) { + return new IssuePosition(startOffset, endOffset); + } + + private IssuePosition(int startOffset, int endOffset) { + this.startOffset = startOffset; + this.endOffset = endOffset; + } + + int startOffset() { + return startOffset; + } + + int endOffset() { + return endOffset; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IssuePosition that = (IssuePosition) o; + return startOffset == that.startOffset + && endOffset == that.endOffset; + } + + @Override + public int hashCode() { + return Objects.hash(startOffset, endOffset); + } +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java b/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java new file mode 100644 index 000000000..ee2c12ce5 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java @@ -0,0 +1,26 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +enum IssueType { GRAMMAR, SPELLING } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java new file mode 100644 index 000000000..da15bdd99 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java @@ -0,0 +1,49 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import com.iluwatar.filterer.domain.Filterer; + +import java.util.List; + +/** + * Represents text that is aware of it's issues with given probability of their occurrence. + */ +public interface ProbabilisticIssueAwareText extends IssueAwareText { + + /** + * {@inheritDoc} + * @return + */ + @Override + List issues(); + + /** + * {@inheritDoc} + * @return + */ + @Override + Filterer filtered(); +} + diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java b/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java new file mode 100644 index 000000000..ccb047fa4 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java @@ -0,0 +1,35 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +/** + * Represents issue that is an issue with given probability. + */ +public interface ProbableIssue extends Issue { + /** + * Returns probability of occurrence of given issue. + * @return probability of occurrence of given issue. + */ + double probability(); +} \ No newline at end of file diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java new file mode 100644 index 000000000..fde5b8d8e --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java @@ -0,0 +1,79 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import java.util.Objects; + +public class SimpleIssue implements Issue { + + private final IssuePosition issuePosition; + private final IssueType issueType; + + SimpleIssue(final IssuePosition issuePosition, IssueType issueType) { + this.issuePosition = issuePosition; + this.issueType = issueType; + } + + /** + * {@inheritDoc} + */ + @Override + public int startOffset() { + return issuePosition.startOffset(); + } + + /** + * {@inheritDoc} + */ + @Override + public int endOffset() { + return issuePosition.endOffset(); + } + + /** + * {@inheritDoc} + */ + @Override + public IssueType type() { + return issueType; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SimpleIssue that = (SimpleIssue) o; + return issuePosition.equals(that.issuePosition) + && issueType == that.issueType; + } + + @Override + public int hashCode() { + return Objects.hash(issuePosition, issueType); + } +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java new file mode 100644 index 000000000..c654a3aaa --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java @@ -0,0 +1,98 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import com.google.common.collect.ImmutableList; +import com.iluwatar.filterer.domain.Filterer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; + +/** + * {@inheritDoc} + */ +public class SimpleIssueAwareText implements IssueAwareText { + + private final String text; + private final ImmutableList issues; + + SimpleIssueAwareText(final String text, final List issues) { + this.text = text; + this.issues = ImmutableList.copyOf(issues); + } + + /** + * {@inheritDoc} + */ + @Override + public String text() { + return text; + } + + /** + * {@inheritDoc} + */ + @Override + public List issues() { + return new ArrayList<>(issues); + } + + /** + * {@inheritDoc} + */ + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private IssueAwareText filteredGroup(Predicate predicate) { + return new SimpleIssueAwareText(this.text, filteredItems(predicate)); + } + + private ImmutableList filteredItems(Predicate predicate) { + return this.issues.stream() + .filter(predicate) + .collect(ImmutableList.toImmutableList()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SimpleIssueAwareText that = (SimpleIssueAwareText) o; + return text.equals(that.text) + && issues.equals(that.issues); + } + + @Override + public int hashCode() { + return Objects.hash(text, issues); + } +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java new file mode 100644 index 000000000..e1b4afc82 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java @@ -0,0 +1,101 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import com.google.common.collect.ImmutableList; +import com.iluwatar.filterer.domain.Filterer; + +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; + +/** + * {@inheritDoc} + */ +public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwareText { + + private final String text; + private final ImmutableList issues; + + SimpleProbabilisticIssueAwareText(final String text, final List issues) { + this.text = text; + this.issues = ImmutableList.copyOf(issues); + } + + /** + * {@inheritDoc} + */ + @Override + public String text() { + return text; + } + + /** + * {@inheritDoc} + */ + @Override + public List issues() { + return issues; + } + + /** + * {@inheritDoc} + */ + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ProbabilisticIssueAwareText filteredGroup( + final Predicate predicate + ) { + return new SimpleProbabilisticIssueAwareText(this.text, filteredItems(predicate)); + } + + private ImmutableList filteredItems( + final Predicate predicate + ) { + return this.issues.stream() + .filter(predicate) + .collect(ImmutableList.toImmutableList()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SimpleProbabilisticIssueAwareText that = (SimpleProbabilisticIssueAwareText) o; + return text.equals(that.text) + && issues.equals(that.issues); + } + + @Override + public int hashCode() { + return Objects.hash(text, issues); + } +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java new file mode 100644 index 000000000..2b7672256 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java @@ -0,0 +1,70 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import java.util.Objects; + +/** + * {@inheritDoc} + */ +public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { + + private final double probability; + + SimpleProbableIssue(final IssuePosition issuePosition, + final IssueType issueType, + final double probability + ) { + super(issuePosition, issueType); + this.probability = probability; + } + + /** + * {@inheritDoc} + */ + @Override + public double probability() { + return probability; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + SimpleProbableIssue that = (SimpleProbableIssue) o; + return Double.compare(that.probability, probability) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), probability); + } +} diff --git a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java b/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java new file mode 100644 index 000000000..1278128ae --- /dev/null +++ b/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java @@ -0,0 +1,52 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SimpleIssueAwareTextTest { + + @Test + void shouldFilterByStartOffset() { + //given + SimpleIssue spellingIssue = new SimpleIssue(IssuePosition.of(4, 5), IssueType.SPELLING); + SimpleIssue grammarIssue = new SimpleIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR); + List issues = List.of(spellingIssue, grammarIssue); + + SimpleIssueAwareText simpleIssueWiseText = new SimpleIssueAwareText("I mihgt gone there", issues); + + //when + IssueAwareText filtered = simpleIssueWiseText.filtered() + .by(issue1 -> issue1.startOffset() == 4); + + //then + assertThat(filtered.issues()).hasSize(1); + assertThat(filtered.issues()).element(0).isEqualTo(spellingIssue); + } + +} diff --git a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java b/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java new file mode 100644 index 000000000..142415111 --- /dev/null +++ b/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java @@ -0,0 +1,52 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer.issue; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SimpleProbabilisticIssueAwareTextTest { + + @Test + void shouldFilterByProbability() { + //given + ProbableIssue spellingIssue = new SimpleProbableIssue(IssuePosition.of(4, 5), IssueType.SPELLING, 100); + ProbableIssue grammarIssue = new SimpleProbableIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR, 99); + List issues = List.of(spellingIssue, grammarIssue); + + SimpleProbabilisticIssueAwareText simpleIssueWiseText = new SimpleProbabilisticIssueAwareText("I mihgt gone there", issues); + + //when + ProbabilisticIssueAwareText filtered = simpleIssueWiseText.filtered() + .by(issue1 -> Double.compare(issue1.probability(), 99) == 0); + + //then + assertThat(filtered.issues()).hasSize(1); + assertThat(filtered.issues()).element(0).isEqualTo(grammarIssue); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0718ff045..1e34bcb67 100644 --- a/pom.xml +++ b/pom.xml @@ -193,6 +193,7 @@ strangler arrange-act-assert transaction-script + filterer From b388020fc0f42badd2af207e1440cb5f077f6d31 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 14:34:23 +0000 Subject: [PATCH 021/254] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 355744159..69f417574 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) -[![All Contributors](https://img.shields.io/badge/all_contributors-125-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-126-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -256,6 +256,7 @@ This project is licensed under the terms of the MIT license.
Bethan Palmer

💻 +
Toxic Dreamz

💻 From 7f09cd5b2d232cf267c5f9d3b69c7699fb8240eb Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 14:34:24 +0000 Subject: [PATCH 022/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index fa325716e..fadd92bc9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1140,6 +1140,15 @@ "contributions": [ "code" ] + }, + { + "login": "ToxicDreamz", + "name": "Toxic Dreamz", + "avatar_url": "https://avatars0.githubusercontent.com/u/45225562?v=4", + "profile": "https://github.com/ToxicDreamz", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From a2ae5d1324386b24aaf944e65304f4ef60481697 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 15:00:48 +0000 Subject: [PATCH 023/254] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 69f417574..4691b19b4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) -[![All Contributors](https://img.shields.io/badge/all_contributors-126-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-127-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -257,6 +257,7 @@ This project is licensed under the terms of the MIT license.
Bethan Palmer

💻
Toxic Dreamz

💻 +
Edy Cu Tjong

📖 From 0529b77abb677dda5ded898aa46c9d1c769e0718 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 15:00:49 +0000 Subject: [PATCH 024/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index fadd92bc9..b968e8c31 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1149,6 +1149,15 @@ "contributions": [ "code" ] + }, + { + "login": "edycutjong", + "name": "Edy Cu Tjong", + "avatar_url": "https://avatars1.githubusercontent.com/u/1098102?v=4", + "profile": "http://www.edycutjong.com", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 4, From 4068d1feadfd03fe683b6157aa1e13fa0f64e495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 22 Aug 2020 14:03:21 +0300 Subject: [PATCH 025/254] Update sonar badges --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4691b19b4..b0e297f82 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ ![Java CI with Maven](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI%20with%20Maven/badge.svg) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=ncloc)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![All Contributors](https://img.shields.io/badge/all_contributors-127-orange.svg?style=flat-square)](#contributors-) From 61b95c294be022b19d48f457ee459610e666dec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 22 Aug 2020 14:49:56 +0300 Subject: [PATCH 026/254] Update github token --- .github/workflows/maven-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index be0a74e9f..9281c0f3d 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -60,5 +60,5 @@ jobs: run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar env: # These two env variables are needed for sonar analysis - GITHUB_TOKEN: ${{ secrets.REPOSITORY_ACCESS_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 61a819aab8de2c9dce268815f641941bd45e18e7 Mon Sep 17 00:00:00 2001 From: Michal Krzywanski Date: Sat, 22 Aug 2020 17:53:09 +0200 Subject: [PATCH 027/254] Added fixes after review. Changed example pattern application to threat detection domain --- filterer/README.MD | 170 +++++++++++++++- filterer/etc/filterer.png | Bin 141773 -> 130820 bytes filterer/etc/filterer.urm.puml | 188 +++++++----------- filterer/pom.xml | 29 ++- .../main/java/com/iluwatar/filterer/App.java | 111 +++++++++++ .../filterer/issue/IssuePosition.java | 76 ------- .../ProbabilisticThreatAwareSystem.java} | 10 +- .../ProbableThreat.java} | 10 +- ...SimpleProbabilisticThreatAwareSystem.java} | 58 +++--- .../SimpleProbableThreat.java} | 23 ++- .../SimpleThreat.java} | 56 ++++-- .../SimpleThreatAwareSystem.java} | 43 ++-- .../{issue/Issue.java => threat/Threat.java} | 24 +-- .../ThreatAwareSystem.java} | 20 +- .../IssueType.java => threat/ThreatType.java} | 4 +- .../java/com/iluwatar/filterer/AppTest.java | 33 +++ ...leProbabilisticThreatAwareSystemTest.java} | 25 ++- .../SimpleThreatAwareSystemTest.java} | 28 ++- 18 files changed, 572 insertions(+), 336 deletions(-) create mode 100644 filterer/src/main/java/com/iluwatar/filterer/App.java delete mode 100644 filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java rename filterer/src/main/java/com/iluwatar/filterer/{issue/ProbabilisticIssueAwareText.java => threat/ProbabilisticThreatAwareSystem.java} (79%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/ProbableIssue.java => threat/ProbableThreat.java} (81%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/SimpleProbabilisticIssueAwareText.java => threat/SimpleProbabilisticThreatAwareSystem.java} (54%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/SimpleProbableIssue.java => threat/SimpleProbableThreat.java} (74%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/SimpleIssue.java => threat/SimpleThreat.java} (59%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/SimpleIssueAwareText.java => threat/SimpleThreatAwareSystem.java} (63%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/Issue.java => threat/Threat.java} (71%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/IssueAwareText.java => threat/ThreatAwareSystem.java} (78%) rename filterer/src/main/java/com/iluwatar/filterer/{issue/IssueType.java => threat/ThreatType.java} (92%) create mode 100644 filterer/src/test/java/com/iluwatar/filterer/AppTest.java rename filterer/src/test/java/com/iluwatar/filterer/{issue/SimpleProbabilisticIssueAwareTextTest.java => threat/SimpleProbabilisticThreatAwareSystemTest.java} (60%) rename filterer/src/test/java/com/iluwatar/filterer/{issue/SimpleIssueAwareTextTest.java => threat/SimpleThreatAwareSystemTest.java} (62%) diff --git a/filterer/README.MD b/filterer/README.MD index 8a2526048..3281e9ecc 100644 --- a/filterer/README.MD +++ b/filterer/README.MD @@ -1,6 +1,6 @@ --- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ layout: pattern -title: Filterer Pattern +title: Filterer folder: filterer permalink: /patterns/filterer/ description: Design pattern that helps container-like objects to return filtered version of themselves.# short meta description that shows in Google search results @@ -11,15 +11,173 @@ tags: --- ## Name / classification -Filterer Pattern +Filterer ## Intent The intent of this design pattern is to to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. ## Explanation -The container-like object needs to have a method that returns an instance of `Filterer`. This helper interface gives +Real world example + +> We are designing a threat(malware) detection system. We can have different types of threats and systems. We have a requirement that +> system should be aware of threats that are present in it. In the design we have to take into consideration that new Threat types can be +> added later. Also there is a requirement that a system can filter itself based on the threats that it possesses (system acts as container-like object for threats). +> + +In plain words + +> We need to be able to filter different types of systems(container-like objects) based on properties of Threats that they contain. +> Adding new properties for Threats should be easy (we still need the ability to filter by those new properties). + +**Programmatic Example** + +To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` interfaces. + +```java +public interface Threat { + String name(); + int id(); + ThreatType type(); +} + +public interface ThreatAwareSystem { + String systemId(); + List threats(); + Filterer filtered(); + +} +``` +Notice the `filtered` method that returns instance of `Filterer` interface which is defined as : +```java +@FunctionalInterface +public interface Filterer { + G by(Predicate predicate); +} +``` +it is used to fulfill the requirement for system to be able to filter itself based on threat properties. +The container-like object (`ThreatAwareSystem` in our case) needs to have a method that returns an instance of `Filterer`. This helper interface gives ability to covariantly specify a lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the container-like objects. +In our example we will be able to pass a predicate that takes `? extends Threat` object and return `? extends ThreatAwareSystem` +from `Filtered::by` method. A simple implementation of `ThreadAwareSystem` : +```java +public class SimpleThreatAwareSystem implements ThreatAwareSystem { + + private final String systemId; + private final ImmutableList issues; + + public SimpleThreatAwareSystem(final String systemId, final List issues) { + this.systemId = systemId; + this.issues = ImmutableList.copyOf(issues); + } + + @Override + public String systemId() { + return systemId; + } + + @Override + public List threats() { + return new ArrayList<>(issues); + } + + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ThreatAwareSystem filteredGroup(Predicate predicate) { + return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate)); + } + + private List filteredItems(Predicate predicate) { + return this.issues.stream() + .filter(predicate) + .collect(Collectors.toList()); + } +} +``` +the `filtered` method is overridden to filter the threats list by given predicate. + +Now if we introduce new subtype of `Thread` interface that adds probability with which given thread can appear : +```java +public interface ProbableThreat extends Threat { + double probability(); +} +``` +we can also introduce a new interface that represents a system that is aware of threats with their probabilities : +````java +public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { + @Override + List threats(); + + @Override + Filterer filtered(); +} +```` +Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify different return covariant type +by specifing different generic types. Our interfaces are clean and not cluttered by default implementations. We +we will be able to filter `ProbabilisticThreatAwareSystem` by `ProbableThreat` properties : +```java +public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { + + private final String systemId; + private final ImmutableList threats; + + public SimpleProbabilisticThreatAwareSystem(final String systemId, final List threats) { + this.systemId = systemId; + this.threats = ImmutableList.copyOf(threats); + } + + @Override + public String systemId() { + return systemId; + } + + @Override + public List threats() { + return threats; + } + + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ProbabilisticThreatAwareSystem filteredGroup(final Predicate predicate) { + return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate)); + } + + private List filteredItems(final Predicate predicate) { + return this.threats.stream() + .filter(predicate) + .collect(Collectors.toList()); + } +} +``` + +Now if we want filter `ThreatAwareSystem` by threat type we can do : +```java +Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); +Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); +List threats = List.of(rootkit, trojan); + +ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + +ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); +``` +or if we want to filter `ProbabilisticThreatAwareSystem` : +```java +ProbableThreat malwareTroyan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); +ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); +List probableThreats = List.of(malwareTroyan, rootkit); + +ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem =new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); + +ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); +``` ## Class diagram ![Filterer](./etc/filterer.png "Filterer") @@ -34,11 +192,11 @@ It enables you to easily extend filtering ability of container-like objects as b ## Known uses One of the uses is present on the blog presented in this link. It presents how to use `Filterer` pattern to create text issue anaylyzer with support for test cases used for unit testing. -## Consequences (the good and the bad, add criticism here) -Good : +## Consequences +Pros : * you can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes. -Bad : +Cons : * covariant return types mixed with generics can be sometimes tricky ## Credits diff --git a/filterer/etc/filterer.png b/filterer/etc/filterer.png index f86764aa32aa18b063105c8ab529c2d04747326c..6a6eb059b92d4bd0cc54d3d0df87cdff8eca01bb 100644 GIT binary patch literal 130820 zcma&Oby!qi`#lVTpdg?~rwB-cw6vgfcY}0yH-dn4x0En+cc-9q*H8ii(jwjO2K4j9 z_xWAd%RkCEbIzH)?^yR*Ya1vdC5(cEhXexygCZ*ORt^RRaR>(HUiO1~;FToYC`IrG zmA#;fy`Gh|i@AZJJ&dq{rGc%Ey@CESU6*IZ_V(7C3=G!hI+peh7UuMNRu)fQauC44 zz=fG8sM!B~9R?O$#`#l~@`Cit%g3JKU#_i}s4y$!`A{ZyVC zovVUSrSoKAjm#nGm6X>5=e(GGr{g&f-n6-=Bv0aPaLhTL{3aU4@cr73^>E23OG)jR zEFwW~{=4Z=kJ!Kc4vjj#u1rm0&|B@B1G_0pV0mNNAo+kB|I$MXF# z=P#cZ0=7T8C*g}dwUi@_Y?@#m!sf_knIsKuJ8`bP!L01f9)-`zkNn~`ZbDf)GxVJn zFJtt{!%P^oSIOz3-e1uONU3K17d35i;dWks4hcR{$dwRc+N*7%$(*1pCm%h@ZdXkr zdnVA?BlpTfh#=fhV97e;gga#S1>V|>?W2>DFJss=OItpHV~5qD+hVo)#UJFf?iUV? zakM~9N52cwMGhzq$f2fnA{hk79=^4Cqf9jpAL*%mc51lp=c3xq@(RHBgGmUKP%WkW!?ze#t^4>KSyJDBZTji`4@%!=NW{|0JTf0tE zKUHJprEgUv&8jv&6;+{4WA>tqkX73#R%#U^tS8UA#=G@DO(b zK1bJVB?i^y!u&{F1~uWrrN9tn$x?x%g!x4VRBDA2+M}u zEsfSC{vBQbWW=FXr-kpzhNGDKysP7Ce0?zJRM~5)04Gi6@$!|2i+!@%jQfW&(i*3@ z0E4*;W40NXnf@&atHI2eMZAiHh#3e+)x=Cb#+xUxy9IPckn@&mNMfZn$v6R`nc;*f zRXk>bZSJR{?@2SJ=_b15iYSqzDiaW~^0;Y-&uZ+K!K;t%yuT&mj4b4(vTB>;;Hm$vEP=?% z2BY@jDTzinLz4C<`p=^(m#~})M*SRmLEeL7&~K+`quZswFx2#XU|_sqMBnl&IBRXC zJk-Egx&F#8#epe^@fPFP>-!2X#Hc zbr6Ctnm5(tR&yUlF}g^-MhwmPpMSi)xP05AV}sr}o{OI^VPXlDl_zs^Dc509{=TWz z8W9HO9kpXT?#_X7J&box|Mxau9&YZS;9v;y-#00^-9FY!l$W#onB6nuQw z^G$9e&;DL@91Uj&{9WP=IpZujrE_6d<`RCB+i`Ja?jvz=@qCwylf9AqXy4iU<9~k0 zjx!dJZ!~AtM`q2)Gu)P)n$1@%Fdm+*vtzfMt+kk`Uj7=cr-b|W(tn;8Nwwp0s!T63 zGV*Y9vZfqV2)oU>hMH1J3W|X8D%0`uva-Fy!xUbRv+bFh>F0(aQVB0fI60x6ot+&W zdfidv*bG_(udLI3ec=q2mzF-bl8HztZdYh~9AZMi67DXvNUK7z41_~)_}2@ROD1w< zeapMMyJL84e~84>YZ~Vi78Px8ZK+inGg{3ze*XO2CPi1Jj?FBTkjwGsP)22VSy@@3 zMqfu&+;fbcoycs(k6cbWeF==d^(mZbNi5)-;j>$QRF15CJL&xJ+Tsd!>G!0zm&Zt! zs6E+Ov8LP3Y+Y1UrBxss5AAB3quA;BZp-@P(2pNgYAiKfU0p3L=?!E5ro-#I2*Y#k z;9+O4G3-xLFt)HD#K8EmwnkC=X?l8^jg2kF!Ojl((Ib5{ODAyY+S=M5@7Ya3bgi$i zFD|x~gPqjU(%RYCp*_DmUO>i2?}($uA1a?7&5^F4EvV!7MToJ4R#HKjnVG31L-k*n zo0^)2;;|Y#3A}leCu&}lkbt9Pq@sdDlYuwo&QPe~LKjz6Rpnq~^AHs^mEDSn2Afo! znI>|MRI=dlT)jgD!C-KUP*8 zwxO&&#VTb!i5a-Kxa4S`l)SvI!Dd_>%~&mMm9$*-l<%(%dX=UGyc1`|9qO6x3dNUq z+*|52r=h2(KR9mpLuO=TjClYSPiJi~4V&+3w#Ca!ZDV_zE=DBZfU=}hDNnhC$RezK zix`dDy+10-7Ve{FgQIH9<@IZbob1t8VlRD0^%_gerB1qGR;{TB9IO}XPnCWyFOy#B z-|tN=QLQ8I;nDb2Fl?p)c-D`Z!1UteG6 z;VQGq1YAzHqpc{!uAd2vdSX51N;XPGN)=l%RPt{RFA>%AySHKL zs2DxY?9Y;;qR@$mEM?g`QIKgUDRFq+Yinw1s;XEE-j|k_>x!S6;`W%8(I&SE!8RL; ziq^q?`79W$lJSAVZuP<5(#>WeBS*8&W`6!G_LjKvSNCsLnwqzD0e(oVxI0FJsa2Jg zAh(|VD?*>a+!d^swTs2wZ{zgIDG@8Seso7uc`SFKbdP{dNGb=xH};Z?tD)uUtaoID z3FPYhd}uZHOeV9!b(u4LQ0uE_Bn1&L=N#9*!K%+>C~XhOHu~ z_4i6I3OYluc|w*9hq|1Wc#NA$wZOx+wzlTx<^)BAKWpj@^T-MOHTymL>~sv1rKKf> zbgDkNa5#~{LyPQ~Vf{w2^8Q|xTI-B0InlU&^ryJEqU%3?=y#7W8x54Ag90y=!YM1d zIZ>4I=@V^FHe;RpDHF0@#UL6U%f}HvKR>-6`jcWm z+R4b>VHR-M7=!(Oc2HAOL#r)j>g?9UewYriHoq-iac35*b%?DXU#SAiDb7;K-*<7k zzwR3r9NbaJ^fw}K?n*YoyfyZI4eeyh>al@*<~+lrsSOm~&05kWj3Ja~|7)MJj=f>;Lf|`!)6!kxCL$tIQc?n|-{g9TjPp@P@a@Z_=c`D7VV`iq_;(0kWHPszWQGrA9jEjrwWPSa3&CZcnn7?!as9IISKc4-fyxLMiB5KB5go-M;`{Ed z^jCy`MRRLJi`z{v4hbz>M14K33#~K(Uxe7}g7IJPk-2NpdESeteK4_Nf&qKqB1!+1 z)!yiLS$+SJ(>o$(S62`QSQR~gH<$q^KpI~o3i9&brqE zo2Ryg6~P*Q1^dz2S)|#(Mnfb1F9d@3C!tm9?ep&ceJU7l4w6GY z@SC@=fT7_F4-`7}YI8Ig#ZRCo4n;}?R35bb%|Mv(M}H8)di>+n8-R588|^jJ{-7v+q=i_ zYLn}N6uq`SF0dN*WT(Rh9ySacrTiSGr)Asc;dwF&jQ;-C!$w`R(_z4JS&dyIQ~ zd-mM4YL%2AHyIch0Cqe(+#E?ah5PsGmR+3~T9|GcJykmp4@pgG^c1w6sE;8YU1xyg zk!85F{P4c|DyO_hBk&kLQ4Fl%OZwO^a{3hkEvKu=<pdK618R7UjAjb+B)FIvV?)5~oWv$JN%mSoimQt@S* zq0`Mx<*wC~NKsRN$=rDiuZYxUjo4bNfG*Bh7_!nEUr{Lf$avYJ5{v)}6``S$#>SM} zhJje;z46>ksjeG&^$wd|U%%$$A=RUhL; z;_#A@Qv|Y4LwZC%f9sb8U2S7BBaEBx}C@#R`PnA8ne=7F`go=6 z=G0YUqNCqTt5um!PfeYiok^wfULI}Fm_OP7NFkB%n2>OLX=!P3u}r@^Dj1sqmEhG- zTig3`8ygz|9(1y+@}udJ=Ch!Yqobqa-Gv-li{Nrnp^)?g(0$Cta`~r0o9!Xuu+0*W zr>~Tsn3w>=3!PeJ0=t!#tZZbh6k{PMvPvj=&eKi38D6GQ;`F5`|$xYHGX`jaNu zdPC0mD&FZFgq(HYBW+&QIW5Y&&9rG) z@87@QYTF)2;ljqoj_3Ym4F(BrFi3H8t4w_T`n9*WcWy4lpym3?P3Mj7l$-&a8k^hM zfk~VJE4%TK_lRUN8^j*eS4duDAA^*nWRYwp!nPEMI@Z7<%%@K~Hb5cQBUgY+-t~*6 zDd{Y)uC4|^7GR+L)qcGdU41h{@^ZH<6U@(`NMIQxXAbrVuynpUah@{gcvF5fo} zuBQ$d#Fj|AO(HKl;&FSyr~}0e4YYSY&Q)aiMlr zV@W*4lok6b+rCKYG7rHd1&xN?Nz>UG9}&^b$mnZ&dUi59!;0R4OdS^U{UO4LOwu`C zsGoneLf+CTj%uuWg;d)L!cPpL&pgj%y~>;PMm!zp$klb?=}D?gITo7Syu;aRshy|3 zRTDEQ-{#=2INix&&AcqfZ7ARM1v5=|Z?9e;y=MK;a|VVIv&mvv$Ic+kzMB4T-zZ(a zFP@#BF95Jrv*7vE$m{Y@IWC3I>&kbV8~zR^vsun2l!K5pR0qMD(Sl8{@i8zkc?L z=es%~4W6!dD0s|Z8Cbm6?*9=?^ur^^3tlZrga5gxb|Zc~5A*2G#pjNQM^ZzalPrnB zir#}(nGU~b?STfBqe`JhefzNb#A{22seE^iOQj@r=J(3z?!q7)HK+Uc)}*a1hSQfk z3dNb!@I#I{l5XT=WUm`5OMg9X3DOs|P_VSFgXQ!KT;AR??^InG$2?M2a`$VwPBpQz znyEC&{P4lgy^%=HSgsQdzxgr(7x|{}`_*6&5)$U=kLAi<-{)ycX{6BuX74G@Z76(|*`I`+g+eLlPLr5o3OO=EO3HcuO+c{l<}B_@H_gY!~SRP-Sl zS`B6LlD{7&2F4>|-r1R%87MSq{I!azY8k}6>d{J-N?iZDOc?EotgKn@D8v`920wAw zeQ>rBw-3d(JK9ne7w>%!hp4o#YH;#5ZFxW?lj3A@SJ+&$* z*8ONZ-tutcm%p3b!PuN$&hK%gv%|?p`9WSU)PB8DT^f}(nkZNUll|px^SSBz2vy9{ z?|fkslJ8#E!G}jj){c$@Jg%)xZit<%5tj3_#F(tqm ze-O8op2b7#fiYT|fjGXrzD|VA?k9%Fl54j2J@7ClhFsuBEX_1S(^$Y!@A$aM$uG~s zi19A`ow3lJovOUmCO74WeoL3J+muzao`EwRTBr%kMt#hK_MU4gHXi4WhGrh8D+JU! zCSG1v8=`U92m~DE{MBl7$yw{As_PglBj~!)0UqAwFwW*8pnXHP*qbC5*D7BiEn18 zHW__^)pg0?axXg(Kh7yf%#Ox5xU%F=0TI=`yOoek3e{M3@&kuKEdVj7ZZKgEi zEBHD&5IQa|&j1I@TgW}`4#YEA`FU#)=b=%vSgX^;m z{pkFhsT^@!!U7q^LKI(d>NypSStmri!6e5x*yHR24g5ZDLqxj8umx|0eTmlG`Eqz* z)ZCMtyiE}dA-Blr{e_TIK0ALdR=tVB5zDL=LQeRT-QU%>T+oqDFw;d+IhAE<=#8QG>)CQ;cP+3C-E+uE*rV$B__-?%_6`ou9ky^JFw3Kmu^r1rppRKab2)e}TapZF zC@0>-nQe^OC_cd2O((Ni5vwjL>W|kRsPk;HmrneGP!^Gm1u6z9pI7kX7h!8CP7|Tj zij5WfUYZnJCD~!<;*Hw69j?3cij{Q*%Exk?l)3AO#EsoO_-qHS++XqXUNzCw zt=(NKlCxn2L->Zey8HL@b1QgRvg z;lx3XkQp;FAkqXw$_!PFT1~DF8)G_*0tjG>Q;!-JMqY4$~9P1T>^S_Ue0T3jco-rHe=FOnrUukgk2uXt0 z+09&@D~rb=nTR5Hq90?n)DJlCT>bzQObCGe?V!cz(Y!Ds!H`g$+FrI*fEp_d`+x86XBJ!A+dq2vFp*IY!EMI- zW`7AMcw{YVAR*JYwDrz6d7Yb38@we!8<1Fltcaygp*7<}q137#ysK zh*msa?&2;m1R5kZ{imPHquwLe$6ieS=ZBjR>00F2U~)!3gNDcj?dh?Vs1oNkwI{LkxSaV=8U3NY<=W{>V8zj z&=b1_l2w{#T&t+fKaQ2hi{7p>0A1KQL|rqn;#twcTNn)8rA+Og)lfsjKVs;NU8UQ38#4iCGX22 zZAz*dK2{6C>QOS2T(Q5?{m>VX(LbkfIBfN+QWO#XjHNFhyqxV9b%{2zOk)z)t)*D8 z*cobiI>)P`s?LgRI-jlAfDp<}rT#T@r~XqYnxK$$e+o{AGR@D8@g|Tw+&pt;6O{#; zGX|~RIoBu4B+_*nqtW*-cD>5x=ZOXe!ZL+;oOb8=yMt;hSKbP@06d!vrpgLK-rhLL z*xMDP*O(HO{A@Zmt3e@wV}I>g+>Ry6$Vdu`U^2@d&|RY9`j?;PNLy_Wk$m*Y%O4tw zJ3lJYjSVLzUSC@Jxv>GtAEE$PiAFaOcP)18Wc~`b?pwZpUrB(S@&vatCYanbhq^+M zdAK(~+y88TdFJ4cc3q=GLIT_5ddc4TSi2}ra>Rb>rGb%`sPHmq20GKW=lkCxQOf_L zGJrtDFdjm|C%rVeaVFP5}jIZ(q=ecbDrvGSlV-h{Oa4WQT( zSo_bLC{Zg}m>pjnVTwbf>aoOv)GHzVF!}syIsAY+i2B*j9?*30o7tU1!Qz%mxF`OE zvJ{klPHv!gDDxP_woTuWVUO-Ta$+8>D?D8H^cY1W+mEY{I--EE>_~3@#>7*4IZMLN zZnfj&=x9DYa(ukNd8WtCRat*+Rbm4e|fIQf4Gz*US?aj@I_oicF`sWEe_Fj zX_Vd_uBeHn0-t9OT)*5dr|K(~vQ|D}Wp>^^@g3GJyQRu(G@q`4-I6mYwVLKCIg6oMIx+Fd$!v{9niu?j^_$1= zCJf+-aIjT^S})!SANr%<1I`wVwIDVR-HvxeeJf%9Jxet@^O4=qf4>;)GriVz?MOXP z9n}_-e;7L|XTlB7A0Y}!Ui3WNP&{%bg)w}iqmyy)nw_#ihw5I1FX1>~t!=cl=JVup zz%7ckTj)_n?tQu&_y0v2+B454a@_OgD0A3UT7PdT16aI$@L4c6?SOV{ zX|%T&2vHFTCb0j;0)my`j}<<{*?B4KJ^k`u9OS)@_Z0{U#9O&xfq{YH;nG0b2FP`A zF#hJ_VZsuN*RZl<+_(;&;?4+wjCnSgj z8~||(blUyjzd>6)Ob$|m{lwaO@%Yj4jV>ki8IVe;oDO1mS@&OY5ixEFVcdNDQ9-bq z!rg^&)?VK}r{aip4dwFx7URi};*%&UuVp`*tqGnD3;>PKP;kBBVO}@wPf^42c#$9=;ACrjma5>+j~@+-8p(UHp=ke z|0fHXKp>C16V*K8f2Z0jb2E1VEk27MGd=1PD-6zKoE=3BM^aZ)u%n=?)L6_oUYyu;+;We2Fx2-R9aAG&z9j+Vaz_yE&O(<*WOQ_Ne7x}T zdmo>B9bpjIA@mSCu)66zq;nTCs&+sAm&E@OK`W+6u^=uqG_<5-_h5b0YN5Fwi;>;2 z{lmlI;bFja0cA-%j<(KuZ>jY?93cS#B|bJb#Te=Pq5_j3OusEM@kc%*+hPAXs#2eaY-4xw#@5IXFti{c1Pq z&S_7%t!HjdOM|^{T?BdHcT1@)fplOt>`S-I8OV77$j6&SSW+YdvTv%rf@0e2JHcUXfy-=$&)h6x%z{HgV|XPuzsX& z6EHH6o8V{*r36u-ufo{DV>5ur5|q6MgOX(;@@}e(1xC%s2K6@S6l6P65ENO>Cb9&~ z%r?{0pYieW1tSufIXYH{hN2kE&CcF~gPZo90ig|+i{9n?2k7*)3-A>@ZY`w2fLQI}?8itXTwMr-yuaYYx zBV&xLT1i6UQ2{g1YGY+k%u$~z6*pq_LZQ(5+FE!-#KC0t@YvwUqQuy5x26d29aUp2 z!g#TdaQy-T3dT({5JUmp6JKiBkB241C6$(!nMvAP4ng3?sa)3=)gI2yGt9^b;ad*5 z2UMl3d}C}mIl0_C{}e@kKC>9AMps{iV8E6uI&WtmsEj=V0oQYX_M?EmT-ioA;a)?R z#54xWvog;bxrY8sb=&WDGoN2vFHBT{0b2zRjXxq0gr%7g?Z@!&99d43hoB#NGKnHhD;NQGV*t>7ZL5-lDmfkEPAU&kaZ6&1VpRFzr0;Pf?`LjDLY zrq{)uFjfVq(j;25fXVekdHBKKUrquH3_EfB538}%Oo#u zl8*T5)vJ%#VC_SvQ!0!GZ=yB~mpMDDuNBj1+?2IfDv?Q0VZo~ulJv-UW$WV;Qp)qK ziouce2z20L$!P)J5x{a|8B`>dmiqYkEOrFAxw)yUt5@JX0F+d9Oi5e@h}3dibBynI zTrQBPK4OXiW-aWFz~u&-1qQR_?5j8kyn3(!it|h3(e9|`pr9c1$v$G`e|!(=Kn7kM z#50%@*#k=6g%!b@2uAzomJc5toBBModP}k|V-sn5U7PnX)RnxGPVAIXGun6^NDVC> z4sx<2L=FMZn6a5>pX$aBH7VW~z7M1D_-UA(ev_>xxq9G{|2deqsF>KD2z#}f>W{(T ztcv1ZmG$|#yD;dMxUw(U{ugs62FKr1-_Ri6v9+~zb+*X>nAD#?jaRX)pp}7sjMsCY zw<5PoOJA~`hWHr^*^1t9vHHr3iydU-D+n>%FNcZ>3#Z7K@Abwru#0d@ccM5+a#40~ zjCJ>@GTwPB{zMPsqR5l{RNb1Mm$Lra=Ev8BjD@sFRY-;89ghqIP* zJ&PSciIU3{3I!8=IL|~(V%C6=R5boRGxZ|bEW2HEijLL zVq8`fW4GJ_%)gO9YYPf*X|^hJT113*p1k((h;@s*OL$ck=1iQ*QgxZ6MB;BI3#T@p zhvs&LH{+ea8+AFoTpjaHz%z{U%IQn=J)oO`0bTiFe(vHxc8rak9hkkyXgFLCD8-GL zgFn8YP>8b7>H?-AgLtuW^SFd>-$cZKLry#{mBY?Iwzj_Babqk{Os&Rp8%SNUY#BX3 zK~%*_wsr@jLkvAFt^T<#3DfNK@_0$pQId?D+&r*f*tn55C_Tr1LA3~X(p5^OOZ%2s zNmh0kmscVg(|ME{?{gf%u4Gjc!0#+;DKca!b1{PHxU)bvDafJ>a1nN3uxD zb)s^3Guv^9muPaeNT*plB$imno_$zAjFA#k+xq@4E%k~7@)RA5DOpQHv^TCf zFff>MZ$drOxk7!^{N-p48W=RP0A+sGQ>>X*Az)Kgh=R}7$Utx8XJXPzDH#l{vFh|u zuQdJ?B?nc5+BBm8$P!UbZCV@b#lrgP)zremg1`Y+V&4NtV1GkGin>gZkd!hOEPwLk z36{Z*3lNVIPwBP9fQ(t*ZZeuJ>j*RrTJddc-2@MfOd%9g7ohNLjOBIce(-K>eH~oh zWC=bp<-0(os0BPdmJHe|mJf-a&EOo7=8mDk!opUXZE3=@b?|EY6759^unD3Km+HI$ zA~%q_;|#<>$@qDjG{A3^CHN))mG!@N<!p==uXJjaWvyM_A54I8 ztedwIarV^>uj|K3YOpJFqp{h|buH%VSG3GnymhA78^MHuW8` zG4#pFXhQ;V7lD`onD->+Sqt+*)qdTM6uho`AG$uy{2G;};;e!N;8{+2)|vunxc`4y zwCRUMB5ZtoE%G^1m7U(+-j$Us-Ez7=zC{+kP!9$QRV#otn@dALNccuT07%De zL@(FOhDcKx+;^LfHztZUfimlQ@DqTvV0?MqT3`MgDWw6iU&qHedR^ZudcLKyB2k85 z^lRTvU}24nc4ps@lert@`Gywy92p3bUitQn8+6Ej`wnX29j=g;l!ToBXl!f*h<81M z>Yl$FCPYnJD?KPzrHb4chR@2)Rtq{cwbu;msWhR)R?X%~cd1^3W{x`|Mj&6WRB*MT z)oN!q=@(FAV_gce;}Mc+z01BFuMk@7rldTKrXK+z&~8nz@t|^$pfx>xMazCDycsq2 zTNF~+no=RA*oL@bCTBmHs(+7+b_I<>PWM+=KoaAXgvx0J`K{uvj_C}*_F@^HRs(w+Xz3#yn z@OI$x!wnc*p3}UJfbF!5o&3@$Ueg17BS5$ZMGN@BM&8K718gT&)dZT%*nf$qQabqR z$=;4dYLyR5%d0;Z`bPVbF=e=XA?At+*>XEZ1*%`Q`{}{?v0ZQwD)Fn*7hLD!yb@@! zX5`4Qm2*GaeQQ#O5_9d*+<+Q&W?bEDct3J=5hYq!}n_o}BxE6wtihLc0tLDE>~? zYCnEXc9*Q~e53K74g?;cwIx@9nzKn!z6saNReMb>{zn8~W z3ab|T0_6bq+33$XJ49TuB}zjjErv3R7aiU{Px{co(^Y8k)Ch%ccpc9vi^of4RK_dw zh#|vXpKBM^)C5#iECaD-XO4@q_`Uu9>J{Ko9X4tw@>ec43NCkNspdYt`u=OtnSugQ z>31h~g@-$y{U(;sN<96x=c1n_J$+c^PL}AK1fvX-;4Eq0ME+2F>rymiGmj00BmwKX ze!VEx**x~yIWuCW}*~m8FhqYqCp~wE}$LO-eAqT#epUV5GGew^Y7nZ(W$Y7eRTF| z)|!5vVZn*J1Gvb~&|H+K6sQ>t8r`d4rhR4rEDPWHfYAdmgl7M2mto%0b4AC6$mBGF zxTws|u~rUI(M1M}UDkW44X}`}MNBtg?$FTq+JB^mgn_I?ovQ9xfIa=CXslC<79~9a zE_3}_>wJ`mnv>lSOtTvQ@$MQ3JjQpeqo6|$q%Dxd1fw`XC;AdeL9l=AY8I-wv}$4v zf^a!dI}oU}iZdM6Inb=N`=tOp<$AO=yo4vx;eY6{*SRxUvI`7E4MwT!+!j!pCGYn3 zH}W~nBh4N(O5?RQ48ZX3oj3+$thYi(=}CDO85wlbF||q6B0W87Hb5wVQbC`eXK+il zt+0g$vd`vKt5%4)`Cd8xd`yNBlw6c2Ful6?&`HEjJ?8^Ed2GWA_0bvR}kt`Uc)|%{p5MtWoUnVWBJzRT2a+cA{>! zDgd;6NgvL=1uY!IVrb$5oTB0C24I$n*>H4u{|GXMFc;udgG5}&H{+hDLuBKym5{;HW>G$(&l?id%v9wEi9;Obo3{m z1EbGC>Sf&ht%a6)8$D?qL1kqMxvybu3M4dj);biyStzp6ACg8#uYpw}SQpUy{yY@9 zRJF6KjNN!Uh3pFX&PHq3uCI-&ZT%#cR@#D9uk%sR~_wy!o%UENT z!{%4eoRe7hO%|HR1E1!(!+=>S>lvU7FTR3Z=_PuMZ`68Q4ni2^3M+41O;w`1F_&uG zGxQTzSzm;ju4esDXHiIbEMspFM*jH9eWrBuZB7V59NuPXXw%ON$%)kkNPs*$)bU3_ z>^RWb5K%U$xU1-Jc6>-_9n<_+$Z6^5{D7J)X>V)$xa6dlVcn-p%GSoFP;*95u0kfK z_QzNrizI7rT=b2y3491fM#51|9)3w*zu@n;2+E3 zwXBB5*6J!CfUAMAXKZZj)2C0MTbe|K{dApB$c)r2+nA{y%%NAOtum~Xk(>Qo*}67n z(DD}aoWI2_6BIWY3(KJtuXdhvO&U%wK8ec@EpNr&ZoY^={?MQTMB87p^+)~@(uk=NBBT3UB zXX6GfPBk9qVxrzMIaxmvjW|c^+YdIEIA%}jdya2 zOtk8Yc=f8AFN+6vkL55Sv`F%GgAyGS9!O8J6K&o6=!qCShYfq9r>5j*m&X!rZZn`V z1N8YLUcj{JPe>1fkS_db+vL$hyDs?3$}V6hatH2>;@)Y> zI*m1{kVPQ;9d68j`$m+Sy2EM)9WUNy0wvVzLe}(ZL%&wO_4*2Xb9;MnYwMNinBDOX zVN9X(rjnHXLGa;59e^Y(W~&wEs_RzofAO+v+b*_CnW8IhuC8+Gw5J1@fmtmQ1d#Ff zcMDm8lb;2nsc#m^6$dQRk7QvyKHibe&f)R#bs#A%i9O5JxT}Z??tht+(t||ig(1br z@L}ntq{9du{EmXz)o!-e)iNC4FHQ*;7k~39t6SnHnzf;pQz)>_| z@qK>3b6$JrLJbdhDBSdW0c*N*1FlcHFe#7F6BwL_el`Q|z1bR1UY3cf73-)e*e5WI zW!aj^E8SOSP+pl}z<;KmEAK7U2BJ9XgU5la#M*#GCu2FWSRE^ka1Yk+s1E=Go6EC` z%HeM!0Z()tkT-O~yf@&upx{uLJ2;yLbSH4KK(nRp52P}DF)jN34QGIyQ`7mOfX(8! zgkc`Uqqw)G98{%g+8re=sZL-FtE##wl;Z}?k1UoT@n;YA;rdc})G}tb{&w-hy2jTC zN@b?%4ZuyTLS2VymI*Az>d;3okEAVc4BGOdx3y3}=Tpbbru)M@fG)O34CgGVUU_)Qln@=IOS$5JlWQ(K$CbUXyNL@r6K7EmNm#0TROdCU2$ zNndNyiVn{L^e~&~+nsB8x*e8jgFbW~7pM=twA!nj==2=-)g)rWr_WQWt`nV_CWVO_^q5zNuhq z%N%&D#7*#e+<&ztZyF^e z!Rpd_oc<66v8I6dAwfF%IXAOzx8!uIZhHC zk_z3bhv3vppepT*XMP-Y)`7ZJC>~Q*jXvFUafAX5{UR4Xy8H3Y`UWXxdOeI3GUj@i6to=Gd)Hm4s|nWktEvK;VM zlmEDG`KvIS$&#SvTSC7y8sBs=N`MN!b%Y%OTOI^B&{tPSQhfhyk;|oPZyY;2VgusQ z^=zLiUD`c>YXWdVf&I zVY(8kq;x$nEs6B#fTHYVY^=7lbfQS@w90&ab5T}U&d#PR-)^m%$JJh?(s%@TxX3Lc zVoN#AFe_5?6vM(;RlRHd07+?9+glBsUP0R@d&}LSc;nb5kUSc)@gVUNsR(#^=wQj> zL=kaCXpk8=ZL&LA(!1MY6vP+Pay?HsBh@TpQ9Fl$_kwXY)c)e5prXa}@5qvp_$|3R zmGE}`aG4EDxdQISb|7>94bpPETEt2-!MQ`74GOtsfB8DQ+J)xJrr==GP$rWEfqcc@ zMAL!Z8A_KZ9>9X3td7k--4Upp7XOP$?Ofi6WGp=&pEnY++-2lm{{G@BiB?fc?o7U; z{5&kH>Lec=oxuO^IIS#ayc@<@uk{({d;!l@ps*KnwVs3FDd>+k&`yy4w8^m z=pcHmRa`~0T5-v~4i+HE{^{vR%v8?UF0eqCNK%#A#osM-Z345NlC^O;d13*RtLW1b zFb++DG4v>SWo06-Y0Y_3k?&({(|k$!4l*}MLV=nB&`B&nLE;SR#|A8{bjdjZAIVi`*mxn?X+R}o zMP_p4FU^!DErNf#`~4#AmUKsp_|cr2tHVjh?17XS;9-ox-DKgsnOQ*P3+E#`Ihv8( zK=kL*wmceHR>HlZQ*Iy;Xd;Xu!T^thR9sdrXS4v!iS}J zKmeyie~_my3``qHRpRX|jfDkaa~Q8gi7a4ODR z`4?N6OuLg$Es9TW6(|y@M6(65nPTuYH?Hz)53Yl}pXHW61U7@;2|aQOU0?IMR0a%&pcdGzhCHFQ%2@UBp=Hx~P=tw&{;Quo?IXU-4#AFl!IyPgI1w79 zzTdy|k5880m-ox}R;4Kx{4)DouE`GzN>?RacCjY$Q>DmlcpH4OdIuT`-YcGNp+qur z=(TZvhNFBnZaMJ>G9h^j_l_|%rvZPIUHO0qhX5OK-1uZ%Bn+siK|7M{%(t51O{+IA z`(h_OAdY`M@CD1_-qzN(@kgb996Xx=?x(eaChrIHdWjH+6q7vFrRDFET|R{{-ACbO zDlx|_0NeB}nVY%bGI$-uZNx^^WqrlCv$SG?^{~kf_2>9_xK!8OhztMMXt0iQ49?B{EC3Qx634paI;Nla1<+Fjkh{eBq~`79&4l?GZ(azj1AnYieO+|dOW~>G=L$UJM_+em>zLh+%)Pw45D^17 z9X1X&CjnirZl5JmXS;$_v_q-8J_2!WZ`#=SAEf1-5c=<=B1No!PWa^~8%p7QMfC*-aeyT^5BM1PE)Sj>fd5dS4h+8ck+Hb# z3%UD>H5-6?I}769p%ABA#X2jlSP1-Ni{J2>Yy2BayDPX3;V%2lkJ~c>nR7qIi7k`7 z`N<8m#*P;D&%Idt%6ecK9*n%9h^L=$xSha!?}Js4S&=nhoMljuc6%as-HGZ87;e7P zAJKw>f@s8qVqZEtfgCT6wD*Avew`X;XB-ifRB)XRvAba%4eQSG0^DHo)NIxEsK?+4 zJsY>s*iq@J-7ZS7ZNK;_xp*f6!SD&Y=rd-v`g;65~oe|6zo$t(i*Ebt$h z#CQSw(K-^RF17d*Blv@l0CJb-4WP>K1N8(v_#>MCPOFt%&>xr#CHsQUfMCe|e- zCG%&vs!qSpb?6PcCw~xy&`=(II0rrupbQXkQqyaslWv3K#GjHp5EYOSV9Gr<4D0R97u zcG<|-*p=<=%LUnXo0DHU`1r{;uCN~9N=g2w>)t)kG%hTExC-YSb@Ij*4CWUy?OI?l zUEbLE62Bi6%I)PTd}F1T%lHB8zQ|Y--#3S)6}(b7i{0yd^zmuc9{>ry_?G8>fqQFm ziYReWpX~{ z;5>oLIwU^TWffNp9O9aULOCfYgl(tX_d2mHpp}sraWVaimbvenL7ID|S${3Ld>t-! z6RwAU61wZE9h`FN!#1^gO(XnU{4^>EIPgFvBD#IFE~2|fJMvki&-6kH&vL?vo;5V@ z%GU;Z^YfsLZ-jH1-|IF>g3CE(1JgXu@_oQKuC@S2uvcDx*44927s0a2rDgD&|(w1ktp(LD)C4_n1&OI zk6=)pOuBytqaLsyJwUZQn$jx*e(G12v%!U{0QgQ8tT}Efg=Jlqb6UTX1O{2)O9eFS zbHE-P`Osk&x~w2X(`(JL8p}wl{TTt3E;HJFt*d?#MJ>iiB5*v zfn$m%^>NxBMyo$dr6Arou;Sm61(SIMdA|@y81}gQkaWhZ%(17MBm7Y|X&M}wI$P#$ z4B+bO_;?|EZT_)a?=v7LhMRO77XYCBUQz3LMi+T0;kQ`E7PT!QX(9jWhkaD7=d|XK zdXic(U9thcCJ zSfsmCQbIsVQb1a|OBzH%LPENc?t17F=>`euMx>-cB&54}KsvsS9zExMzj5yv_a9*V zc=q0F%{Av-Yh~HGF77(E_y;~ecBQ3d&ihkmDb*QvUNYsWKW_c}S)6GBl;&pIVGjSP z<5C_5yiF4IJwBap1Sa6wxll!&YcBjul=T8+UxQ$a%e~NdpzGuV~m3IC|jn^Bjx##yrfn{U!vEY9^8|Q3# z>ScvA7-t*VNdVP`CJHX`Ai0|3W&=jp(d1Mi_G~(VId!`AHkK19XDBjiQay!4wH?;a zrp8M~R)^ccY_m?yhB$||G9IaO*)F$`!=zZ<@p>eKL`8MEqeHvaVs)}Im-Ppoc_^NQ0t#{-kcTon z*t0(#MAz1K_r|6M*uhJaeBHz4+zoIE2cL%$Gg-D0k6@Q;yCNs z??C(=^1r7CT0s%hp2kdn5Yc<_3c`aV{SQ%MHY*yTTW6bfmM;4C`{tMqh_859!~Pa` z4R$3;q?E?qxEa?SHA?EV(U zA}0CtUJBD4F|Cg;eb2DsNo8~XHK7D>AN+i<`7!R8cOEB%CO&hXX-Ao$^FH~9JEgD6d9L5HLr;V0s|m(w zpPhv8gfL*Ff906xi_i{0UiA`-dux?W6|JG#%-_tlx4-x7zCKnB<-YkO>bu!Zfosl| z5?5UZoCuoQy5g`Qr2B{qC3*P;eP+0Iagc_=osYn8EKfkWXg! zp7fvt4rdC96hY6Yp3BbrH)rF8Kv?e|#6*yr8j@ta5Sm%RGa+%=NM+(jxSa^gy;+1;62jNx%%vQv?=FR|g(EdK# zCBCl9hh=FJ5cyQ@S6ruC6EXOsPfJ~ozQnnl{x}>L1y zSCinBX5&ZM;$=jd;E_=U7yBkiN)YcYvOy|Mk~OEE`=kC1VT z*uNlVvhbUn?CEiNc^Jpi>5q$#D|dKKMUrJmzrWytysQ(-;h3kRy=dwYY9r^jlE19c zlXi0ADn!(DyDA8Pd>qe%W!;fpD8{!0Z)0|rQy>0h=bS>XYTV=&4=2spDrcaWVEXg3 zSIVyklW}!aROGyWDs+Dt%sbwhs=7U2&zRJAA5enzRMiTN-wJT>k zw-p76r$LkF+JI~T#7=y^{!Lg#MR`bmT+9wIWz_=)$os}MwqYk3$%;g7>l<@;-&EV_ zT(h66E4u(DKwY`N%au&F!ME=z4nchIT~sh;99hVTpsxvfxu5)6?i7J)R}XN??#CM+%|`AX zWf)<|m`0f~XlD)%GKActk`?$ex}=YDqM({lz_k-r2R&S-o{IhHyhmzlZ;wyznd_O; z1B%j_Puun+;n#=VV2~O*-qv{D6N`FSG3L{MZqGJ-fLK_ByB1Yzh~yMbCeDxPt5nWyK z=A)mBP30ROWuTd`dJbzJUmpU+pCPchI7>eKyjSYi^}rXR=F~IWIQX!Qt(Olhvs6vt zU#dZlcKGyafAiUi=JwBRLV8x5vIRMZrVvzyN`R?^u9OCaGLkqy5x5zTE~ByEaS?y+ zl~WC4lTg98EBoxL%MknZ$Xsl0J^i(>#MA&+@u1yFxe{(RYC+{GF%mj@eDc6sjD}@oj*O${f&UhJ z>i)svnW9j-G;AjD)<~adeYkiYkZt2#2;3ybP-)P0Asuwc`6bozblZx75OLin-DBptvz*R zy{-(Cl+jA`u^C%%De~<51pLQ!Gh{6mXtnfIvJQ}o`pMTLLP>^mLI{800-AFKydV#B zj}T>6hLna#=~1?9FRZOf$vk$BM9c@@YJrfwMQ`Yo7yF23%(Eaz!3ZhvQcMPwD303( zb3X@Fg?rZghs_N7N-=(z;Lb>Pu22X+psv9aSM?UGN=?UeldXE_)_S$N&0L)JWsqb6^qd8WJ;%Uj(~NlD7;kWtR@IK zx0~3ws0vms8bx1U&aP&QhD56QbZ+~%t(fL7AH}ZtWm4y`Xzls zt~T>IGF-CKwK?G+pMpMba=0~Lf5EJvp}lH!u6)1_&h(A|G_UyqT44GnCuOe`GV2UM zllh3L3~@_0&67&chmEYDYh$)9+LKT2^0YjUUpGO&%CrRx2>@YIU(fWT(j9h8xqI{} z7-)384-)#w3e0gU$!HZ+n*e>BsuDO4Co7ba5DaTN*2XN;`M>b|0BxAm6lb#yoN za7%L@g=cuMS8Z)^O%6J-;Snw-OUxw^u|lrL;-4obt*p?-xm+CzbNeU*A=!DJY$)Nq zP-`dXOaC0AmXN!TQ}eKtwy7^iKD@r~_xneA4Y%)oNNcf&()HY+dFe4(gy?U@!Po5K z(>?hxV;(A&@f+{JO7&hrea1_B`pSSxp^|oPnya%w^uadH~mzZ==GIXA(um>_8u0_B-6~guQ9)WjU{NzVSc?e z{qspCZRICv{R8~43vR%7zQ}hmIKx@iQyEWbjI;?n6hv~IQbXU#_j4UcB^-F~!d-J0 z|KU;7MMqS$3PfGV$PT1Y7CLS-niU+Nlzz)io39E5t z@(x66O|1!A=A#X1;N05repmesXfV^=NyXuu!#wf11-24*?$fNbGNrA`u(&gLPRC@b zLH!?)rc}Cwjw}vLMFtMLm8ue@?|YZ~iaS4a+*r&md}FF#FrQMBTc8UCJ=CGU>?Cf~u! z(BcpNOmbA8%`@-_WyXkHswdO7U;{*Sj*i~^5V?L3tEiz znHQDc{(8H31O((4-Y0|bWks*tudd5Rxsb|Dq-i5J)`k5)Z}I`#L{*U zMtA$@It|Q*u^iHOKlz%*wY|f^Vb~EolAU3K=YJrcOl+$$t?4I(Ejm2n_hy1$=__9R zBAB5CC*ts-GfY^dBKkvyA0P$C$=DWd5ET^M`HxodJ!k|>tu1Okr5vz5%|yDik4H*5J~d$ zs<1HJbFM&g@sX@C%8KZ0o8ss!nW%-%ZI8$tEG-3v_rMKASZTh6DYWA1R`c-jEDVJ= zDHykRPcOH)gX4i218#Jc#4AEvrUW$h}(u?IY`L{jvZYH*7# zbwdnI77a|SJcTUeQ3GZ+_&kp8QSz4fhYy-kYI(|cobM}>yZ`TIU+Ig}P~zD;_s>19 zm~YuX4E2}f-J&YpH(+|D?8PpiTOj@hUqx*bTYQ)Q@W5id-ik-+2D<8fbab@weI#F& z&;TbV4=9*RIo?kYfnvSXB#(lG0FJ0w1 zjD9|oNpFI}^R4Y&BM#r+&jm6e7F?m89Q2`*5)%#M*j**EmCp*S z6SHG*5|2glfs6xF5_}Fbk?rgHy3;DT+K=hCXOWnN#Rsm_$)r(+woC?;ugw2`PO0QL zng2{C634%vgGZ`=mwTqgg9v?mUr{Na+S~Py!fHghaDV8*cMnmxVWh~ z^?aTk@>+r27KL(OC(YYjC30k)Wnn#jNhLY|f=Zmj{j(T7iGO)5A~Bgj&x>Z*F1aW6 zE_W9n3xP}@4ka|;dDl=cv#hfM(V@gz+QyZpOF*^C*Xz+-SZYZ@5Tkb2*Pl3;DK;dk zD=Qa8DW;a`%?u^uw%b_1n>VDYsf?B^yaY1I&@>P~fn7GH1%jd*(fh6YqRr8`syogh$QI---pD(3lGeMKSB( zP*uEaclr4a5K2K(uV!j!Dh2Q-n(S6>m%l_5+@~oj4ol^-FDZE@Wp{Ngu&H%(p>a~- zylBB@yOVKy_3>GL$(x|m)GFhrtS-|4%s+yUB;oQmR;h|-;pXII<8|eh_KW!%y9Vf~ z-HBojPg$&KI!b%z*y7QK02~> zvSyhqDP!52C_efik{J@h5k)p5ER(lrx5flgkunw4#A-rW4tCzNB;aP2NoJ-q%~ER9+yto zvEJuUD!~P>#SU^wNyIGMH979yCdci%X3y9q;JveGxpv~GNGUI45p-k}pf&Mo^=e=K z5|Bz^iwOQ9dS-@BLa7Ml2F+}k)5=OR78ZrC%A)=VNUW+!=HqJFpO|l{z!`q-d)fAb zXrk-ZnLgY2+f{Qr>w2{tf?R-xlo-ZJXMTy`E63j_DCGv{t4SRDPxyRwL%0`1y)7mN zdwunc&!Ireos*hcMCA;(!YN6M6q7zWUTiTO3^zQx*k*3R@D6rM-b(3^<5fcbO#X_9 z&F#2KB8ol4auQ`}IltHb0|ZP>ikhrO?nr2xkz=b0Q1V|j%aBFI%%>-2Rr@&GOu)^2 z6Rj=jG8gEaJU!yID=I(zeIuW<+f0@Nd3V>q3(4jqo2r8TTv1OCwnvNc6CqM~@t}e; z-g=Ww=EPRvN!y_6QIb7a1pnufiUr(qN5w@7!@}HXU_eSMYDiL2NY4C^di&A##h9^t z4%*JjHJYQX32G;&2v+?PEnkmsC6h^52N4e>spL^W{|zn}6aG|rEDr-pYtp0DhOodiIM)8isIARN@Rz2jHe|DC6ot{=^6Fa;_2P`>!E)4ZB@@;h*dU!xM5 zzHhfQupyx!ue5HmB|sT_kW>wtrDB=_qz9enR}U=mUU3dnYiQQ9hiY*jgM_#hR6sqB zX9{Jrkch%bDS}hg22p<(*G4vb94F4AEeDk+emX_=G5D$3ir$RU9_1eLerr#W*G@9R z_1DP!!R;u2qbk@<>QL>S3DY4LsE|IL&Y#%7uG51lDKbJOah=9O5oxbWf>16h6r`l( zYWp?G(708}MP4pV8X85R`18b?3~z+XQn2!v2u3$ zUSs2?1Ee9oqg}p(3+;;M7Y$-QZ{Mm?J$m@?>sS^36sKb^q;O;emk8Fs1{pmXk0o{} z4pUwxuV|cGI+aiAApl(jM7EM!0t9x)R`@EP$$d2crYdD({hAB~s~9%lXXihiywcpE zQeG@FH;VF)WbybasF0KV+SB?vJGq3s2bx^V#ioD!FuA??q~?=xHsT6qy(3CQdLRe} zNG}g(3b+Q0j+P`aXHfD27mtsqiptvKf#EY`eU(ur7t|Cs!<)6#QkfJ9`G-9d8#5ro zWZKpl*LkE!%d0a+@Sx?*uPhp{*OLieZKkEAOw}DQb>M{0VMzbnQd6=(wo6?lB&QIP zpA&Ui22pQe_Xi1QcGj0dx$sqdeYLo)<*__~k?hy5$j_95$XPi33T?@6wwN5sSMzXi za7^zSOr;H)lIF9zmU(OlP*TfsPT%8{Oy!)9X>G6v(6VV5)<5xA?AaD^=?%XY_1`tv zWbDab_YUJLe89voxeGGpt5IR?UPj9XLysi#f=UWFv(3kgZgO7(r=C#q_JiB9`bkaDYrv$o1;$7R<~ zU{v1r#s-`1%Tr$ahZv-qlI*M4v~`)u$z0xua}AF5&7Qb8)Pp@zlvLbV_b5c%+I#Gw)QOe@reUyW%Dpd@MQX?syE3XoBR9qCbAD1VsG?Pgkp??@nS#M zSV>=BI;)OyTHuJ3Nrd^DbL6zw0BG^+0OZYxn420J>a;i{q2Bh3T5&Q;tz?i&0lY<6 zOGrh6@aS=ec?;yQrDbo$UO3Tm3QUDzDJ3 z$M97BIS3`RV)z4TyrCNh@)|0Ftm2xyaBEFJFW4D6aFU8Y&Jtxoz;)G%938-^@m^H# zdBBWbS4?#Gi??`MCJPZ^JGfxe(-Yv}3*{4JHW${svvDmhB}q)I?Hd?y{ki3OB}w9g z^Cimr{Sd&AB1Bs4X4uEDOZkY~H}m^57GP&O_7swR&_zfS5EEGd3o0SP=cr_T+) z()A@OAM9PaR{mgF7Zh~L>&!xEx3fbMYZvDus;`ISDaRr~vG83{ z6BS3HvUzz$adez=Yt6S5e*2p6NAml^)J9PTFZ#@1Tzi*OsDgPaC z%gPT1VL{d87j6?baWPN53cW%;-K@7k&9F_hUwWPbAXN^QR8~8gtG2+f{c4{ff8&>0 z8^R}#UM;E0MXDr)4E>w5bM4GtY804{)7&>oI)JVw%j7Z;)3r*twxtV&jo=jIJu5Yi zDm-8oVPNKzmTXHeG4F&UjmWYNe5M+F5DIQzkxsUAC~L;Sgoe)j`%N|0dV*$3^b?Dz zWuvZK9ci_Ox_KYr&I_6O0t;x6u4o^Kf4>RPc>5ba*o`N1OlhOND4h9?20U6YSntDk ziDoUW-??dm;|m|dIL|)B8HtEwrubFlY%n~0A<_NsC7EOOXg#l7G)8xJag=upG3dNr z8|ct$d@Itb))?q3{|uud0$x(pR$UI z5hHHKl05*Z=E=tRYKtLd`U0;!_VEWEMjd8CU1bI@FFfFqO^YrM5(wUjg z^dYk(nIp%_7u2CLJ4cTISro^|O{!3cd9qw8;>8KN#YCTLcjRdS#=HY$SNuT68K z++qZ7LR;Fjoe@&T!nRMnF*DMPkT<^bUYdig%gXVlT<^#GjRbzQ0S)jc`vx=FK`%WY z{4Hii6rMj%0)+~p{)XbDLlznEvG|^ynO{+@2}^3+*V3V5wNW=-LDJXiIiJ5llKTG9 zu)>i^WAW@zjVOZO;lMW~=kn7=_6w%hj9SRrv20(Qw!bZIm)9QfT~S>TCSzsNdFRKy zz=^%l#Amd~%=B5oF)Jn#xX@aha_pSPJ5Z+Z`fh!3tl_#kz1kD=)7Hns{_^T70oKCm_BJ`eH_%RMS@Si^I(n7@(&)x1 zkEh1H?dM|&AOP5O0}p=(0($9(@2~R8=)glCkbn8206NxCkT-!=MPo0AlS0+xAt71F zImgz^wtjm2M*N#jP|AG$(W$&@aut%S(r8?M{7xp)YX=!-5y;fnG`;2kJiL;iQ82|C z%#sxUR`S%55zJq?x7GyhG_+m@=?^2BU*n^B(eRsWQ>EpA*NKmjWD82&2MEQbWWy|f zTu4J-vQI2Ns2_D@=;(_{Wbn{oWl?om_NQgbubCz4ctlf1o+O))?NH^vo6(B0(1|%8 zChR6(Zt85~Y0wS*PLKA>K5S7*jm@aWd@xr5 zY_`$W&yeh54AW*AuXosdXG|0c#>i0<6L2;FCEp zoh10a;OY+`Ho0YuKD)6N23j5UPx9YINYQEVjeR^eVL#0m2m5xIB1*@v}$m& z5_&zjFO-T-al<(^r^|lzIAAC06`ogIRoZGeh5)sio`uD1G!+?({ycv@3>) z=Go?0GN}9$6Zau#-t(@j@gfk01Xf)lVz7#6Z%>rs3Be2Y@Y=b#QrP!0fE?Mb%X-^Lr@Y{uE-#Y;ZzF;$ckv6PU8O^2+L9Q{QR=4wWhOEZYapFDbucM9 z&#s=c8i`sSP|pCN(zQL_cw~#`xpD<=&wKV&lU`fGmkppNM?Na`*?BIPB>__Z_$xFm z

f9pFXN}2->Zq<;c?8CCwtW4>{8bS=o=?5f3M2W~~jllZ`5wgNngqu-^||-^ec! zk0pX9yycV9c0eQA1)E1ZrNoeC*vmGu!c)zjky>>rq8iDwNBMXSmpwpTUBRym@fGUffPw=Tu5}llud@vx6UvFyrg3qZ3}f@>l}{%-`RD zu8KYPp+kb&Gi$Ls4u4Qub2I#$2S56=PS|k!+bWIycmb7M?@SHt&;5CM>DX2g&h}JB z9>w<<=;(3^?+4Nn3waFj&Fhz;?5mRxS)1yf0=|ih!S!GvUuq4c*4^oPG2qVSX&0>w zMx1>Cm23DY$NZ(~=QmAIyq`G?rUkJ|r(j$G`LDL2C&K0D*()f2{YGNy3^t^ zfFWbYj3A=4oiv1|pZpL4=;#KYIlX}uU=SeG8|8b}G*oY258cM!llRoGM(2u-k0-?$ zZJ(dV4YhN!F3ahir%YLpkJo^gH~7uvtX%rCp&TfF<=8SqJLWx(@S(=n<*ft) zH)jSLupYJ%AEsKpYrzqq6JbI3z4xuh@^WR8wZmaR*=cG_^ISZ_{_Wc=On3>2NX=$9 z@^RSe27r?w6)0+a@P+iyMr^e>0DGTjyhy?MzHt7a&vLX_wSm(jX+oP7J{0%{a>2x~ z1Jxh@^D#dC62Sa5D);@vJ6bCiujM38LO@Uz(5vH;f2cqJDSwfoWE%&+iD<9LWfg0Z zPikxtknUGzDT-2o!ujcXMmJhg%zVZsXmp%kzP9%DIn~uYeS(OxxGdS!u3f^eF3G-= zOG?a}Wu-G29Q^SPl-1iqyc`xg-sj1aC3Pap1jq)8H~9HpY1er83YJ(DsjqwMG;3@2 zLa5+ex76HZ`mVgLeY+!2H5h}2M##PYg{&#IR;AlRBmP;Ns3PfmBx(cW;@?)*;>ScQik(eTOZ{}2RvX_?IjAteKa~d zn%ek{^yNtO3Xha(z$dM|Jf_ zGBTiT>bbo?AH?u5Xm`dkp)@!oS*k<$!x+G&*FlFj*Ou%L@^S4YXyAp^45<^6qW6u1XHgM91g-URu{##0f+8d2aiwzyQ74s2^x>1P`X>c_UK z-bE>pkqn0ws+kx%HL$a(OLP`L^)OF0@n!-*UJd4fa=WF93>0Ya5ddfzNolIG9oYh862|whthE~Y zp@iM92Og9>x)tEiu2-@#bh( z;+_K4vvONUHODf&$CRk5GJz(M)YOs(e1OU{>;BpacvK7czbEM<9cwu%i|gD3KSmGa z1Y44>=T1`E?}@Ro*EXj@OV-frbDtOm#tbknay@xVmtB$rODgn!Yxf5qeUHuF?0hW` z8s>hL{kkWs380SHxUyHV{Pj`xF*OJ6ZglOe=a_Q%HBjYqkx+-gVDq_~3rp-Ap$mEv zj7K6*Vwr?k!-Symy2=%aC9E((&b!lIr+Y$7_d38?W_x1xf+b*pg0(FZ52Nc{_UrgD z?vI>VSk0IuOaAPP!N9=T)?s;RPe^Z2lcnS#v$HOaUKmXkoC5Q_pa%PnC`dArki|@! zq>Y&C6>b}acbvL$Dj<0IARu^t?(b)&Y(p*MVJZP5aBo}Uowc=fx4$Vu){$t9{v09j zMghB|u%b*m0&7#I47$Eb9cLyncw(b3X<`gVDJ)$;e(oV?B*-d*o9%zW6jUw&HzEQg zEapFNO9tWf6SLjzNZHOs^$oiFG6wF9+2lfIB#vj%2!4@;mA^zlfFq4>EseV4kcjjf zNMNxdwJ~ymcjQs)_*Dh?J`LuqwNkkWU>}S z$gU8GwW~syXq!-!G<(TtOEFUPOq&JJQUxldDq0s_f!s##B zg?N`JOVIv6r)Y9IdE?vT;OV{Sz6!a#|GSD9u!h_VqjS@(R%LAOjvr?f>D!qfRCI zGHh?%_0ewqFXJBv?e37wx9ELdF=+7!#;h}_`*^4A)2H#q%Cp=2;Ip=w |3tw^zH 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 z�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 J-P3vg{{V|wMWFxy literal 141773 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%0ALv#igQ8NZ|3?qHU^qD?G%J=d~i5NG+tY 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

pY19!`Gaxytl%FiSo0r1}x?B$#Xwa2HWdQ5vi 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 diff --git a/filterer/etc/filterer.urm.puml b/filterer/etc/filterer.urm.puml index 24060b6aa..c0bb0b54d 100644 --- a/filterer/etc/filterer.urm.puml +++ b/filterer/etc/filterer.urm.puml @@ -4,129 +4,93 @@ package com.iluwatar.filterer.domain { + by(Predicate) : G {abstract} } } -package com.iluwatar.filterer.issue { - interface Issue { - + endOffset() : int {abstract} - + startOffset() : int {abstract} - + type() : IssueType {abstract} +package com.iluwatar.filterer { + class App { + - LOGGER : Logger {static} + + App() + - filteringSimpleProbableThreats() {static} + - filteringSimpleThreats() {static} + + main(args : String[]) {static} } - interface IssueAwareText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - + text() : String {abstract} +} +package com.iluwatar.filterer.threat { + interface ProbabilisticThreatAwareSystem { + + filtered() : Filterer {abstract} + + threats() : List {abstract} } - class IssuePosition { - - endOffset : int - - startOffset : int - - IssuePosition(startOffset : int, endOffset : int) - ~ endOffset() : int - + equals(o : Object) : boolean - + hashCode() : int - + of(startOffset : int, endOffset : int) : IssuePosition {static} - ~ startOffset() : int - } - ~enum IssueType { - + GRAMMAR {static} - + SPELLING {static} - + valueOf(name : String) : IssueType {static} - + values() : IssueType[] {static} - } - interface IssueWiseText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - + text() : String {abstract} - } - interface ProbabilisticIssueAwareText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - } - interface ProbabilisticIssueWiseText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - } - interface ProbableIssue { + interface ProbableThreat { + probability() : double {abstract} } - class SimpleIssue { - - issuePosition : IssuePosition - - issueType : IssueType - ~ SimpleIssue(issuePosition : IssuePosition, issueType : IssueType) - + endOffset() : int + class SimpleProbabilisticThreatAwareSystem { + - systemId : String + - threats : ImmutableList + + SimpleProbabilisticThreatAwareSystem(systemId : String, threats : List) + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ProbabilisticThreatAwareSystem + - filteredItems(predicate : Predicate) : List + hashCode() : int - + startOffset() : int - + type() : IssueType + + systemId() : String + + threats() : List + + toString() : String } - class SimpleIssueAwareText { - - issues : ImmutableList - - text : String - ~ SimpleIssueAwareText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : IssueAwareText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleIssueWiseText { - - issues : ImmutableList - - text : String - + SimpleIssueWiseText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : IssueWiseText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleProbabilisticIssueAwareText { - - issues : ImmutableList - - text : String - ~ SimpleProbabilisticIssueAwareText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : ProbabilisticIssueAwareText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleProbabilisticIssueWiseText { - - issues : ImmutableList - - text : String - + SimpleProbabilisticIssueWiseText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : ProbabilisticIssueWiseText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleProbableIssue { + class SimpleProbableThreat { - probability : double - ~ SimpleProbableIssue(issuePosition : IssuePosition, issueType : IssueType, probability : double) + + SimpleProbableThreat(name : String, id : int, threatType : ThreatType, probability : double) + equals(o : Object) : boolean + hashCode() : int + probability() : double + + toString() : String + } + class SimpleThreat { + - id : int + - name : String + - threatType : ThreatType + + SimpleThreat(threatType : ThreatType, id : int, name : String) + + id() : int + + name() : String + + toString() : String + + type() : ThreatType + } + class SimpleThreatAwareSystem { + - issues : ImmutableList + - systemId : String + + SimpleThreatAwareSystem(systemId : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ThreatAwareSystem + - filteredItems(predicate : Predicate) : List + + hashCode() : int + + systemId() : String + + threats() : List + + toString() : String + } + interface Threat { + + id() : int {abstract} + + name() : String {abstract} + + type() : ThreatType {abstract} + } + interface ThreatAwareSystem { + + filtered() : Filterer {abstract} + + systemId() : String {abstract} + + threats() : List {abstract} + } + enum ThreatType { + + ROOTKIT {static} + + TROJAN {static} + + WORM {static} + + valueOf(name : String) : ThreatType {static} + + values() : ThreatType[] {static} } } -SimpleIssueWiseText --> "-issues" Issue -SimpleProbabilisticIssueAwareText --> "-issues" ProbableIssue -SimpleIssue --> "-issueType" IssueType -SimpleIssueAwareText --> "-issues" Issue -SimpleProbabilisticIssueWiseText --> "-issues" ProbableIssue -SimpleIssue --> "-issuePosition" IssuePosition -ProbabilisticIssueAwareText --|> IssueAwareText -ProbabilisticIssueWiseText --|> IssueWiseText -ProbableIssue --|> Issue -SimpleIssue ..|> Issue -SimpleIssueAwareText ..|> IssueAwareText -SimpleIssueWiseText ..|> IssueWiseText -SimpleProbabilisticIssueAwareText ..|> ProbabilisticIssueAwareText -SimpleProbabilisticIssueWiseText ..|> ProbabilisticIssueWiseText -SimpleProbableIssue ..|> ProbableIssue -SimpleProbableIssue --|> SimpleIssue +SimpleThreatAwareSystem --> "-issues" Threat +SimpleThreat --> "-threatType" ThreatType +SimpleProbabilisticThreatAwareSystem --> "-threats" ProbableThreat +ProbabilisticThreatAwareSystem --|> ThreatAwareSystem +ProbableThreat --|> Threat +SimpleProbabilisticThreatAwareSystem ..|> ProbabilisticThreatAwareSystem +SimpleProbableThreat ..|> ProbableThreat +SimpleProbableThreat --|> SimpleThreat +SimpleThreat ..|> Threat +SimpleThreatAwareSystem ..|> ThreatAwareSystem @enduml \ No newline at end of file diff --git a/filterer/pom.xml b/filterer/pom.xml index 24dae571e..4477332ae 100644 --- a/filterer/pom.xml +++ b/filterer/pom.xml @@ -39,37 +39,34 @@ com.google.guava guava - 29.0-jre org.junit.jupiter junit-jupiter-api - 5.6.2 test org.junit.jupiter junit-jupiter-engine - 5.6.2 - test - - - org.assertj - assertj-core - 3.16.1 test - - maven-surefire-plugin - 2.22.2 - - - maven-failsafe-plugin - 2.22.2 + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.filterer.App + + + + + diff --git a/filterer/src/main/java/com/iluwatar/filterer/App.java b/filterer/src/main/java/com/iluwatar/filterer/App.java new file mode 100644 index 000000000..97ed24837 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/App.java @@ -0,0 +1,111 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer; + +import com.iluwatar.filterer.threat.ProbabilisticThreatAwareSystem; +import com.iluwatar.filterer.threat.ProbableThreat; +import com.iluwatar.filterer.threat.SimpleProbabilisticThreatAwareSystem; +import com.iluwatar.filterer.threat.SimpleProbableThreat; +import com.iluwatar.filterer.threat.SimpleThreat; +import com.iluwatar.filterer.threat.SimpleThreatAwareSystem; +import com.iluwatar.filterer.threat.Threat; +import com.iluwatar.filterer.threat.ThreatAwareSystem; +import com.iluwatar.filterer.threat.ThreatType; + +import java.util.List; +import java.util.function.Predicate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This demo class represent how {@link com.iluwatar.filterer.domain.Filterer} pattern is used to + * filter container-like objects to return filtered versions of themselves. The container like + * objects are systems that are aware of threats that they can be vulnerable to. We would like + * to have a way to create copy of different system objects but with filtered threats. + * The thing is to keep it simple if we add new subtype of {@link Threat} + * (for example {@link ProbableThreat}) - we still need to be able to filter by it's properties. + */ +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + public static void main(String[] args) { + filteringSimpleThreats(); + filteringSimpleProbableThreats(); + } + + /** + * Demonstrates how to filter {@link com.iluwatar.filterer.threat.ProbabilisticThreatAwareSystem} + * based on probability property. The @{@link com.iluwatar.filterer.domain.Filterer#by(Predicate)} + * method is able to use {@link com.iluwatar.filterer.threat.ProbableThreat} + * as predicate argument. + */ + private static void filteringSimpleProbableThreats() { + LOGGER.info(" ### Filtering ProbabilisticThreatAwareSystem by probability ###"); + + ProbableThreat trojanArcBomb = + new SimpleProbableThreat("Trojan-ArcBomb", 1, ThreatType.TROJAN, 0.99); + ProbableThreat rootkit = + new SimpleProbableThreat("Rootkit-Kernel", 2, ThreatType.ROOTKIT, 0.8); + + List probableThreats = List.of(trojanArcBomb, rootkit); + + ProbabilisticThreatAwareSystem probabilisticThreatAwareSystem = + new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); + + LOGGER.info("Filtering ProbabilisticThreatAwareSystem. Initial : " + + probabilisticThreatAwareSystem); + + //Filtering using filterer + ProbabilisticThreatAwareSystem filtered = probabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); + + LOGGER.info("Filtered by probability = 0.99 : " + filtered); + } + + /** + * Demonstrates how to filter {@link ThreatAwareSystem} based on startingOffset property + * of {@link SimpleThreat}. The @{@link com.iluwatar.filterer.domain.Filterer#by(Predicate)} + * method is able to use {@link Threat} as predicate argument. + */ + private static void filteringSimpleThreats() { + LOGGER.info("### Filtering ThreatAwareSystem by ThreatType ###"); + + Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); + Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); + List threats = List.of(rootkit, trojan); + + ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + + LOGGER.info("Filtering ThreatAwareSystem. Initial : " + threatAwareSystem); + + //Filtering using Filterer + ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); + + LOGGER.info("Filtered by threatType = ROOTKIT : " + rootkitThreatAwareSystem); + } + +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java b/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java deleted file mode 100644 index a771c1a82..000000000 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The MIT License - * Copyright © 2014-2019 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.filterer.issue; - -import java.util.Objects; - -/** - * Represents position of an issue. Takes starting and ending offset of issue in given text. - */ -public final class IssuePosition { - - private final int startOffset; - private final int endOffset; - - /** - * Factory method for constructing `IssuePosition` instances. - * @param startOffset starting offset of where the issue begins. - * @param endOffset ending offset of where the issue ends. - * @return new IssuePosition instance. - */ - public static IssuePosition of(final int startOffset, final int endOffset) { - return new IssuePosition(startOffset, endOffset); - } - - private IssuePosition(int startOffset, int endOffset) { - this.startOffset = startOffset; - this.endOffset = endOffset; - } - - int startOffset() { - return startOffset; - } - - int endOffset() { - return endOffset; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IssuePosition that = (IssuePosition) o; - return startOffset == that.startOffset - && endOffset == that.endOffset; - } - - @Override - public int hashCode() { - return Objects.hash(startOffset, endOffset); - } -} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java similarity index 79% rename from filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java index da15bdd99..3a2959828 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java @@ -21,29 +21,29 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.iluwatar.filterer.domain.Filterer; import java.util.List; /** - * Represents text that is aware of it's issues with given probability of their occurrence. + * Represents system that is aware of it's threats with given probability of their occurrence. */ -public interface ProbabilisticIssueAwareText extends IssueAwareText { +public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { /** * {@inheritDoc} * @return */ @Override - List issues(); + List threats(); /** * {@inheritDoc} * @return */ @Override - Filterer filtered(); + Filterer filtered(); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java similarity index 81% rename from filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java index ccb047fa4..11e61dbf6 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java @@ -21,15 +21,15 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; /** - * Represents issue that is an issue with given probability. + * Represents threat that might be a threat with given probability. */ -public interface ProbableIssue extends Issue { +public interface ProbableThreat extends Threat { /** - * Returns probability of occurrence of given issue. - * @return probability of occurrence of given issue. + * Returns probability of occurrence of given threat. + * @return probability of occurrence of given threat. */ double probability(); } \ No newline at end of file diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java similarity index 54% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java index e1b4afc82..37fae6a74 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.google.common.collect.ImmutableList; import com.iluwatar.filterer.domain.Filterer; @@ -29,56 +29,60 @@ import com.iluwatar.filterer.domain.Filterer; import java.util.List; import java.util.Objects; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * {@inheritDoc} */ -public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwareText { +public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { - private final String text; - private final ImmutableList issues; + private final String systemId; + private final ImmutableList threats; - SimpleProbabilisticIssueAwareText(final String text, final List issues) { - this.text = text; - this.issues = ImmutableList.copyOf(issues); + public SimpleProbabilisticThreatAwareSystem( + final String systemId, + final List threats + ) { + this.systemId = systemId; + this.threats = ImmutableList.copyOf(threats); } /** * {@inheritDoc} */ @Override - public String text() { - return text; + public String systemId() { + return systemId; } /** * {@inheritDoc} */ @Override - public List issues() { - return issues; + public List threats() { + return threats; } /** * {@inheritDoc} */ @Override - public Filterer filtered() { + public Filterer filtered() { return this::filteredGroup; } - private ProbabilisticIssueAwareText filteredGroup( - final Predicate predicate + private ProbabilisticThreatAwareSystem filteredGroup( + final Predicate predicate ) { - return new SimpleProbabilisticIssueAwareText(this.text, filteredItems(predicate)); + return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate)); } - private ImmutableList filteredItems( - final Predicate predicate + private List filteredItems( + final Predicate predicate ) { - return this.issues.stream() + return this.threats.stream() .filter(predicate) - .collect(ImmutableList.toImmutableList()); + .collect(Collectors.toList()); } @Override @@ -89,13 +93,21 @@ public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwar if (o == null || getClass() != o.getClass()) { return false; } - SimpleProbabilisticIssueAwareText that = (SimpleProbabilisticIssueAwareText) o; - return text.equals(that.text) - && issues.equals(that.issues); + SimpleProbabilisticThreatAwareSystem that = (SimpleProbabilisticThreatAwareSystem) o; + return systemId.equals(that.systemId) + && threats.equals(that.threats); } @Override public int hashCode() { - return Objects.hash(text, issues); + return Objects.hash(systemId, threats); + } + + @Override + public String toString() { + return "SimpleProbabilisticThreatAwareSystem{" + + "systemId='" + systemId + '\'' + + ", threats=" + threats + + '}'; } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java similarity index 74% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java index 2b7672256..27efc740a 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java @@ -21,22 +21,23 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import java.util.Objects; /** * {@inheritDoc} */ -public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { +public class SimpleProbableThreat extends SimpleThreat implements ProbableThreat { private final double probability; - SimpleProbableIssue(final IssuePosition issuePosition, - final IssueType issueType, - final double probability + public SimpleProbableThreat(final String name, + final int id, + final ThreatType threatType, + final double probability ) { - super(issuePosition, issueType); + super(threatType, id, name); this.probability = probability; } @@ -59,7 +60,7 @@ public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { if (!super.equals(o)) { return false; } - SimpleProbableIssue that = (SimpleProbableIssue) o; + SimpleProbableThreat that = (SimpleProbableThreat) o; return Double.compare(that.probability, probability) == 0; } @@ -67,4 +68,12 @@ public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { public int hashCode() { return Objects.hash(super.hashCode(), probability); } + + @Override + public String toString() { + return "SimpleProbableThreat{" + + "probability=" + probability + + "} " + + super.toString(); + } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java similarity index 59% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java index fde5b8d8e..fe7f155d4 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java @@ -21,42 +21,54 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import java.util.Objects; -public class SimpleIssue implements Issue { +/** + * Represents a simple threat. + */ +public class SimpleThreat implements Threat { - private final IssuePosition issuePosition; - private final IssueType issueType; + private final ThreatType threatType; + private final int id; + private final String name; - SimpleIssue(final IssuePosition issuePosition, IssueType issueType) { - this.issuePosition = issuePosition; - this.issueType = issueType; + /** + * Constructor. + * + * @param threatType {@link ThreatType}. + * @param id threat id. + * @param name threat name. + */ + public SimpleThreat(final ThreatType threatType, final int id, String name) { + this.threatType = threatType; + this.id = id; + this.name = name; } /** * {@inheritDoc} */ @Override - public int startOffset() { - return issuePosition.startOffset(); + public String name() { + return name; } /** * {@inheritDoc} */ @Override - public int endOffset() { - return issuePosition.endOffset(); + public int id() { + return id; } /** * {@inheritDoc} */ @Override - public IssueType type() { - return issueType; + public ThreatType type() { + return threatType; } @Override @@ -67,13 +79,23 @@ public class SimpleIssue implements Issue { if (o == null || getClass() != o.getClass()) { return false; } - SimpleIssue that = (SimpleIssue) o; - return issuePosition.equals(that.issuePosition) - && issueType == that.issueType; + SimpleThreat that = (SimpleThreat) o; + return id == that.id + && threatType == that.threatType + && Objects.equals(name, that.name); } @Override public int hashCode() { - return Objects.hash(issuePosition, issueType); + return Objects.hash(threatType, id, name); + } + + @Override + public String toString() { + return "SimpleThreat{" + + "threatType=" + threatType + + ", id=" + id + + ", name='" + name + '\'' + + '}'; } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java similarity index 63% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java index c654a3aaa..49707cf50 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.google.common.collect.ImmutableList; import com.iluwatar.filterer.domain.Filterer; @@ -30,17 +30,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * {@inheritDoc} */ -public class SimpleIssueAwareText implements IssueAwareText { +public class SimpleThreatAwareSystem implements ThreatAwareSystem { - private final String text; - private final ImmutableList issues; + private final String systemId; + private final ImmutableList issues; - SimpleIssueAwareText(final String text, final List issues) { - this.text = text; + public SimpleThreatAwareSystem(final String systemId, final List issues) { + this.systemId = systemId; this.issues = ImmutableList.copyOf(issues); } @@ -48,15 +49,15 @@ public class SimpleIssueAwareText implements IssueAwareText { * {@inheritDoc} */ @Override - public String text() { - return text; + public String systemId() { + return systemId; } /** * {@inheritDoc} */ @Override - public List issues() { + public List threats() { return new ArrayList<>(issues); } @@ -64,18 +65,18 @@ public class SimpleIssueAwareText implements IssueAwareText { * {@inheritDoc} */ @Override - public Filterer filtered() { + public Filterer filtered() { return this::filteredGroup; } - private IssueAwareText filteredGroup(Predicate predicate) { - return new SimpleIssueAwareText(this.text, filteredItems(predicate)); + private ThreatAwareSystem filteredGroup(Predicate predicate) { + return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate)); } - private ImmutableList filteredItems(Predicate predicate) { + private List filteredItems(Predicate predicate) { return this.issues.stream() .filter(predicate) - .collect(ImmutableList.toImmutableList()); + .collect(Collectors.toList()); } @Override @@ -86,13 +87,21 @@ public class SimpleIssueAwareText implements IssueAwareText { if (o == null || getClass() != o.getClass()) { return false; } - SimpleIssueAwareText that = (SimpleIssueAwareText) o; - return text.equals(that.text) + SimpleThreatAwareSystem that = (SimpleThreatAwareSystem) o; + return systemId.equals(that.systemId) && issues.equals(that.issues); } @Override public int hashCode() { - return Objects.hash(text, issues); + return Objects.hash(systemId, issues); + } + + @Override + public String toString() { + return "SimpleThreatAwareSystem{" + + "systemId='" + systemId + + '\'' + ", issues=" + issues + + '}'; } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java similarity index 71% rename from filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java index 957ade6e5..515b59332 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java @@ -21,29 +21,29 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; /** - * Represents an issue that can be detected in given text. + * Represents a threat that can be detected in given system. */ -public interface Issue { +public interface Threat { /** - * Returns starting position where the issue begins. + * Returns name of the threat. * - * @return value representing starting position of the issue. + * @return value representing name of the threat. */ - int startOffset(); + String name(); /** - * Returns ending position where the issue ends. + * Returns unique id of the threat. * - * @return value representing ending position of the issue. + * @return value representing threat id. */ - int endOffset(); + int id(); /** - * Returns issue type. - * @return {@link IssueType} + * Returns threat type. + * @return {@link ThreatType} */ - IssueType type(); + ThreatType type(); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java similarity index 78% rename from filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java index 8141ae849..b889d537d 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java @@ -21,35 +21,35 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.iluwatar.filterer.domain.Filterer; import java.util.List; /** - * Represents text that is aware of issues that are present in it. + * Represents system that is aware of threats that are present in it. */ -public interface IssueAwareText { +public interface ThreatAwareSystem { /** - * Returns the analyzed text. + * Returns the system id. * - * @return the analyzed text. + * @return system id. */ - String text(); + String systemId(); /** - * Returns list of issues for this text. - * @return list of issues for this text. + * Returns list of threats for this system. + * @return list of threats for this system. */ - List issues(); + List threats(); /** * Returns the instance of {@link Filterer} helper interface that allows to covariantly * specify lower bound for predicate that we want to filter by. * @return an instance of {@link Filterer} helper interface. */ - Filterer filtered(); + Filterer filtered(); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java similarity index 92% rename from filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java index ee2c12ce5..5f9a152a8 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java @@ -21,6 +21,6 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; -enum IssueType { GRAMMAR, SPELLING } +public enum ThreatType { TROJAN, WORM, ROOTKIT } diff --git a/filterer/src/test/java/com/iluwatar/filterer/AppTest.java b/filterer/src/test/java/com/iluwatar/filterer/AppTest.java new file mode 100644 index 000000000..551ebcc18 --- /dev/null +++ b/filterer/src/test/java/com/iluwatar/filterer/AppTest.java @@ -0,0 +1,33 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.filterer; + +import org.junit.jupiter.api.Test; + +class AppTest { + @Test + void shouldLaunchApp() { + App.main(new String[]{}); + } +} \ No newline at end of file diff --git a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java similarity index 60% rename from filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java rename to filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java index 142415111..592fabe88 100644 --- a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java +++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java @@ -21,32 +21,31 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import org.junit.jupiter.api.Test; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; - -class SimpleProbabilisticIssueAwareTextTest { +import static org.junit.jupiter.api.Assertions.assertEquals; +class SimpleProbabilisticThreatAwareSystemTest { @Test void shouldFilterByProbability() { //given - ProbableIssue spellingIssue = new SimpleProbableIssue(IssuePosition.of(4, 5), IssueType.SPELLING, 100); - ProbableIssue grammarIssue = new SimpleProbableIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR, 99); - List issues = List.of(spellingIssue, grammarIssue); + ProbableThreat trojan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); + ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); + List probableThreats = List.of(trojan, rootkit); - SimpleProbabilisticIssueAwareText simpleIssueWiseText = new SimpleProbabilisticIssueAwareText("I mihgt gone there", issues); + ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem = + new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); //when - ProbabilisticIssueAwareText filtered = simpleIssueWiseText.filtered() - .by(issue1 -> Double.compare(issue1.probability(), 99) == 0); + ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); //then - assertThat(filtered.issues()).hasSize(1); - assertThat(filtered.issues()).element(0).isEqualTo(grammarIssue); + assertEquals(filtered.threats().size(), 1); + assertEquals(filtered.threats().get(0), trojan); } - } \ No newline at end of file diff --git a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java similarity index 62% rename from filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java rename to filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java index 1278128ae..91fb62718 100644 --- a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java +++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java @@ -21,32 +21,30 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import org.junit.jupiter.api.Test; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; - -class SimpleIssueAwareTextTest { +import static org.junit.jupiter.api.Assertions.*; +class SimpleThreatAwareSystemTest { @Test - void shouldFilterByStartOffset() { + void shouldFilterByThreatType() { //given - SimpleIssue spellingIssue = new SimpleIssue(IssuePosition.of(4, 5), IssueType.SPELLING); - SimpleIssue grammarIssue = new SimpleIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR); - List issues = List.of(spellingIssue, grammarIssue); + Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); + Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); + List threats = List.of(rootkit, trojan); - SimpleIssueAwareText simpleIssueWiseText = new SimpleIssueAwareText("I mihgt gone there", issues); + ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); //when - IssueAwareText filtered = simpleIssueWiseText.filtered() - .by(issue1 -> issue1.startOffset() == 4); + ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); //then - assertThat(filtered.issues()).hasSize(1); - assertThat(filtered.issues()).element(0).isEqualTo(spellingIssue); + assertEquals(rootkitThreatAwareSystem.threats().size(), 1); + assertEquals(rootkitThreatAwareSystem.threats().get(0), rootkit); } - -} +} \ No newline at end of file From 3d9afbaeec872b6ee36f68c9e5738f543d8d5562 Mon Sep 17 00:00:00 2001 From: Michal Krzywanski Date: Sat, 22 Aug 2020 18:24:41 +0200 Subject: [PATCH 028/254] fixed typo in read me --- filterer/README.MD | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/filterer/README.MD b/filterer/README.MD index 3281e9ecc..b8207af6f 100644 --- a/filterer/README.MD +++ b/filterer/README.MD @@ -190,7 +190,8 @@ It enables you to easily extend filtering ability of container-like objects as b * [Application of Filterer pattern in domain of text analysis](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) ## Known uses -One of the uses is present on the blog presented in this link. It presents how to use `Filterer` pattern to create text issue anaylyzer with support for test cases used for unit testing. +One of the uses is present on the blog presented in [this](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) link. +It presents how to use `Filterer` pattern to create text issue analyzer with support for test cases used for unit testing. ## Consequences Pros : From e65b65257ebaf80113ec08f2ff85c2b8a1c10bd4 Mon Sep 17 00:00:00 2001 From: Michal Krzywanski Date: Sun, 23 Aug 2020 11:00:15 +0200 Subject: [PATCH 029/254] fixing typos in readme file, introducing var local type inference where possible --- filterer/README.MD | 8 +++---- .../main/java/com/iluwatar/filterer/App.java | 23 ++++++++----------- .../SimpleProbabilisticThreatAwareSystem.java | 2 +- .../filterer/threat/SimpleProbableThreat.java | 2 +- .../filterer/threat/SimpleThreat.java | 2 +- .../threat/SimpleThreatAwareSystem.java | 2 +- ...pleProbabilisticThreatAwareSystemTest.java | 8 +++---- .../threat/SimpleThreatAwareSystemTest.java | 8 +++---- 8 files changed, 26 insertions(+), 29 deletions(-) diff --git a/filterer/README.MD b/filterer/README.MD index b8207af6f..0c03e21a9 100644 --- a/filterer/README.MD +++ b/filterer/README.MD @@ -14,7 +14,7 @@ tags: Filterer ## Intent -The intent of this design pattern is to to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. +The intent of this design pattern is to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. ## Explanation Real world example @@ -59,7 +59,7 @@ The container-like object (`ThreatAwareSystem` in our case) needs to have a meth ability to covariantly specify a lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the container-like objects. In our example we will be able to pass a predicate that takes `? extends Threat` object and return `? extends ThreatAwareSystem` -from `Filtered::by` method. A simple implementation of `ThreadAwareSystem` : +from `Filtered::by` method. A simple implementation of `ThreatAwareSystem` : ```java public class SimpleThreatAwareSystem implements ThreatAwareSystem { @@ -99,7 +99,7 @@ public class SimpleThreatAwareSystem implements ThreatAwareSystem { ``` the `filtered` method is overridden to filter the threats list by given predicate. -Now if we introduce new subtype of `Thread` interface that adds probability with which given thread can appear : +Now if we introduce a new subtype of `Threat` interface that adds probability with which given threat can appear : ```java public interface ProbableThreat extends Threat { double probability(); @@ -116,7 +116,7 @@ public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { } ```` Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify different return covariant type -by specifing different generic types. Our interfaces are clean and not cluttered by default implementations. We +by specifying different generic types. Our interfaces are clean and not cluttered by default implementations. We we will be able to filter `ProbabilisticThreatAwareSystem` by `ProbableThreat` properties : ```java public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { diff --git a/filterer/src/main/java/com/iluwatar/filterer/App.java b/filterer/src/main/java/com/iluwatar/filterer/App.java index 97ed24837..43de5a646 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/App.java +++ b/filterer/src/main/java/com/iluwatar/filterer/App.java @@ -23,7 +23,6 @@ package com.iluwatar.filterer; -import com.iluwatar.filterer.threat.ProbabilisticThreatAwareSystem; import com.iluwatar.filterer.threat.ProbableThreat; import com.iluwatar.filterer.threat.SimpleProbabilisticThreatAwareSystem; import com.iluwatar.filterer.threat.SimpleProbableThreat; @@ -65,24 +64,22 @@ public class App { private static void filteringSimpleProbableThreats() { LOGGER.info(" ### Filtering ProbabilisticThreatAwareSystem by probability ###"); - ProbableThreat trojanArcBomb = - new SimpleProbableThreat("Trojan-ArcBomb", 1, ThreatType.TROJAN, 0.99); - ProbableThreat rootkit = - new SimpleProbableThreat("Rootkit-Kernel", 2, ThreatType.ROOTKIT, 0.8); + var trojanArcBomb = new SimpleProbableThreat("Trojan-ArcBomb", 1, ThreatType.TROJAN, 0.99); + var rootkit = new SimpleProbableThreat("Rootkit-Kernel", 2, ThreatType.ROOTKIT, 0.8); List probableThreats = List.of(trojanArcBomb, rootkit); - ProbabilisticThreatAwareSystem probabilisticThreatAwareSystem = - new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); + var probabilisticThreatAwareSystem = + new SimpleProbabilisticThreatAwareSystem("Sys-1", probableThreats); LOGGER.info("Filtering ProbabilisticThreatAwareSystem. Initial : " + probabilisticThreatAwareSystem); //Filtering using filterer - ProbabilisticThreatAwareSystem filtered = probabilisticThreatAwareSystem.filtered() + var filteredThreatAwareSystem = probabilisticThreatAwareSystem.filtered() .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); - LOGGER.info("Filtered by probability = 0.99 : " + filtered); + LOGGER.info("Filtered by probability = 0.99 : " + filteredThreatAwareSystem); } /** @@ -93,16 +90,16 @@ public class App { private static void filteringSimpleThreats() { LOGGER.info("### Filtering ThreatAwareSystem by ThreatType ###"); - Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); - Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); + var rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); + var trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); List threats = List.of(rootkit, trojan); - ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + var threatAwareSystem = new SimpleThreatAwareSystem("Sys-1", threats); LOGGER.info("Filtering ThreatAwareSystem. Initial : " + threatAwareSystem); //Filtering using Filterer - ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + var rootkitThreatAwareSystem = threatAwareSystem.filtered() .by(threat -> threat.type() == ThreatType.ROOTKIT); LOGGER.info("Filtered by threatType = ROOTKIT : " + rootkitThreatAwareSystem); diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java index 37fae6a74..3991d975e 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java @@ -93,7 +93,7 @@ public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreat if (o == null || getClass() != o.getClass()) { return false; } - SimpleProbabilisticThreatAwareSystem that = (SimpleProbabilisticThreatAwareSystem) o; + var that = (SimpleProbabilisticThreatAwareSystem) o; return systemId.equals(that.systemId) && threats.equals(that.threats); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java index 27efc740a..54da07873 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java @@ -60,7 +60,7 @@ public class SimpleProbableThreat extends SimpleThreat implements ProbableThreat if (!super.equals(o)) { return false; } - SimpleProbableThreat that = (SimpleProbableThreat) o; + var that = (SimpleProbableThreat) o; return Double.compare(that.probability, probability) == 0; } diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java index fe7f155d4..08a8b0e17 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java @@ -79,7 +79,7 @@ public class SimpleThreat implements Threat { if (o == null || getClass() != o.getClass()) { return false; } - SimpleThreat that = (SimpleThreat) o; + var that = (SimpleThreat) o; return id == that.id && threatType == that.threatType && Objects.equals(name, that.name); diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java index 49707cf50..f1dec40ae 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java @@ -87,7 +87,7 @@ public class SimpleThreatAwareSystem implements ThreatAwareSystem { if (o == null || getClass() != o.getClass()) { return false; } - SimpleThreatAwareSystem that = (SimpleThreatAwareSystem) o; + var that = (SimpleThreatAwareSystem) o; return systemId.equals(that.systemId) && issues.equals(that.issues); } diff --git a/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java index 592fabe88..2f14ca057 100644 --- a/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java +++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java @@ -33,15 +33,15 @@ class SimpleProbabilisticThreatAwareSystemTest { @Test void shouldFilterByProbability() { //given - ProbableThreat trojan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); - ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); + var trojan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); + var rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); List probableThreats = List.of(trojan, rootkit); - ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem = + var simpleProbabilisticThreatAwareSystem = new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); //when - ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() + var filtered = simpleProbabilisticThreatAwareSystem.filtered() .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); //then diff --git a/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java index 91fb62718..ea918c9ec 100644 --- a/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java +++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java @@ -33,14 +33,14 @@ class SimpleThreatAwareSystemTest { @Test void shouldFilterByThreatType() { //given - Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); - Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); + var rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); + var trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); List threats = List.of(rootkit, trojan); - ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + var threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); //when - ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + var rootkitThreatAwareSystem = threatAwareSystem.filtered() .by(threat -> threat.type() == ThreatType.ROOTKIT); //then From 7411ea86bf6c2ea375d238f98b9d5a1d504d7c71 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 23 Aug 2020 13:59:14 +0000 Subject: [PATCH 030/254] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b0e297f82..d186a560b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-127-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-128-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -259,6 +259,7 @@ This project is licensed under the terms of the MIT license.
Bethan Palmer

💻
Toxic Dreamz

💻
Edy Cu Tjong

📖 +
Michał Krzywański

💻 From c18282ad5d3cf69e024288571b14edca1777f3d3 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 23 Aug 2020 13:59:15 +0000 Subject: [PATCH 031/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index b968e8c31..18a590cc5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1158,6 +1158,15 @@ "contributions": [ "doc" ] + }, + { + "login": "mkrzywanski", + "name": "Michał Krzywański", + "avatar_url": "https://avatars0.githubusercontent.com/u/15279585?v=4", + "profile": "https://github.com/mkrzywanski", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From 0cba30784430fe001a6fe944494d9459b9b55b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 23 Aug 2020 17:06:37 +0300 Subject: [PATCH 032/254] Fix readme filename --- filterer/{README.MD => README.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename filterer/{README.MD => README.md} (98%) diff --git a/filterer/README.MD b/filterer/README.md similarity index 98% rename from filterer/README.MD rename to filterer/README.md index 0c03e21a9..9ac49d6f8 100644 --- a/filterer/README.MD +++ b/filterer/README.md @@ -1,4 +1,4 @@ ---- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ +--- layout: pattern title: Filterer folder: filterer From 015b4181145680e4b93f1fc54895aacb1238cdbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 23 Aug 2020 18:03:29 +0300 Subject: [PATCH 033/254] Update README.md --- filterer/README.md | 97 +++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/filterer/README.md b/filterer/README.md index 9ac49d6f8..89dc87e84 100644 --- a/filterer/README.md +++ b/filterer/README.md @@ -11,27 +11,33 @@ tags: --- ## Name / classification + Filterer ## Intent -The intent of this design pattern is to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. + +The intent of this design pattern is to introduce a functional interface that will add a +functionality for container-like objects to easily return filtered versions of themselves. ## Explanation + Real world example -> We are designing a threat(malware) detection system. We can have different types of threats and systems. We have a requirement that -> system should be aware of threats that are present in it. In the design we have to take into consideration that new Threat types can be -> added later. Also there is a requirement that a system can filter itself based on the threats that it possesses (system acts as container-like object for threats). -> +> We are designing a threat (malware) detection software which can analyze target systems for +> threats that are present in it. In the design we have to take into consideration that new +> Threat types can be added later. Additionally, there is a requirement that the threat detection +> system can filter the detected threats based on different criteria (the target system acts as +> container-like object for threats). In plain words -> We need to be able to filter different types of systems(container-like objects) based on properties of Threats that they contain. -> Adding new properties for Threats should be easy (we still need the ability to filter by those new properties). +> Filterer pattern is a design pattern that helps container-like objects return filtered versions +> of themselves. **Programmatic Example** -To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` interfaces. +To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` +interfaces. ```java public interface Threat { @@ -47,19 +53,26 @@ public interface ThreatAwareSystem { } ``` -Notice the `filtered` method that returns instance of `Filterer` interface which is defined as : + +Notice the `filtered` method that returns instance of `Filterer` interface which is defined as: + ```java @FunctionalInterface public interface Filterer { G by(Predicate predicate); } ``` -it is used to fulfill the requirement for system to be able to filter itself based on threat properties. -The container-like object (`ThreatAwareSystem` in our case) needs to have a method that returns an instance of `Filterer`. This helper interface gives -ability to covariantly specify a lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the container-like objects. -In our example we will be able to pass a predicate that takes `? extends Threat` object and return `? extends ThreatAwareSystem` -from `Filtered::by` method. A simple implementation of `ThreatAwareSystem` : +It is used to fulfill the requirement for system to be able to filter itself based on threat +properties. The container-like object (`ThreatAwareSystem` in our case) needs to have a method that +returns an instance of `Filterer`. This helper interface gives ability to covariantly specify a +lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the +container-like objects. + +In our example we will be able to pass a predicate that takes `? extends Threat` object and +return `? extends ThreatAwareSystem` from `Filtered::by` method. A simple implementation +of `ThreatAwareSystem`: + ```java public class SimpleThreatAwareSystem implements ThreatAwareSystem { @@ -97,15 +110,21 @@ public class SimpleThreatAwareSystem implements ThreatAwareSystem { } } ``` -the `filtered` method is overridden to filter the threats list by given predicate. -Now if we introduce a new subtype of `Threat` interface that adds probability with which given threat can appear : +The `filtered` method is overridden to filter the threats list by given predicate. + +Now if we introduce a new subtype of `Threat` interface that adds probability with which given +threat can appear: + ```java public interface ProbableThreat extends Threat { double probability(); } ``` -we can also introduce a new interface that represents a system that is aware of threats with their probabilities : + +We can also introduce a new interface that represents a system that is aware of threats with their +probabilities: + ````java public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { @Override @@ -115,9 +134,12 @@ public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { Filterer filtered(); } ```` -Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify different return covariant type -by specifying different generic types. Our interfaces are clean and not cluttered by default implementations. We -we will be able to filter `ProbabilisticThreatAwareSystem` by `ProbableThreat` properties : + +Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify +different return covariant type by specifying different generic types. Our interfaces are clean and +not cluttered by default implementations. We we will be able to filter +`ProbabilisticThreatAwareSystem` by `ProbableThreat` properties: + ```java public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { @@ -156,7 +178,8 @@ public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreat } ``` -Now if we want filter `ThreatAwareSystem` by threat type we can do : +Now if we want filter `ThreatAwareSystem` by threat type we can do: + ```java Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); @@ -167,7 +190,9 @@ ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", th ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() .by(threat -> threat.type() == ThreatType.ROOTKIT); ``` -or if we want to filter `ProbabilisticThreatAwareSystem` : + +Or if we want to filter `ProbabilisticThreatAwareSystem`: + ```java ProbableThreat malwareTroyan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); @@ -178,27 +203,37 @@ ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem =new SimpleP ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); ``` + ## Class diagram + ![Filterer](./etc/filterer.png "Filterer") ## Applicability -Pattern can be used when working with container-like objects that use subtyping, instead of parametrizing(generics) for extensible class structure. -It enables you to easily extend filtering ability of container-like objects as business requirements change. + +Pattern can be used when working with container-like objects that use subtyping, instead of +parametrizing (generics) for extensible class structure. It enables you to easily extend filtering +ability of container-like objects as business requirements change. ## Tutorials + * [Article about Filterer pattern posted on it's author's blog](https://blog.tlinkowski.pl/2018/filterer-pattern/) * [Application of Filterer pattern in domain of text analysis](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) ## Known uses -One of the uses is present on the blog presented in [this](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) link. -It presents how to use `Filterer` pattern to create text issue analyzer with support for test cases used for unit testing. + +One of the uses is present on the blog presented in +[this](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) link. It presents how +to use `Filterer` pattern to create text issue analyzer with support for test cases used for unit +testing. ## Consequences -Pros : - * you can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes. -Cons : - * covariant return types mixed with generics can be sometimes tricky +Pros: + * You can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes. + +Cons: + * Covariant return types mixed with generics can be sometimes tricky ## Credits -* Author of the pattern : [Tomasz Linkowski](https://tlinkowski.pl/) \ No newline at end of file + +* Author of the pattern : [Tomasz Linkowski](https://tlinkowski.pl/) From 6d83ceba285fb2a62119f6169d8041ec05c196c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 23 Aug 2020 18:53:57 +0300 Subject: [PATCH 034/254] Update README.md --- bridge/README.md | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) 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 + ![alt text](./etc/bridge.urm.png "Bridge 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 From 3754c666045c1420d9bd118bc0f4ea8fee85a680 Mon Sep 17 00:00:00 2001 From: Stefan Birkner Date: Mon, 24 Aug 2020 23:12:45 +0200 Subject: [PATCH 035/254] Replace System Rules with System Lambda System Lambda is more specific. It only wraps the part of the code that produces the output. --- pom.xml | 6 +-- subclass-sandbox/pom.xml | 2 +- .../subclasssandbox/GroundDiveTest.java | 38 +++++++++--------- .../subclasssandbox/SkyLaunchTest.java | 39 +++++++++---------- 4 files changed, 40 insertions(+), 45 deletions(-) diff --git a/pom.xml b/pom.xml index 1275ce115..3b7ad3568 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ 2.3.1 2.3.2 1.3.2 - 1.19.0 + 1.1.0 2.0.0 3.5.0 @@ -338,8 +338,8 @@ com.github.stefanbirkner - system-rules - ${system-rules.version} + system-lambda + ${system-lambda.version} test diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index ac718291e..a912ada3f 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -42,7 +42,7 @@ com.github.stefanbirkner - system-rules + system-lambda org.junit.jupiter diff --git a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java index 97e2ac67d..3b379946c 100644 --- a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java +++ b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java @@ -23,55 +23,48 @@ package com.iluwatar.subclasssandbox; +import com.github.stefanbirkner.systemlambda.Statement; import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemOutRule; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.tapSystemOutNormalized; /** * GroundDive unit tests. */ public class GroundDiveTest { - @Rule - public SystemOutRule log = new SystemOutRule().enableLog(); - @Test - public void testMove() { - log.clearLog(); + public void testMove() throws Exception { var groundDive = new GroundDive(); groundDive.move(1.0, 1.0, 1.0); - var outputLog = getLogContent(log.getLog()); + var outputLog = getLogContent(() -> groundDive.move(1.0, 1.0, 1.0)); var expectedLog = "Move to ( 1.0, 1.0, 1.0 )"; Assert.assertEquals(outputLog, expectedLog); } @Test - public void testPlaySound() { - log.clearLog(); + public void testPlaySound() throws Exception { var groundDive = new GroundDive(); - groundDive.playSound("SOUND_NAME", 1); - var outputLog = getLogContent(log.getLog()); + var outputLog = getLogContent(() -> groundDive.playSound("SOUND_NAME", 1)); var expectedLog = "Play SOUND_NAME with volumn 1"; Assert.assertEquals(outputLog, expectedLog); } @Test - public void testSpawnParticles() { - log.clearLog(); + public void testSpawnParticles() throws Exception { var groundDive = new GroundDive(); - groundDive.spawnParticles("PARTICLE_TYPE", 100); - final var outputLog = getLogContent(log.getLog()); + final var outputLog = getLogContent( + () -> groundDive.spawnParticles("PARTICLE_TYPE", 100)); final var expectedLog = "Spawn 100 particle with type PARTICLE_TYPE"; Assert.assertEquals(outputLog, expectedLog); } @Test - public void testActivate() { - log.clearLog(); + public void testActivate() throws Exception { var groundDive = new GroundDive(); - groundDive.activate(); - var logs = log.getLog().split("\n"); + var logs = tapSystemOutNormalized(groundDive::activate) + .split("\n"); final var expectedSize = 3; final var log1 = logs[0].split("-")[1].trim() + " -" + logs[0].split("-")[2].trim(); final var expectedLog1 = "Move to ( 0.0, 0.0, -20.0 )"; @@ -85,6 +78,11 @@ public class GroundDiveTest { Assert.assertEquals(log3, expectedLog3); } + private String getLogContent(Statement statement) throws Exception { + var log = tapSystemOutNormalized(statement); + return getLogContent(log); + } + private String getLogContent(String log) { return log.split("-")[1].trim(); } diff --git a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java index e192737f6..d285e6c7d 100644 --- a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java +++ b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java @@ -23,55 +23,47 @@ package com.iluwatar.subclasssandbox; +import com.github.stefanbirkner.systemlambda.Statement; import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemOutRule; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.tapSystemOutNormalized; /** * SkyLaunch unit tests. */ public class SkyLaunchTest { - @Rule - public SystemOutRule log = new SystemOutRule().enableLog(); - @Test - public void testMove() { - log.clearLog(); + public void testMove() throws Exception { var skyLaunch = new SkyLaunch(); - skyLaunch.move(1.0, 1.0, 1.0); - var outputLog = getLogContent(log.getLog()); + var outputLog = getLogContent(() -> skyLaunch.move(1.0, 1.0, 1.0)); var expectedLog = "Move to ( 1.0, 1.0, 1.0 )"; Assert.assertEquals(outputLog, expectedLog); } @Test - public void testPlaySound() { - log.clearLog(); + public void testPlaySound() throws Exception { var skyLaunch = new SkyLaunch(); - skyLaunch.playSound("SOUND_NAME", 1); - var outputLog = getLogContent(log.getLog()); + var outputLog = getLogContent(() -> skyLaunch.playSound("SOUND_NAME", 1)); var expectedLog = "Play SOUND_NAME with volumn 1"; Assert.assertEquals(outputLog, expectedLog); } @Test - public void testSpawnParticles() { - log.clearLog(); + public void testSpawnParticles() throws Exception { var skyLaunch = new SkyLaunch(); - skyLaunch.spawnParticles("PARTICLE_TYPE", 100); - var outputLog = getLogContent(log.getLog()); + var outputLog = getLogContent( + () -> skyLaunch.spawnParticles("PARTICLE_TYPE", 100)); var expectedLog = "Spawn 100 particle with type PARTICLE_TYPE"; Assert.assertEquals(outputLog, expectedLog); } @Test - public void testActivate() { - log.clearLog(); + public void testActivate() throws Exception { var skyLaunch = new SkyLaunch(); - skyLaunch.activate(); - var logs = log.getLog().split("\n"); + var logs = tapSystemOutNormalized(skyLaunch::activate) + .split("\n"); final var expectedSize = 3; final var log1 = getLogContent(logs[0]); final var expectedLog1 = "Move to ( 0.0, 0.0, 20.0 )"; @@ -85,6 +77,11 @@ public class SkyLaunchTest { Assert.assertEquals(log3, expectedLog3); } + private String getLogContent(Statement statement) throws Exception { + var log = tapSystemOutNormalized(statement); + return getLogContent(log); + } + private String getLogContent(String log) { return log.split("-")[1].trim(); } From b8f83c326dceb92290b31480a074c92058760989 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2020 14:42:53 +0000 Subject: [PATCH 036/254] docs: update README.md [skip ci] --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d186a560b..95fe7a912 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-128-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-129-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -261,6 +261,9 @@ This project is licensed under the terms of the MIT license.
Edy Cu Tjong

📖
Michał Krzywański

💻 + +
Stefan Birkner

💻 + From 96aa21d0e886a9858637f30c0110aedf5f752c2d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2020 14:42:54 +0000 Subject: [PATCH 037/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 18a590cc5..65eb0bf92 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1167,6 +1167,15 @@ "contributions": [ "code" ] + }, + { + "login": "stefanbirkner", + "name": "Stefan Birkner", + "avatar_url": "https://avatars1.githubusercontent.com/u/711349?v=4", + "profile": "https://www.stefan-birkner.de", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From a0e5d061cbb55d4eb0cca1798e545ccbbb391de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 25 Aug 2020 21:20:30 +0300 Subject: [PATCH 038/254] Milestone 1.23.0 --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- acyclic-visitor/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- ambassador/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- arrange-act-assert/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- balking/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- bytecode/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- circuit-breaker/pom.xml | 2 +- collection-pipeline/pom.xml | 2 +- combinator/pom.xml | 2 +- command/pom.xml | 2 +- commander/pom.xml | 2 +- composite/pom.xml | 2 +- converter/pom.xml | 2 +- cqrs/pom.xml | 2 +- dao/pom.xml | 2 +- data-bus/pom.xml | 2 +- data-locality/pom.xml | 2 +- data-mapper/pom.xml | 2 +- data-transfer-object/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- dirty-flag/pom.xml | 4 ++-- double-buffer/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- eip-aggregator/pom.xml | 2 +- eip-message-channel/pom.xml | 2 +- eip-publish-subscribe/pom.xml | 2 +- eip-splitter/pom.xml | 2 +- eip-wire-tap/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- event-queue/pom.xml | 2 +- event-sourcing/pom.xml | 2 +- execute-around/pom.xml | 2 +- extension-objects/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- filterer/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- game-loop/pom.xml | 2 +- guarded-suspension/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- leader-election/pom.xml | 2 +- leader-followers/pom.xml | 2 +- marker/pom.xml | 2 +- master-worker-pattern/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- page-object/sample-application/pom.xml | 2 +- page-object/test-automation/pom.xml | 2 +- partial-response/pom.xml | 2 +- pipeline/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- priority-queue/pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- retry/pom.xml | 2 +- role-object/pom.xml | 2 +- saga/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- serverless/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- sharding/pom.xml | 2 +- singleton/pom.xml | 2 +- spatial-partition/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strangler/pom.xml | 2 +- strategy/pom.xml | 2 +- subclass-sandbox/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- throttling/pom.xml | 2 +- tls/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- trampoline/pom.xml | 2 +- transaction-script/pom.xml | 2 +- twin/pom.xml | 2 +- typeobjectpattern/pom.xml | 2 +- unit-of-work/pom.xml | 2 +- update-method/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 145 files changed, 149 insertions(+), 149 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index 5a19c3c81..a285e2d82 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -21,7 +21,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index 614b26232..4fe0b58cd 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 abstract-factory diff --git a/acyclic-visitor/pom.xml b/acyclic-visitor/pom.xml index 24bab933a..41a126d27 100644 --- a/acyclic-visitor/pom.xml +++ b/acyclic-visitor/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 acyclic-visitor diff --git a/adapter/pom.xml b/adapter/pom.xml index 4c725def8..2cd449c06 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index f4482d0e3..8f1e2ad06 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -20,7 +20,7 @@ aggregator-microservices com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 aggregator-service diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index f99d26b65..bde50bd98 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -20,7 +20,7 @@ aggregator-microservices com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index f7899aa8f..76d506ed1 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -20,7 +20,7 @@ aggregator-microservices com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 inventory-microservice diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index a63ec2f12..e6bf655f7 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 aggregator-microservices diff --git a/ambassador/pom.xml b/ambassador/pom.xml index 6d6a9894d..33f623457 100644 --- a/ambassador/pom.xml +++ b/ambassador/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 ambassador diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 744023e90..08c7d47dc 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index 27ef343af..ba055bd71 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 image-microservice diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 63a986996..0edcbc83a 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index e7b144c58..6b61ff2e5 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/arrange-act-assert/pom.xml b/arrange-act-assert/pom.xml index bb0387e7a..c00660b01 100644 --- a/arrange-act-assert/pom.xml +++ b/arrange-act-assert/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 46aa9d354..32adc0508 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 async-method-invocation diff --git a/balking/pom.xml b/balking/pom.xml index 964531692..6d789244c 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/bridge/pom.xml b/bridge/pom.xml index 0664bc9b5..ae50aba2e 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 bridge diff --git a/builder/pom.xml b/builder/pom.xml index dab9c66a7..069f6f841 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 26987c73a..9f7e3ea70 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 business-delegate diff --git a/bytecode/pom.xml b/bytecode/pom.xml index f6be69cee..cfae54ad1 100644 --- a/bytecode/pom.xml +++ b/bytecode/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/caching/pom.xml b/caching/pom.xml index 704dd78d0..82e7546f5 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 caching diff --git a/callback/pom.xml b/callback/pom.xml index c156527f5..a493c2cab 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 callback diff --git a/chain/pom.xml b/chain/pom.xml index cf70ad1e8..40966eebf 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 chain diff --git a/circuit-breaker/pom.xml b/circuit-breaker/pom.xml index fd9f85675..4df9aacd3 100644 --- a/circuit-breaker/pom.xml +++ b/circuit-breaker/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 circuit-breaker diff --git a/collection-pipeline/pom.xml b/collection-pipeline/pom.xml index 6d8d467ad..e8de7ff33 100644 --- a/collection-pipeline/pom.xml +++ b/collection-pipeline/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 collection-pipeline diff --git a/combinator/pom.xml b/combinator/pom.xml index c2677fcc1..62c6a6658 100644 --- a/combinator/pom.xml +++ b/combinator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 combinator diff --git a/command/pom.xml b/command/pom.xml index 50a14c45f..557f2cd89 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 command diff --git a/commander/pom.xml b/commander/pom.xml index 7ab29e421..8b87442ae 100644 --- a/commander/pom.xml +++ b/commander/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 commander diff --git a/composite/pom.xml b/composite/pom.xml index c16b95c13..5e41920d7 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 composite diff --git a/converter/pom.xml b/converter/pom.xml index 56eb2ccdb..b19db2bae 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 converter 4.0.0 diff --git a/cqrs/pom.xml b/cqrs/pom.xml index b3a0303e6..57570fff4 100644 --- a/cqrs/pom.xml +++ b/cqrs/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 cqrs diff --git a/dao/pom.xml b/dao/pom.xml index 7e8bd5625..ead5e030f 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 dao diff --git a/data-bus/pom.xml b/data-bus/pom.xml index e67135ae0..cc3553336 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -33,7 +33,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 data-bus diff --git a/data-locality/pom.xml b/data-locality/pom.xml index 660daa9b7..f14676b45 100644 --- a/data-locality/pom.xml +++ b/data-locality/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 data-locality diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 64f03a186..45221020b 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 data-mapper diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml index 459b1ab1e..d51b62d2c 100644 --- a/data-transfer-object/pom.xml +++ b/data-transfer-object/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 data-transfer-object diff --git a/decorator/pom.xml b/decorator/pom.xml index c7e1a4d8d..1209d5efb 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index 63cd91842..8ff7c6617 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 9baffe382..85e8cdd1c 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 dependency-injection diff --git a/dirty-flag/pom.xml b/dirty-flag/pom.xml index 372a637f1..3908dca36 100644 --- a/dirty-flag/pom.xml +++ b/dirty-flag/pom.xml @@ -29,10 +29,10 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 dirty-flag - 1.23.0-SNAPSHOT + 1.23.0 dirty-flag http://maven.apache.org diff --git a/double-buffer/pom.xml b/double-buffer/pom.xml index cb66af1cb..e2e649fa9 100644 --- a/double-buffer/pom.xml +++ b/double-buffer/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index a77546386..de8d27a4e 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index 9582797a2..67febf5bb 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 double-dispatch diff --git a/eip-aggregator/pom.xml b/eip-aggregator/pom.xml index 578d1bbf2..c77dded15 100644 --- a/eip-aggregator/pom.xml +++ b/eip-aggregator/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 diff --git a/eip-message-channel/pom.xml b/eip-message-channel/pom.xml index bea72b1f9..02db57903 100644 --- a/eip-message-channel/pom.xml +++ b/eip-message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 eip-message-channel diff --git a/eip-publish-subscribe/pom.xml b/eip-publish-subscribe/pom.xml index e7b5462b6..ab98cf76a 100644 --- a/eip-publish-subscribe/pom.xml +++ b/eip-publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 eip-publish-subscribe diff --git a/eip-splitter/pom.xml b/eip-splitter/pom.xml index 9c06f3f8d..d1bc7f9c6 100644 --- a/eip-splitter/pom.xml +++ b/eip-splitter/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 diff --git a/eip-wire-tap/pom.xml b/eip-wire-tap/pom.xml index 06cbc33db..2b122a64e 100644 --- a/eip-wire-tap/pom.xml +++ b/eip-wire-tap/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 5553de2e3..1f3896ff3 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index 001b3b9a8..ccbda1f0a 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 17d2795c4..b9da44c6f 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 event-driven-architecture diff --git a/event-queue/pom.xml b/event-queue/pom.xml index fd8ce9902..1a93f9dad 100644 --- a/event-queue/pom.xml +++ b/event-queue/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 event-queue diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml index 0d1592abb..486f6d9e0 100644 --- a/event-sourcing/pom.xml +++ b/event-sourcing/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 event-sourcing diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 1752f04f5..65b98a10f 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 execute-around diff --git a/extension-objects/pom.xml b/extension-objects/pom.xml index 0194357ed..f6463e35f 100644 --- a/extension-objects/pom.xml +++ b/extension-objects/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/facade/pom.xml b/facade/pom.xml index a7fdb88f0..3847f8cbb 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index 87f27b341..521e6340f 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index 5f0358d4d..8038a1ff9 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index 13f646b80..a44eae026 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/filterer/pom.xml b/filterer/pom.xml index 4477332ae..e64ac9846 100644 --- a/filterer/pom.xml +++ b/filterer/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index 9eb063c13..28e573258 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index 8effd0fc9..00435f835 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index f3a8082b5..574f5b516 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index 34dabc182..447e341fd 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 front-controller diff --git a/game-loop/pom.xml b/game-loop/pom.xml index 706d3cff4..33a671449 100644 --- a/game-loop/pom.xml +++ b/game-loop/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index 791c696c1..81cf96084 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 jar guarded-suspension diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index fdb37edb0..e101a849c 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index 4873d0ddb..3a932749b 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index ea8597374..59f82325a 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index 118cfcdf6..d2d538c24 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 514cedbea..1d4faf770 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 iterator diff --git a/layers/pom.xml b/layers/pom.xml index 2ebace18b..d4b218272 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index a6a5d3a45..1bfe3b637 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 lazy-loading diff --git a/leader-election/pom.xml b/leader-election/pom.xml index 8fc833f18..b61041502 100644 --- a/leader-election/pom.xml +++ b/leader-election/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 leader-election diff --git a/leader-followers/pom.xml b/leader-followers/pom.xml index c0f27d051..2e5789acc 100644 --- a/leader-followers/pom.xml +++ b/leader-followers/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 leader-followers diff --git a/marker/pom.xml b/marker/pom.xml index 5212832d8..2e2ec74b5 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/master-worker-pattern/pom.xml b/master-worker-pattern/pom.xml index 26f4d70bb..54a72da69 100644 --- a/master-worker-pattern/pom.xml +++ b/master-worker-pattern/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 master-worker-pattern diff --git a/mediator/pom.xml b/mediator/pom.xml index 23d28726b..ffae20778 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 mediator diff --git a/memento/pom.xml b/memento/pom.xml index 70121cea3..265825ccb 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 memento diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index a8ef230e8..6e2e062d8 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 97b47f82c..363dfd78c 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 model-view-presenter model-view-presenter diff --git a/module/pom.xml b/module/pom.xml index 5d9a6d529..4768ffcef 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 module diff --git a/monad/pom.xml b/monad/pom.xml index f553c3079..e74ee83eb 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 monad diff --git a/monostate/pom.xml b/monostate/pom.xml index 0e51fc700..f00f7a677 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index ef1e9c892..8bb51845f 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index a32f6a3ea..0d24529fa 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index 9cdff25e4..c08862948 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 0437c2da5..41cbd8571 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0-SNAPSHOT + 1.23.0 naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index 3457ac0a4..869af61f3 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0-SNAPSHOT + 1.23.0 naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index f46541f48..f43b99197 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0-SNAPSHOT + 1.23.0 naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index 5b7a2e0c7..0fc95946c 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 naked-objects pom @@ -333,17 +333,17 @@ ${project.groupId} naked-objects-dom - 1.23.0-SNAPSHOT + 1.23.0 ${project.groupId} naked-objects-fixture - 1.23.0-SNAPSHOT + 1.23.0 ${project.groupId} naked-objects-webapp - 1.23.0-SNAPSHOT + 1.23.0 diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index bbddeb791..86960a5fb 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0-SNAPSHOT + 1.23.0 naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index 7b88fca79..e91b06f74 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 null-object diff --git a/object-mother/pom.xml b/object-mother/pom.xml index 5ac3ce410..07d724e76 100644 --- a/object-mother/pom.xml +++ b/object-mother/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 object-mother diff --git a/object-pool/pom.xml b/object-pool/pom.xml index 2adad8942..ed3f87a0d 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 object-pool diff --git a/observer/pom.xml b/observer/pom.xml index 1e48268d8..e971c5602 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 observer diff --git a/page-object/pom.xml b/page-object/pom.xml index 4bf31d72e..6c1066fce 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -46,7 +46,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 page-object pom diff --git a/page-object/sample-application/pom.xml b/page-object/sample-application/pom.xml index 5ded184cc..c715418d5 100644 --- a/page-object/sample-application/pom.xml +++ b/page-object/sample-application/pom.xml @@ -29,7 +29,7 @@ page-object com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 sample-application diff --git a/page-object/test-automation/pom.xml b/page-object/test-automation/pom.xml index 68025f4b8..f2ca98689 100644 --- a/page-object/test-automation/pom.xml +++ b/page-object/test-automation/pom.xml @@ -29,7 +29,7 @@ page-object com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 test-automation diff --git a/partial-response/pom.xml b/partial-response/pom.xml index d10a496dd..a4788e5d1 100644 --- a/partial-response/pom.xml +++ b/partial-response/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/pipeline/pom.xml b/pipeline/pom.xml index 8c511cd8a..a29007cda 100644 --- a/pipeline/pom.xml +++ b/pipeline/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 pipeline diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 4989581d7..38d12c6c7 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 poison-pill diff --git a/pom.xml b/pom.xml index 3b7ad3568..56c593574 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 pom 2014-2019 diff --git a/priority-queue/pom.xml b/priority-queue/pom.xml index 7f435f489..338079a66 100644 --- a/priority-queue/pom.xml +++ b/priority-queue/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index cb81ca3fc..bc4eeff65 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index ab1872c51..853eb68f8 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index 4a9d76df1..ac0f66a43 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 promise diff --git a/property/pom.xml b/property/pom.xml index d271af036..e96371c9c 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 property diff --git a/prototype/pom.xml b/prototype/pom.xml index e68b11892..7fc26080a 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index f54c77dcf..8d2749483 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 proxy diff --git a/queue-load-leveling/pom.xml b/queue-load-leveling/pom.xml index ee6e6c623..8f9a785c9 100644 --- a/queue-load-leveling/pom.xml +++ b/queue-load-leveling/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 queue-load-leveling diff --git a/reactor/pom.xml b/reactor/pom.xml index b95b0b6e2..424c00db7 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index 92f53df66..10d49f6cc 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 0b98cdb41..5511c4fc3 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index ef8e19f48..80d34e3aa 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 resource-acquisition-is-initialization diff --git a/retry/pom.xml b/retry/pom.xml index e6c2701e0..db59fa049 100644 --- a/retry/pom.xml +++ b/retry/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 retry jar diff --git a/role-object/pom.xml b/role-object/pom.xml index c980adc2c..2b3e07be0 100644 --- a/role-object/pom.xml +++ b/role-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 role-object diff --git a/saga/pom.xml b/saga/pom.xml index 1971ae6cf..c83c8fb45 100644 --- a/saga/pom.xml +++ b/saga/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 saga diff --git a/semaphore/pom.xml b/semaphore/pom.xml index b6375366b..0a2ac7aed 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 semaphore diff --git a/servant/pom.xml b/servant/pom.xml index 395060d50..e8925cea9 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 servant diff --git a/serverless/pom.xml b/serverless/pom.xml index 1fb55ec47..c9d7ec71b 100644 --- a/serverless/pom.xml +++ b/serverless/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 diff --git a/service-layer/pom.xml b/service-layer/pom.xml index 881ec8ba6..aaee48310 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index 1d8e9fcd8..ed2366ed0 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 service-locator diff --git a/sharding/pom.xml b/sharding/pom.xml index 2d00629bc..61c15db5b 100644 --- a/sharding/pom.xml +++ b/sharding/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/singleton/pom.xml b/singleton/pom.xml index b09602d0e..7b7686108 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 singleton diff --git a/spatial-partition/pom.xml b/spatial-partition/pom.xml index 7312427d0..2f47d73d9 100644 --- a/spatial-partition/pom.xml +++ b/spatial-partition/pom.xml @@ -46,7 +46,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 spatial-partition diff --git a/specification/pom.xml b/specification/pom.xml index 9214e984e..d2945516b 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 specification diff --git a/state/pom.xml b/state/pom.xml index b1ff3f5f3..c53f3d797 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 3cea3b158..1de9b653d 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 step-builder diff --git a/strangler/pom.xml b/strangler/pom.xml index 4a1fb42ba..ba85f7184 100644 --- a/strangler/pom.xml +++ b/strangler/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/strategy/pom.xml b/strategy/pom.xml index cd1395c7a..aad38f1ce 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 strategy diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index a912ada3f..144f099a3 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/template-method/pom.xml b/template-method/pom.xml index c449ef04f..36a0d8550 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index 0ea0b1266..abcb8a9f5 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 thread-pool diff --git a/throttling/pom.xml b/throttling/pom.xml index 6ae062c5e..77f911c24 100644 --- a/throttling/pom.xml +++ b/throttling/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/tls/pom.xml b/tls/pom.xml index 7100ae295..f6adc911f 100644 --- a/tls/pom.xml +++ b/tls/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 tls diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index 2966cca19..3324f75f0 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 tolerant-reader diff --git a/trampoline/pom.xml b/trampoline/pom.xml index 13988ca92..c651b4f8b 100644 --- a/trampoline/pom.xml +++ b/trampoline/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 trampoline diff --git a/transaction-script/pom.xml b/transaction-script/pom.xml index 5dc2aa981..081567c47 100644 --- a/transaction-script/pom.xml +++ b/transaction-script/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/twin/pom.xml b/twin/pom.xml index cb60511c9..37c06bd20 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 twin diff --git a/typeobjectpattern/pom.xml b/typeobjectpattern/pom.xml index c8f0005af..32e252aea 100644 --- a/typeobjectpattern/pom.xml +++ b/typeobjectpattern/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 typeobjectpattern diff --git a/unit-of-work/pom.xml b/unit-of-work/pom.xml index 0f8f0b21a..730b7921b 100644 --- a/unit-of-work/pom.xml +++ b/unit-of-work/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/update-method/pom.xml b/update-method/pom.xml index 78b89555a..2659d1e2c 100644 --- a/update-method/pom.xml +++ b/update-method/pom.xml @@ -28,7 +28,7 @@ java-design-patterns com.iluwatar - 1.23.0-SNAPSHOT + 1.23.0 4.0.0 diff --git a/value-object/pom.xml b/value-object/pom.xml index aa4101b5c..a2dd714de 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 00497b41f..dddb4d4e3 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0-SNAPSHOT + 1.23.0 visitor From 723afb85ba1ce9a1865040a8471ab457dc0edc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 25 Aug 2020 21:21:36 +0300 Subject: [PATCH 039/254] Set version for next development iteration --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- acyclic-visitor/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- ambassador/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- arrange-act-assert/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- balking/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- bytecode/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- circuit-breaker/pom.xml | 2 +- collection-pipeline/pom.xml | 2 +- combinator/pom.xml | 2 +- command/pom.xml | 2 +- commander/pom.xml | 2 +- composite/pom.xml | 2 +- converter/pom.xml | 2 +- cqrs/pom.xml | 2 +- dao/pom.xml | 2 +- data-bus/pom.xml | 2 +- data-locality/pom.xml | 2 +- data-mapper/pom.xml | 2 +- data-transfer-object/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- dirty-flag/pom.xml | 4 ++-- double-buffer/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- eip-aggregator/pom.xml | 2 +- eip-message-channel/pom.xml | 2 +- eip-publish-subscribe/pom.xml | 2 +- eip-splitter/pom.xml | 2 +- eip-wire-tap/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- event-queue/pom.xml | 2 +- event-sourcing/pom.xml | 2 +- execute-around/pom.xml | 2 +- extension-objects/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- filterer/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- game-loop/pom.xml | 2 +- guarded-suspension/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- leader-election/pom.xml | 2 +- leader-followers/pom.xml | 2 +- marker/pom.xml | 2 +- master-worker-pattern/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- page-object/sample-application/pom.xml | 2 +- page-object/test-automation/pom.xml | 2 +- partial-response/pom.xml | 2 +- pipeline/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- priority-queue/pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- retry/pom.xml | 2 +- role-object/pom.xml | 2 +- saga/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- serverless/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- sharding/pom.xml | 2 +- singleton/pom.xml | 2 +- spatial-partition/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strangler/pom.xml | 2 +- strategy/pom.xml | 2 +- subclass-sandbox/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- throttling/pom.xml | 2 +- tls/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- trampoline/pom.xml | 2 +- transaction-script/pom.xml | 2 +- twin/pom.xml | 2 +- typeobjectpattern/pom.xml | 2 +- unit-of-work/pom.xml | 2 +- update-method/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 145 files changed, 149 insertions(+), 149 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index a285e2d82..15e7cc54d 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -21,7 +21,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index 4fe0b58cd..2328c60a8 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT abstract-factory diff --git a/acyclic-visitor/pom.xml b/acyclic-visitor/pom.xml index 41a126d27..8c53b8750 100644 --- a/acyclic-visitor/pom.xml +++ b/acyclic-visitor/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT acyclic-visitor diff --git a/adapter/pom.xml b/adapter/pom.xml index 2cd449c06..a4d8d7b12 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 8f1e2ad06..b7c2bac66 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -20,7 +20,7 @@ aggregator-microservices com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 aggregator-service diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index bde50bd98..71935757f 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -20,7 +20,7 @@ aggregator-microservices com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index 76d506ed1..6c2726a35 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -20,7 +20,7 @@ aggregator-microservices com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 inventory-microservice diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index e6bf655f7..9e66e9be0 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 aggregator-microservices diff --git a/ambassador/pom.xml b/ambassador/pom.xml index 33f623457..0e5e208d5 100644 --- a/ambassador/pom.xml +++ b/ambassador/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 ambassador diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 08c7d47dc..c5ca117b6 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index ba055bd71..821857449 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 image-microservice diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 0edcbc83a..8ed569412 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 6b61ff2e5..dc3591bf3 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/arrange-act-assert/pom.xml b/arrange-act-assert/pom.xml index c00660b01..4b0d57ebf 100644 --- a/arrange-act-assert/pom.xml +++ b/arrange-act-assert/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 32adc0508..b4f7dd670 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT async-method-invocation diff --git a/balking/pom.xml b/balking/pom.xml index 6d789244c..0a86bc430 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/bridge/pom.xml b/bridge/pom.xml index ae50aba2e..41271814c 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT bridge diff --git a/builder/pom.xml b/builder/pom.xml index 069f6f841..6aa467f9e 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 9f7e3ea70..a46e856a9 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -22,7 +22,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT business-delegate diff --git a/bytecode/pom.xml b/bytecode/pom.xml index cfae54ad1..d21064be4 100644 --- a/bytecode/pom.xml +++ b/bytecode/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/caching/pom.xml b/caching/pom.xml index 82e7546f5..627f76e98 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT caching diff --git a/callback/pom.xml b/callback/pom.xml index a493c2cab..a74b653e1 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT callback diff --git a/chain/pom.xml b/chain/pom.xml index 40966eebf..9a7097e6d 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT chain diff --git a/circuit-breaker/pom.xml b/circuit-breaker/pom.xml index 4df9aacd3..083c527fa 100644 --- a/circuit-breaker/pom.xml +++ b/circuit-breaker/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT circuit-breaker diff --git a/collection-pipeline/pom.xml b/collection-pipeline/pom.xml index e8de7ff33..08c41880b 100644 --- a/collection-pipeline/pom.xml +++ b/collection-pipeline/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT collection-pipeline diff --git a/combinator/pom.xml b/combinator/pom.xml index 62c6a6658..4886873cd 100644 --- a/combinator/pom.xml +++ b/combinator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT combinator diff --git a/command/pom.xml b/command/pom.xml index 557f2cd89..3869d4b44 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT command diff --git a/commander/pom.xml b/commander/pom.xml index 8b87442ae..baabc04fc 100644 --- a/commander/pom.xml +++ b/commander/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT commander diff --git a/composite/pom.xml b/composite/pom.xml index 5e41920d7..6f7147482 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT composite diff --git a/converter/pom.xml b/converter/pom.xml index b19db2bae..1bed5e973 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -20,7 +20,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT converter 4.0.0 diff --git a/cqrs/pom.xml b/cqrs/pom.xml index 57570fff4..1838ed599 100644 --- a/cqrs/pom.xml +++ b/cqrs/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT cqrs diff --git a/dao/pom.xml b/dao/pom.xml index ead5e030f..32e9ef1ff 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT dao diff --git a/data-bus/pom.xml b/data-bus/pom.xml index cc3553336..4db738307 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -33,7 +33,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT data-bus diff --git a/data-locality/pom.xml b/data-locality/pom.xml index f14676b45..88fd96c64 100644 --- a/data-locality/pom.xml +++ b/data-locality/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT data-locality diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 45221020b..cf17de69b 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT data-mapper diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml index d51b62d2c..2529b3756 100644 --- a/data-transfer-object/pom.xml +++ b/data-transfer-object/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT data-transfer-object diff --git a/decorator/pom.xml b/decorator/pom.xml index 1209d5efb..b075704c8 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index 8ff7c6617..d7ad81362 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 85e8cdd1c..f3aaba520 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT dependency-injection diff --git a/dirty-flag/pom.xml b/dirty-flag/pom.xml index 3908dca36..b796ab37a 100644 --- a/dirty-flag/pom.xml +++ b/dirty-flag/pom.xml @@ -29,10 +29,10 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT dirty-flag - 1.23.0 + 1.24.0-SNAPSHOT dirty-flag http://maven.apache.org diff --git a/double-buffer/pom.xml b/double-buffer/pom.xml index e2e649fa9..cc4032074 100644 --- a/double-buffer/pom.xml +++ b/double-buffer/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index de8d27a4e..04aba2260 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index 67febf5bb..275b505a5 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT double-dispatch diff --git a/eip-aggregator/pom.xml b/eip-aggregator/pom.xml index c77dded15..efee153a3 100644 --- a/eip-aggregator/pom.xml +++ b/eip-aggregator/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT diff --git a/eip-message-channel/pom.xml b/eip-message-channel/pom.xml index 02db57903..12fe153e3 100644 --- a/eip-message-channel/pom.xml +++ b/eip-message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT eip-message-channel diff --git a/eip-publish-subscribe/pom.xml b/eip-publish-subscribe/pom.xml index ab98cf76a..f354b1ee3 100644 --- a/eip-publish-subscribe/pom.xml +++ b/eip-publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT eip-publish-subscribe diff --git a/eip-splitter/pom.xml b/eip-splitter/pom.xml index d1bc7f9c6..5b4758a9e 100644 --- a/eip-splitter/pom.xml +++ b/eip-splitter/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT diff --git a/eip-wire-tap/pom.xml b/eip-wire-tap/pom.xml index 2b122a64e..332861547 100644 --- a/eip-wire-tap/pom.xml +++ b/eip-wire-tap/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 1f3896ff3..813521c48 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index ccbda1f0a..06921a100 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index b9da44c6f..c40a8821b 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT event-driven-architecture diff --git a/event-queue/pom.xml b/event-queue/pom.xml index 1a93f9dad..232b9abaa 100644 --- a/event-queue/pom.xml +++ b/event-queue/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT event-queue diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml index 486f6d9e0..44af5fc5e 100644 --- a/event-sourcing/pom.xml +++ b/event-sourcing/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT event-sourcing diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 65b98a10f..2d0640fe0 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT execute-around diff --git a/extension-objects/pom.xml b/extension-objects/pom.xml index f6463e35f..7247a9676 100644 --- a/extension-objects/pom.xml +++ b/extension-objects/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/facade/pom.xml b/facade/pom.xml index 3847f8cbb..cf73e6a43 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index 521e6340f..987bbdb24 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index 8038a1ff9..c49fae691 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index a44eae026..1818d882d 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/filterer/pom.xml b/filterer/pom.xml index e64ac9846..46042c1b0 100644 --- a/filterer/pom.xml +++ b/filterer/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index 28e573258..138dbfa12 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index 00435f835..14f4f5557 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index 574f5b516..b9ffd42ae 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index 447e341fd..a90029a82 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT front-controller diff --git a/game-loop/pom.xml b/game-loop/pom.xml index 33a671449..6935c1fd1 100644 --- a/game-loop/pom.xml +++ b/game-loop/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index 81cf96084..f1bd31c66 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT jar guarded-suspension diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index e101a849c..635b76172 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index 3a932749b..f51825d5f 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index 59f82325a..d8ee9985f 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index d2d538c24..d32c80839 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 1d4faf770..bca091f11 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT iterator diff --git a/layers/pom.xml b/layers/pom.xml index d4b218272..9c299d2ba 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index 1bfe3b637..49421edc2 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT lazy-loading diff --git a/leader-election/pom.xml b/leader-election/pom.xml index b61041502..78ad13e4d 100644 --- a/leader-election/pom.xml +++ b/leader-election/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT leader-election diff --git a/leader-followers/pom.xml b/leader-followers/pom.xml index 2e5789acc..42e552ac8 100644 --- a/leader-followers/pom.xml +++ b/leader-followers/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT leader-followers diff --git a/marker/pom.xml b/marker/pom.xml index 2e2ec74b5..64b7243f3 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/master-worker-pattern/pom.xml b/master-worker-pattern/pom.xml index 54a72da69..c6bc2facf 100644 --- a/master-worker-pattern/pom.xml +++ b/master-worker-pattern/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT master-worker-pattern diff --git a/mediator/pom.xml b/mediator/pom.xml index ffae20778..ae802a349 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT mediator diff --git a/memento/pom.xml b/memento/pom.xml index 265825ccb..596883819 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT memento diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 6e2e062d8..98c9dddfe 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 363dfd78c..ee309f292 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT model-view-presenter model-view-presenter diff --git a/module/pom.xml b/module/pom.xml index 4768ffcef..2dc3fe340 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT module diff --git a/monad/pom.xml b/monad/pom.xml index e74ee83eb..2c21a28b3 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT monad diff --git a/monostate/pom.xml b/monostate/pom.xml index f00f7a677..02e271931 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index 8bb51845f..d1e4d50d5 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index 0d24529fa..2bf95f070 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index c08862948..84455abb1 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 41cbd8571..1b1eb2266 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0 + 1.24.0-SNAPSHOT naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index 869af61f3..a918e20de 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0 + 1.24.0-SNAPSHOT naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index f43b99197..b9482b292 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0 + 1.24.0-SNAPSHOT naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index 0fc95946c..e8b9b79c5 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT naked-objects pom @@ -333,17 +333,17 @@ ${project.groupId} naked-objects-dom - 1.23.0 + 1.24.0-SNAPSHOT ${project.groupId} naked-objects-fixture - 1.23.0 + 1.24.0-SNAPSHOT ${project.groupId} naked-objects-webapp - 1.23.0 + 1.24.0-SNAPSHOT diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 86960a5fb..3a817f9e2 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -30,7 +30,7 @@ com.iluwatar naked-objects - 1.23.0 + 1.24.0-SNAPSHOT naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index e91b06f74..4317ee36a 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT null-object diff --git a/object-mother/pom.xml b/object-mother/pom.xml index 07d724e76..f9ca156ad 100644 --- a/object-mother/pom.xml +++ b/object-mother/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT object-mother diff --git a/object-pool/pom.xml b/object-pool/pom.xml index ed3f87a0d..0587c3968 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT object-pool diff --git a/observer/pom.xml b/observer/pom.xml index e971c5602..c558992ac 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT observer diff --git a/page-object/pom.xml b/page-object/pom.xml index 6c1066fce..a91843121 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -46,7 +46,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT page-object pom diff --git a/page-object/sample-application/pom.xml b/page-object/sample-application/pom.xml index c715418d5..6748a4063 100644 --- a/page-object/sample-application/pom.xml +++ b/page-object/sample-application/pom.xml @@ -29,7 +29,7 @@ page-object com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT sample-application diff --git a/page-object/test-automation/pom.xml b/page-object/test-automation/pom.xml index f2ca98689..5f64807de 100644 --- a/page-object/test-automation/pom.xml +++ b/page-object/test-automation/pom.xml @@ -29,7 +29,7 @@ page-object com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT test-automation diff --git a/partial-response/pom.xml b/partial-response/pom.xml index a4788e5d1..fbece028e 100644 --- a/partial-response/pom.xml +++ b/partial-response/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/pipeline/pom.xml b/pipeline/pom.xml index a29007cda..fca6180bc 100644 --- a/pipeline/pom.xml +++ b/pipeline/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT pipeline diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 38d12c6c7..c4780fe1b 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT poison-pill diff --git a/pom.xml b/pom.xml index 56c593574..56b955204 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT pom 2014-2019 diff --git a/priority-queue/pom.xml b/priority-queue/pom.xml index 338079a66..ff04a5359 100644 --- a/priority-queue/pom.xml +++ b/priority-queue/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index bc4eeff65..01d0149ea 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index 853eb68f8..4884ef728 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index ac0f66a43..6ef67edec 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT promise diff --git a/property/pom.xml b/property/pom.xml index e96371c9c..8746a60ac 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT property diff --git a/prototype/pom.xml b/prototype/pom.xml index 7fc26080a..220ed4521 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index 8d2749483..0e7707bf8 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT proxy diff --git a/queue-load-leveling/pom.xml b/queue-load-leveling/pom.xml index 8f9a785c9..817e6e3cc 100644 --- a/queue-load-leveling/pom.xml +++ b/queue-load-leveling/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT queue-load-leveling diff --git a/reactor/pom.xml b/reactor/pom.xml index 424c00db7..c25ed45ae 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index 10d49f6cc..37f70b435 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 5511c4fc3..694629efa 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index 80d34e3aa..34428033b 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT resource-acquisition-is-initialization diff --git a/retry/pom.xml b/retry/pom.xml index db59fa049..2f0b15bd2 100644 --- a/retry/pom.xml +++ b/retry/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT retry jar diff --git a/role-object/pom.xml b/role-object/pom.xml index 2b3e07be0..07becfc9b 100644 --- a/role-object/pom.xml +++ b/role-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT role-object diff --git a/saga/pom.xml b/saga/pom.xml index c83c8fb45..a3ae60ed8 100644 --- a/saga/pom.xml +++ b/saga/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT saga diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 0a2ac7aed..64fd44db6 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT semaphore diff --git a/servant/pom.xml b/servant/pom.xml index e8925cea9..c7b282c09 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT servant diff --git a/serverless/pom.xml b/serverless/pom.xml index c9d7ec71b..2880764ec 100644 --- a/serverless/pom.xml +++ b/serverless/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT diff --git a/service-layer/pom.xml b/service-layer/pom.xml index aaee48310..071cf0f49 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index ed2366ed0..2b0037eb8 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT service-locator diff --git a/sharding/pom.xml b/sharding/pom.xml index 61c15db5b..5f6c40ee5 100644 --- a/sharding/pom.xml +++ b/sharding/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/singleton/pom.xml b/singleton/pom.xml index 7b7686108..80a34ea86 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT singleton diff --git a/spatial-partition/pom.xml b/spatial-partition/pom.xml index 2f47d73d9..fe749b22b 100644 --- a/spatial-partition/pom.xml +++ b/spatial-partition/pom.xml @@ -46,7 +46,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT spatial-partition diff --git a/specification/pom.xml b/specification/pom.xml index d2945516b..1494ca305 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT specification diff --git a/state/pom.xml b/state/pom.xml index c53f3d797..a434dabe4 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 1de9b653d..de5763695 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT step-builder diff --git a/strangler/pom.xml b/strangler/pom.xml index ba85f7184..7cb2ff263 100644 --- a/strangler/pom.xml +++ b/strangler/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/strategy/pom.xml b/strategy/pom.xml index aad38f1ce..0f3b0e830 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT strategy diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index 144f099a3..780547e95 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/template-method/pom.xml b/template-method/pom.xml index 36a0d8550..cbf2ac156 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index abcb8a9f5..3727bd240 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT thread-pool diff --git a/throttling/pom.xml b/throttling/pom.xml index 77f911c24..ba2ca9c47 100644 --- a/throttling/pom.xml +++ b/throttling/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/tls/pom.xml b/tls/pom.xml index f6adc911f..54e911e40 100644 --- a/tls/pom.xml +++ b/tls/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT tls diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index 3324f75f0..6cc0ac283 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT tolerant-reader diff --git a/trampoline/pom.xml b/trampoline/pom.xml index c651b4f8b..fff117bf8 100644 --- a/trampoline/pom.xml +++ b/trampoline/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT trampoline diff --git a/transaction-script/pom.xml b/transaction-script/pom.xml index 081567c47..7a6f40219 100644 --- a/transaction-script/pom.xml +++ b/transaction-script/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/twin/pom.xml b/twin/pom.xml index 37c06bd20..b879ac593 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT twin diff --git a/typeobjectpattern/pom.xml b/typeobjectpattern/pom.xml index 32e252aea..03af8e78d 100644 --- a/typeobjectpattern/pom.xml +++ b/typeobjectpattern/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT typeobjectpattern diff --git a/unit-of-work/pom.xml b/unit-of-work/pom.xml index 730b7921b..1d57e138f 100644 --- a/unit-of-work/pom.xml +++ b/unit-of-work/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/update-method/pom.xml b/update-method/pom.xml index 2659d1e2c..3a60d433b 100644 --- a/update-method/pom.xml +++ b/update-method/pom.xml @@ -28,7 +28,7 @@ java-design-patterns com.iluwatar - 1.23.0 + 1.24.0-SNAPSHOT 4.0.0 diff --git a/value-object/pom.xml b/value-object/pom.xml index a2dd714de..dbbbccd01 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index dddb4d4e3..a08f6ee8c 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.23.0 + 1.24.0-SNAPSHOT visitor From 9dd46d7b4a4329d07956b263dd627272e25db707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 25 Aug 2020 21:42:42 +0300 Subject: [PATCH 040/254] Update README.md --- builder/README.md | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) 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 + ![alt text](./etc/builder.urm.png "Builder 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 From b07d33f332f2378e26b4191de42174fb7ba83468 Mon Sep 17 00:00:00 2001 From: Amit Garg Date: Wed, 26 Aug 2020 00:09:30 +0100 Subject: [PATCH 041/254] Upgrade Mockito version to latest --- pom.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 56b955204..6d779700f 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 1.4 2.24.0 19.0 - 1.10.19 + 3.5.6 2.22 4.0 3.12.1 @@ -206,6 +206,18 @@ + + net.bytebuddy + byte-buddy + 1.9.7 + test + + + net.bytebuddy + byte-buddy-agent + 1.9.7 + test + org.hibernate hibernate-core From 8983f9c11ce69f18661479ef40512bbab0c98bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 26 Aug 2020 21:54:44 +0300 Subject: [PATCH 042/254] Update README.md --- callback/README.md | 18 ++++++++++++------ callback/etc/callback.png | Bin 8577 -> 18256 bytes callback/etc/callback.urm.puml | 5 ----- 3 files changed, 12 insertions(+), 11 deletions(-) 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 + ![alt text](./etc/callback.png "Callback") ## 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 a81745871a642705dad3be5fe90fc7abacb7185c..7b499f79fcaa1484dcdd485668c14549eef79b6e 100644 GIT binary patch literal 18256 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 Peyvbb(N->dY!&ujDtTa# 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() From 7118ccafa95916267c2160cdaf12b4be95e1f6b2 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Fri, 28 Aug 2020 12:17:38 +0530 Subject: [PATCH 043/254] Update maven-ci.yml Removed if clause for building code in main codebase from the CI pipeline. --- .github/workflows/maven-ci.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 9281c0f3d..304953bc9 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -49,14 +49,10 @@ jobs: ${{ runner.os }}-maven- # Some tests need screen access - name: Install xvfb - run: sudo apt-get install xvfb + run: sudo apt-get install -y xvfb # SonarQube scan does not work for forked repositories # See https://jira.sonarsource.com/browse/MMF-1371 - - name: Build with Maven - if: github.ref != 'refs/heads/master' - run: xvfb-run mvn clean verify - name: Build with Maven and run SonarQube analysis - if: github.ref == 'refs/heads/master' run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar env: # These two env variables are needed for sonar analysis From 47e746c3bae4ebfd7a422b99f923458940067d58 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Fri, 28 Aug 2020 12:26:27 +0530 Subject: [PATCH 044/254] Update maven-pr-builder.yml removed the if checking block for building Pull Requests as this was redundant code. --- .github/workflows/maven-pr-builder.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 7e4f3670f..8ef817687 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -49,9 +49,8 @@ jobs: ${{ runner.os }}-maven- # Some tests need screen access - name: Install xvfb - run: sudo apt-get install xvfb + run: sudo apt-get install -y xvfb # SonarQube scan does not work for forked repositories # See https://jira.sonarsource.com/browse/MMF-1371 - name: Build with Maven - if: github.ref != 'refs/heads/master' run: xvfb-run mvn clean verify From 96c16a8f3a904c17f47856219b245e52df33c000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 11:29:30 +0300 Subject: [PATCH 045/254] Update README.md --- chain/README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) 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 + ![alt text](./etc/chain.urm.png "Chain of Responsibility 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 From a4f2d14848ae3f53cd3d6ed6bca9ea7cd0318ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 12:01:23 +0300 Subject: [PATCH 046/254] Update README.md --- circuit-breaker/README.md | 47 ++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 16 deletions(-) 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: ![alt text](./etc/ServiceDiagram.PNG "Service Diagram") -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. ![alt text](./etc/StateDiagram.PNG "State Diagram") -- 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 + ![alt text](./etc/circuit-breaker.urm.png "Circuit Breaker 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 From 8135dbecdba26c93aad9d40dbee67f2fadd63167 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sat, 29 Aug 2020 17:36:31 +0530 Subject: [PATCH 047/254] Update maven-ci.yml --- .github/workflows/maven-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 304953bc9..cb3b8e45c 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -50,7 +50,8 @@ jobs: # Some tests need screen access - name: Install xvfb run: sudo apt-get install -y xvfb - # SonarQube scan does not work for forked repositories + # The SonarQube analysis is only for the master branch of the main repository. + # SonarQube scan does not work for forked repositories try changing it to xvfb-run mvn clean verify # See https://jira.sonarsource.com/browse/MMF-1371 - name: Build with Maven and run SonarQube analysis run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar From 338c146c7888d368177c50808ea581bf3e42aa45 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sat, 29 Aug 2020 17:39:50 +0530 Subject: [PATCH 048/254] Update maven-pr-builder.yml --- .github/workflows/maven-pr-builder.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 8ef817687..0c6d624c2 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -50,7 +50,8 @@ jobs: # Some tests need screen access - name: Install xvfb run: sudo apt-get install -y xvfb - # SonarQube scan does not work for forked repositories + # This worflow is only for building Pull Requests, the master branch runs Sonar analysis on the main repository. + # SonarQube scan does not work for forked repositories. # See https://jira.sonarsource.com/browse/MMF-1371 - name: Build with Maven run: xvfb-run mvn clean verify From 675b2f14b22b042be0663f05afd7a56cfaf1b5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:10:59 +0300 Subject: [PATCH 049/254] Update README.md --- command/README.md | 72 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 21 deletions(-) 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 + ![alt text](./etc/command.png "Command") ## 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 From 2bb2134636dec894c828666e9bdc1920775883be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:17:15 +0300 Subject: [PATCH 050/254] Update README.md --- composite/README.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/composite/README.md b/composite/README.md index dad6fb5a5..b7aaa69df 100644 --- a/composite/README.md +++ b/composite/README.md @@ -9,15 +9,17 @@ tags: --- ## Intent -Compose objects into tree structures to represent part-whole -hierarchies. Composite lets clients treat individual objects and compositions -of objects uniformly. + +Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients +treat individual objects and compositions of objects uniformly. ## Explanation Real world example -> Every sentence is composed of words which are in turn composed of characters. Each of these objects is printable and they can have something printed before or after them like sentence always ends with full stop and word always has space before it +> Every sentence is composed of words which are in turn composed of characters. Each of these +> objects is printable and they can have something printed before or after them like sentence always +> ends with full stop and word always has space before it. In plain words @@ -25,11 +27,16 @@ In plain words Wikipedia says -> In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly. +> In software engineering, the composite pattern is a partitioning design pattern. The composite +> pattern describes that a group of objects is to be treated in the same way as a single instance of +> an object. The intent of a composite is to "compose" objects into tree structures to represent +> part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects +> and compositions uniformly. **Programmatic Example** -Taking our sentence example from above. Here we have the base class and different printable types +Taking our sentence example from above. Here we have the base class `LetterComposite` and the +different printable types `Letter`, `Word` and `Sentence`. ```java public abstract class LetterComposite { @@ -102,7 +109,7 @@ public class Sentence extends LetterComposite { } ``` -Then we have a messenger to carry messages +Then we have a messenger to carry messages: ```java public class Messenger { @@ -143,7 +150,7 @@ public class Messenger { } ``` -And then it can be used as +And then it can be used as: ```java var orcMessage = new Messenger().messageFromOrcs(); @@ -153,13 +160,16 @@ elfMessage.print(); // Much wind pours from your mouth. ``` ## Class diagram + ![alt text](./etc/composite.urm.png "Composite class diagram") ## Applicability + Use the Composite pattern when -* you want to represent part-whole hierarchies of objects -* you want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly +* You want to represent part-whole hierarchies of objects. +* You want clients to be able to ignore the difference between compositions of objects and +individual objects. Clients will treat all objects in the composite structure uniformly. ## Real world examples From e8b42bd135fbedf4816b1d5222a13dfbf0701ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:23:28 +0300 Subject: [PATCH 051/254] Update README.md --- converter/README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/converter/README.md b/converter/README.md index 3be8ce331..02b172149 100644 --- a/converter/README.md +++ b/converter/README.md @@ -9,16 +9,19 @@ tags: --- ## Intent -The purpose of the Converter Pattern is to provide a generic, common way of bidirectional + +The purpose of the Converter pattern is to provide a generic, common way of bidirectional conversion between corresponding types, allowing a clean implementation in which the types do not -need to be aware of each other. Moreover, the Converter Pattern introduces bidirectional collection +need to be aware of each other. Moreover, the Converter pattern introduces bidirectional collection mapping, reducing a boilerplate code to minimum. ## Explanation Real world example -> In real world applications it is often the case that database layer consists of entities that need to be mapped into DTOs for use on the business logic layer. Similar mapping is done for potentially huge amount of classes and we need a generic way to achieve this. +> In real world applications it is often the case that database layer consists of entities that need +> to be mapped into DTOs for use on the business logic layer. Similar mapping is done for +> potentially huge amount of classes and we need a generic way to achieve this. In plain words @@ -26,7 +29,8 @@ In plain words **Programmatic Example** -We need a generic solution for the mapping problem. To achieve this, let's introduce a generic converter. +We need a generic solution for the mapping problem. To achieve this, let's introduce a generic +converter. ```java public class Converter { @@ -77,7 +81,7 @@ public class UserConverter extends Converter { } ``` -Now mapping between User and UserDto becomes trivial. +Now mapping between `User` and `UserDto` becomes trivial. ```java var userConverter = new UserConverter(); @@ -86,14 +90,18 @@ var user = userConverter.convertFromDto(dtoUser); ``` ## Class diagram + ![alt text](./etc/converter.png "Converter Pattern") ## Applicability + Use the Converter Pattern in the following situations: -* When you have types that logically correspond which other and you need to convert entities between them -* When you want to provide different ways of types conversions depending on a context -* Whenever you introduce a DTO (Data transfer object), you will probably need to convert it into the domain equivalence +* When you have types that logically correspond with each other and you need to convert entities +between them. +* When you want to provide different ways of types conversions depending on the context. +* Whenever you introduce a DTO (Data transfer object), you will probably need to convert it into the +domain equivalence. ## Credits From 6373f7b115e570c0e075cc25eb1770ba41aeb2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:38:20 +0300 Subject: [PATCH 052/254] Update README.md --- dao/README.md | 248 ++++++++++---------------------------------------- 1 file changed, 47 insertions(+), 201 deletions(-) diff --git a/dao/README.md b/dao/README.md index 11e5f9ca3..29e64a74f 100644 --- a/dao/README.md +++ b/dao/README.md @@ -9,13 +9,15 @@ tags: --- ## Intent + Object provides an abstract interface to some type of database or other persistence mechanism. ## Explanation Real world example -> There's a set of customers that need to be persisted to database. Additionally we need the whole set of CRUD (create/read/update/delete) operations so we can operate on customers easily. +> There's a set of customers that need to be persisted to database. Additionally we need the whole +> set of CRUD (create/read/update/delete) operations so we can operate on customers easily. In plain words @@ -23,11 +25,12 @@ In plain words Wikipedia says -> In computer software, a data access object (DAO) is a pattern that provides an abstract interface to some type of database or other persistence mechanism. +> In computer software, a data access object (DAO) is a pattern that provides an abstract interface +> to some type of database or other persistence mechanism. **Programmatic Example** -Walking through our customers example, here's the basic Customer entity. +Walking through our customers example, here's the basic `Customer` entity. ```java public class Customer { @@ -41,60 +44,13 @@ public class Customer { this.firstName = firstName; this.lastName = lastName; } - - public int getId() { - return id; - } - - public void setId(final int id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(final String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(final String lastName) { - this.lastName = lastName; - } - - @Override - public String toString() { - return "Customer{" + "id=" + getId() + ", firstName='" + getFirstName() + '\'' + ", lastName='" - + getLastName() + '\'' + '}'; - } - - @Override - public boolean equals(final Object that) { - var isEqual = false; - if (this == that) { - isEqual = true; - } else if (that != null && getClass() == that.getClass()) { - final var customer = (Customer) that; - if (getId() == customer.getId()) { - isEqual = true; - } - } - return isEqual; - } - - @Override - public int hashCode() { - return getId(); - } + // getters and setters -> + ... } ``` -Here's the DAO interface and two different implementations for it. InMemoryCustomerDao keeps a simple map of customers -in memory while DBCustomerDao is the real RDBMS implementation. +Here's the `CustomerDao` interface and two different implementations for it. `InMemoryCustomerDao` +keeps a simple map of customers in memory while `DBCustomerDao` is the real RDBMS implementation. ```java public interface CustomerDao { @@ -114,35 +70,8 @@ public class InMemoryCustomerDao implements CustomerDao { private final Map idToCustomer = new HashMap<>(); - @Override - public Stream getAll() { - return idToCustomer.values().stream(); - } - - @Override - public Optional getById(final int id) { - return Optional.ofNullable(idToCustomer.get(id)); - } - - @Override - public boolean add(final Customer customer) { - if (getById(customer.getId()).isPresent()) { - return false; - } - - idToCustomer.put(customer.getId(), customer); - return true; - } - - @Override - public boolean update(final Customer customer) { - return idToCustomer.replace(customer.getId(), customer) != null; - } - - @Override - public boolean delete(final Customer customer) { - return idToCustomer.remove(customer.getId()) != null; - } + // implement the interface using the map + ... } public class DbCustomerDao implements CustomerDao { @@ -155,121 +84,8 @@ public class DbCustomerDao implements CustomerDao { this.dataSource = dataSource; } - @Override - public Stream getAll() throws Exception { - try { - var connection = getConnection(); - var statement = connection.prepareStatement("SELECT * FROM CUSTOMERS"); - var resultSet = statement.executeQuery(); - return StreamSupport.stream(new Spliterators.AbstractSpliterator(Long.MAX_VALUE, - Spliterator.ORDERED) { - - @Override - public boolean tryAdvance(Consumer action) { - try { - if (!resultSet.next()) { - return false; - } - action.accept(createCustomer(resultSet)); - return true; - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - }, false).onClose(() -> mutedClose(connection, statement, resultSet)); - } catch (SQLException e) { - throw new CustomException(e.getMessage(), e); - } - } - - private Connection getConnection() throws SQLException { - return dataSource.getConnection(); - } - - private void mutedClose(Connection connection, PreparedStatement statement, ResultSet resultSet) { - try { - resultSet.close(); - statement.close(); - connection.close(); - } catch (SQLException e) { - LOGGER.info("Exception thrown " + e.getMessage()); - } - } - - private Customer createCustomer(ResultSet resultSet) throws SQLException { - return new Customer(resultSet.getInt("ID"), - resultSet.getString("FNAME"), - resultSet.getString("LNAME")); - } - - @Override - public Optional getById(int id) throws Exception { - - ResultSet resultSet = null; - - try (var connection = getConnection(); - var statement = connection.prepareStatement("SELECT * FROM CUSTOMERS WHERE ID = ?")) { - - statement.setInt(1, id); - resultSet = statement.executeQuery(); - if (resultSet.next()) { - return Optional.of(createCustomer(resultSet)); - } else { - return Optional.empty(); - } - } catch (SQLException ex) { - throw new CustomException(ex.getMessage(), ex); - } finally { - if (resultSet != null) { - resultSet.close(); - } - } - } - - @Override - public boolean add(Customer customer) throws Exception { - if (getById(customer.getId()).isPresent()) { - return false; - } - - try (var connection = getConnection(); - var statement = connection.prepareStatement("INSERT INTO CUSTOMERS VALUES (?,?,?)")) { - statement.setInt(1, customer.getId()); - statement.setString(2, customer.getFirstName()); - statement.setString(3, customer.getLastName()); - statement.execute(); - return true; - } catch (SQLException ex) { - throw new CustomException(ex.getMessage(), ex); - } - } - - @Override - public boolean update(Customer customer) throws Exception { - try (var connection = getConnection(); - var statement = - connection - .prepareStatement("UPDATE CUSTOMERS SET FNAME = ?, LNAME = ? WHERE ID = ?")) { - statement.setString(1, customer.getFirstName()); - statement.setString(2, customer.getLastName()); - statement.setInt(3, customer.getId()); - return statement.executeUpdate() > 0; - } catch (SQLException ex) { - throw new CustomException(ex.getMessage(), ex); - } - } - - @Override - public boolean delete(Customer customer) throws Exception { - try (var connection = getConnection(); - var statement = connection.prepareStatement("DELETE FROM CUSTOMERS WHERE ID = ?")) { - statement.setInt(1, customer.getId()); - return statement.executeUpdate() > 0; - } catch (SQLException ex) { - throw new CustomException(ex.getMessage(), ex); - } - } -} + // implement the interface using the data source + ... ``` Finally here's how we use our DAO to manage customers. @@ -301,15 +117,45 @@ Finally here's how we use our DAO to manage customers. deleteSchema(dataSource); ``` +The program output: + +```java +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +customerDao.getCustomerById(2): Optional[Customer{id=2, firstName='Bob', lastName='Bobson'}] +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@7cef4e59 +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +Customer{id=4, firstName='Daniel', lastName='Danielson'} +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@2db0f6b2 +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +customerDao.getCustomerById(2): Optional[Customer{id=2, firstName='Bob', lastName='Bobson'}] +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@12c8a2c0 +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +Customer{id=4, firstName='Daniel', lastName='Danielson'} +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@6ec8211c +``` ## Class diagram + ![alt text](./etc/dao.png "Data Access Object") ## Applicability -Use the Data Access Object in any of the following situations -* when you want to consolidate how the data layer is accessed -* when you want to avoid writing multiple data retrieval/persistence layers +Use the Data Access Object in any of the following situations: + +* When you want to consolidate how the data layer is accessed. +* When you want to avoid writing multiple data retrieval/persistence layers. ## Credits From 8512c65aefb821e7a1d9631040a55c9c79601902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:42:46 +0300 Subject: [PATCH 053/254] Update README.md --- data-transfer-object/README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/data-transfer-object/README.md b/data-transfer-object/README.md index fd0ff1137..72e2e240e 100644 --- a/data-transfer-object/README.md +++ b/data-transfer-object/README.md @@ -9,13 +9,16 @@ tags: --- ## Intent -Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to remote server. + +Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to +remote server. ## Explanation Real world example -> We need to fetch information about customers from remote database. Instead of querying the attributes one at a time, we use DTOs to transfer all the relevant attributes in a single shot. +> We need to fetch information about customers from remote database. Instead of querying the +> attributes one at a time, we use DTOs to transfer all the relevant attributes in a single shot. In plain words @@ -23,16 +26,17 @@ In plain words Wikipedia says -> In the field of programming a data transfer object (DTO) is an object that carries data between processes. The -motivation for its use is that communication between processes is usually done resorting to remote interfaces -(e.g., web services), where each call is an expensive operation. Because the majority of the cost of each call is -related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an -object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by -one call only. +> In the field of programming a data transfer object (DTO) is an object that carries data between +> processes. The motivation for its use is that communication between processes is usually done +> resorting to remote interfaces (e.g. web services), where each call is an expensive operation. +> Because the majority of the cost of each call is related to the round-trip time between the client +> and the server, one way of reducing the number of calls is to use an object (the DTO) that +> aggregates the data that would have been transferred by the several calls, but that is served by +> one call only. **Programmatic Example** -Let's first introduce our simple customer DTO class. +Let's first introduce our simple `CustomerDTO` class. ```java public class CustomerDto { @@ -60,7 +64,7 @@ public class CustomerDto { } ``` -Customer resource class acts as the server for customer information. +`CustomerResource` class acts as the server for customer information. ```java public class CustomerResource { @@ -94,10 +98,12 @@ Now fetching customer information is easy since we have the DTOs. ``` ## Class diagram + ![alt text](./etc/data-transfer-object.urm.png "data-transfer-object") ## Applicability -Use the Data Transfer Object pattern when + +Use the Data Transfer Object pattern when: * The client is asking for multiple information. And the information is related. * When you want to boost the performance to get resources. From 2dd2cfb8cabbac1ecd72bb091f4e43b41f1b3cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:49:45 +0300 Subject: [PATCH 054/254] Update README.md --- decorator/README.md | 51 +++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/decorator/README.md b/decorator/README.md index 26dbd1803..7ac0bb94c 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -10,30 +10,39 @@ tags: --- ## Also known as + Wrapper ## Intent -Attach additional responsibilities to an object dynamically. -Decorators provide a flexible alternative to subclassing for extending -functionality. + +Attach additional responsibilities to an object dynamically. Decorators provide a flexible +alternative to subclassing for extending functionality. ## Explanation Real world example -> There is an angry troll living in the nearby hills. Usually it goes bare handed but sometimes it has a weapon. To arm the troll it's not necessary to create a new troll but to decorate it dynamically with a suitable weapon. +> There is an angry troll living in the nearby hills. Usually it goes bare handed but sometimes it +> has a weapon. To arm the troll it's not necessary to create a new troll but to decorate it +> dynamically with a suitable weapon. In plain words -> Decorator pattern lets you dynamically change the behavior of an object at run time by wrapping them in an object of a decorator class. +> Decorator pattern lets you dynamically change the behavior of an object at run time by wrapping +> them in an object of a decorator class. Wikipedia says -> In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. +> In object-oriented programming, the decorator pattern is a design pattern that allows behavior to +> be added to an individual object, either statically or dynamically, without affecting the behavior +> of other objects from the same class. The decorator pattern is often useful for adhering to the +> Single Responsibility Principle, as it allows functionality to be divided between classes with +> unique areas of concern. **Programmatic Example** -Let's take the troll example. First of all we have a simple troll implementing the troll interface +Let's take the troll example. First of all we have a `SimpleTroll` implementing the `Troll` +interface: ```java public interface Troll { @@ -63,7 +72,7 @@ public class SimpleTroll implements Troll { } ``` -Next we want to add club for the troll. We can do it dynamically by using a decorator +Next we want to add club for the troll. We can do it dynamically by using a decorator: ```java public class ClubbedTroll implements Troll { @@ -94,7 +103,7 @@ public class ClubbedTroll implements Troll { } ``` -Here's the troll in action +Here's the troll in action: ```java // simple troll @@ -108,20 +117,36 @@ clubbedTroll.attack(); // The troll tries to grab you! The troll swings at you w clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away! ``` +Program output: + +```java +The troll tries to grab you! +The troll shrieks in horror and runs away! +The troll tries to grab you! The troll swings at you with a club! +The troll shrieks in horror and runs away! +``` + ## Class diagram + ![alt text](./etc/decorator.urm.png "Decorator pattern class diagram") ## Applicability -Use Decorator -* To add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects -* For responsibilities that can be withdrawn -* When extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing +Decorator is used to: + +* Add responsibilities to individual objects dynamically and transparently, that is, without +affecting other objects. +* For responsibilities that can be withdrawn. +* When extension by subclassing is impractical. Sometimes a large number of independent extensions +are possible and would produce an explosion of subclasses to support every combination. Or a class +definition may be hidden or otherwise unavailable for subclassing. ## Tutorial + * [Decorator Pattern Tutorial](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example) ## Real world examples + * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) * [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) From 8afe4c314a462eef05f2c2b026eb8ae9e90bb014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 16:56:52 +0300 Subject: [PATCH 055/254] Update README.md --- dependency-injection/README.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/dependency-injection/README.md b/dependency-injection/README.md index b47c1d2f9..e5bf93387 100644 --- a/dependency-injection/README.md +++ b/dependency-injection/README.md @@ -9,15 +9,19 @@ tags: --- ## Intent -Dependency Injection is a software design pattern in which one or more dependencies (or services) are injected, or -passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates -the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and -to follow the inversion of control and single responsibility principles. + +Dependency Injection is a software design pattern in which one or more dependencies (or services) +are injected, or passed by reference, into a dependent object (or client) and are made part of the +client's state. The pattern separates the creation of a client's dependencies from its own behavior, +which allows program designs to be loosely coupled and to follow the inversion of control and single +responsibility principles. ## Explanation + Real world example -> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably. +> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want +> to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably. In plain words @@ -25,11 +29,12 @@ In plain words Wikipedia says -> In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies. +> In software engineering, dependency injection is a technique in which an object receives other +> objects that it depends on. These other objects are called dependencies. **Programmatic Example** -Let's first introduce the tobacco brands. +Let's first introduce the `Tobacco` interface and the concrete brands. ```java public abstract class Tobacco { @@ -52,7 +57,7 @@ public class OldTobyTobacco extends Tobacco { } ``` -Next here's the wizard class hierarchy. +Next here's the `Wizard` class hierarchy. ```java public interface Wizard { @@ -83,13 +88,15 @@ And lastly we can show how easy it is to give the old wizard any brand of tobacc ``` ## Class diagram + ![alt text](./etc/dependency-injection.png "Dependency Injection") ## Applicability -Use the Dependency Injection pattern when -* When you need to remove knowledge of concrete implementation from object -* To enable unit testing of classes in isolation using mock objects or stubs +Use the Dependency Injection pattern when: + +* When you need to remove knowledge of concrete implementation from object. +* To enable unit testing of classes in isolation using mock objects or stubs. ## Credits From f5886325ec8e07e994f4eeda8d7a4adb1e391f45 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sat, 29 Aug 2020 19:34:43 +0530 Subject: [PATCH 056/254] Update maven-ci.yml upgraded build server runtime from Ubuntu 18.04 to 20.04 LTS --- .github/workflows/maven-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index cb3b8e45c..19291fa41 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -33,7 +33,7 @@ on: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 From 1973d1bc63bc60727b5fdba0dda9070eb66f5cd9 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sat, 29 Aug 2020 19:35:20 +0530 Subject: [PATCH 057/254] Update maven-pr-builder.yml upgraded build server runtime from Ubuntu 18.04 to 20.04 LTS for the PR builder as well --- .github/workflows/maven-pr-builder.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 0c6d624c2..f970c0ee5 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -33,7 +33,7 @@ on: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 From c541176b3869000dffb595a84de09147ecad31e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 20:26:37 +0300 Subject: [PATCH 058/254] Update README.md --- execute-around/README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/execute-around/README.md b/execute-around/README.md index 2873aef9b..600e41196 100644 --- a/execute-around/README.md +++ b/execute-around/README.md @@ -9,15 +9,18 @@ tags: --- ## Intent -Execute Around idiom frees the user from certain actions that should always be executed before and after the business -method. A good example of this is resource allocation and deallocation leaving the user to specify only what to do with -the resource. + +Execute Around idiom frees the user from certain actions that should always be executed before and +after the business method. A good example of this is resource allocation and deallocation leaving +the user to specify only what to do with the resource. ## Explanation Real world example -> We need to provide a class that can be used to write text strings to files. To make it easy for the user we let our service class open and close the file automatically, the user only has to specify what is written into which file. +> We need to provide a class that can be used to write text strings to files. To make it easy for +> the user we let our service class open and close the file automatically, the user only has to +> specify what is written into which file. In plain words @@ -25,7 +28,9 @@ In plain words [Stack Overflow](https://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom) says -> Basically it's the pattern where you write a method to do things which are always required, e.g. resource allocation and clean-up, and make the caller pass in "what we want to do with the resource". +> Basically it's the pattern where you write a method to do things which are always required, e.g. +> resource allocation and clean-up, and make the caller pass in "what we want to do with the +> resource". **Programmatic Example** @@ -61,12 +66,15 @@ To utilize the file writer the following code is needed. ``` ## Class diagram + ![alt text](./etc/execute-around.png "Execute Around") ## Applicability + Use the Execute Around idiom when -* you use an API that requires methods to be called in pairs such as open/close or allocate/deallocate. +* You use an API that requires methods to be called in pairs such as open/close or +allocate/deallocate. ## Credits From 0ee03db4d0b0fa6061d6147b2ce1432c245e8539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 20:38:04 +0300 Subject: [PATCH 059/254] Update README.md --- facade/README.md | 53 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/facade/README.md b/facade/README.md index ce9d892b6..f6765e325 100644 --- a/facade/README.md +++ b/facade/README.md @@ -10,14 +10,18 @@ tags: --- ## Intent -Provide a unified interface to a set of interfaces in a subsystem. -Facade defines a higher-level interface that makes the subsystem easier to use. + +Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level +interface that makes the subsystem easier to use. ## Explanation Real world example -> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you believe because you are using a simple interface that goldmine provides on the outside, internally it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a facade. +> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you +> believe because you are using a simple interface that goldmine provides on the outside, internally +> it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a +> facade. In plain words @@ -25,11 +29,13 @@ In plain words Wikipedia says -> A facade is an object that provides a simplified interface to a larger body of code, such as a class library. +> A facade is an object that provides a simplified interface to a larger body of code, such as a +> class library. **Programmatic Example** -Taking our goldmine example from above. Here we have the dwarven mine worker hierarchy +Let's take our goldmine example from above. Here we have the dwarven mine worker hierarchy. First +there's a base class `DwarvenMineWorker`: ```java public abstract class DwarvenMineWorker { @@ -87,7 +93,12 @@ public abstract class DwarvenMineWorker { GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK } } +``` +Then we have the concrete dwarf classes `DwarvenTunnelDigger`, `DwarvenGoldDigger` and +`DwarvenCartOperator`: + +```java public class DwarvenTunnelDigger extends DwarvenMineWorker { private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class); @@ -135,7 +146,7 @@ public class DwarvenCartOperator extends DwarvenMineWorker { ``` -To operate all these goldmine workers we have the facade +To operate all these goldmine workers we have the `DwarvenGoldmineFacade`: ```java public class DwarvenGoldmineFacade { @@ -168,22 +179,27 @@ public class DwarvenGoldmineFacade { } ``` -Now to use the facade +Now let's use the facade: ```java -DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade(); +var facade = new DwarvenGoldmineFacade(); facade.startNewDay(); +facade.digOutGold(); +facade.endDay(); +``` + +Program output: + +```java // Dwarf gold digger wakes up. // Dwarf gold digger goes to the mine. // Dwarf cart operator wakes up. // Dwarf cart operator goes to the mine. // Dwarven tunnel digger wakes up. // Dwarven tunnel digger goes to the mine. -facade.digOutGold(); // Dwarf gold digger digs for gold. // Dwarf cart operator moves gold chunks out of the mine. // Dwarven tunnel digger creates another promising tunnel. -facade.endDay(); // Dwarf gold digger goes home. // Dwarf gold digger goes to sleep. // Dwarf cart operator goes home. @@ -193,14 +209,25 @@ facade.endDay(); ``` ## Class diagram + ![alt text](./etc/facade.urm.png "Facade pattern class diagram") ## Applicability + Use the Facade pattern when -* you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the subsystem more reusable and easier to customize, but it also becomes harder to use for clients that don't need to customize it. A facade can provide a simple default view of the subsystem that is good enough for most clients. Only clients needing more customizability will need to look beyond the facade. -* there are many dependencies between clients and the implementation classes of an abstraction. Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting subsystem independence and portability. -* you want to layer your subsystems. Use a facade to define an entry point to each subsystem level. If subsystems are dependent, then you can simplify the dependencies between them by making them communicate with each other solely through their facades. +* You want to provide a simple interface to a complex subsystem. Subsystems often get more complex +as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the +subsystem more reusable and easier to customize, but it also becomes harder to use for clients that +don't need to customize it. A facade can provide a simple default view of the subsystem that is good +enough for most clients. Only clients needing more customization will need to look beyond the +facade. +* There are many dependencies between clients and the implementation classes of an abstraction. +Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting +subsystem independence and portability. +* You want to layer your subsystems. Use a facade to define an entry point to each subsystem level. +If subsystems are dependent, then you can simplify the dependencies between them by making them +communicate with each other solely through their facades. ## Credits From b77a05f0fb09fdae94055c7d1506b4898e80985e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 20:46:40 +0300 Subject: [PATCH 060/254] Update README.md --- factory-method/README.md | 41 ++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/factory-method/README.md b/factory-method/README.md index 206388537..180ddb868 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -10,17 +10,20 @@ tags: --- ## Also known as + Virtual Constructor ## Intent -Define an interface for creating an object, but let subclasses -decide which class to instantiate. Factory Method lets a class defer -instantiation to subclasses. + +Define an interface for creating an object, but let subclasses decide which class to instantiate. +Factory Method lets a class defer instantiation to subclasses. ## Explanation + Real world example -> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. Depending on the customer at hand the right type of blacksmith is summoned. +> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. +> Depending on the customer at hand the right type of blacksmith is summoned. In plain words @@ -28,11 +31,16 @@ In plain words Wikipedia says -> In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor. +> In class-based programming, the factory method pattern is a creational pattern that uses factory +> methods to deal with the problem of creating objects without having to specify the exact class of +> the object that will be created. This is done by creating objects by calling a factory method +> — either specified in an interface and implemented by child classes, or implemented in a base +> class and optionally overridden by derived classes—rather than by calling a constructor. **Programmatic Example** -Taking our blacksmith example above. First of all we have a blacksmith interface and some implementations for it +Taking our blacksmith example above. First of all we have a `Blacksmith` interface and some +implementations for it: ```java public interface Blacksmith { @@ -52,24 +60,33 @@ public class OrcBlacksmith implements Blacksmith { } ``` -Now as the customers come the correct type of blacksmith is summoned and requested weapons are manufactured +When the customers come, the correct type of blacksmith is summoned and requested weapons are +manufactured: ```java var blacksmith = new ElfBlacksmith(); blacksmith.manufactureWeapon(WeaponType.SPEAR); blacksmith.manufactureWeapon(WeaponType.AXE); -// Elvish weapons are created +``` + +Program output: +```java +// Elven spear +// Elven axe ``` ## Class diagram + ![alt text](./etc/factory-method.urm.png "Factory Method pattern class diagram") ## Applicability -Use the Factory Method pattern when -* a class can't anticipate the class of objects it must create -* a class wants its subclasses to specify the objects it creates -* classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate +Use the Factory Method pattern when: + +* Class cannot anticipate the class of objects it must create. +* Class wants its subclasses to specify the objects it creates. +* Classes delegate responsibility to one of several helper subclasses, and you want to localize the +knowledge of which helper subclass is the delegate. ## Real world examples From 1fbef60f37dea69764ed665d2b28e099bc31afef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:00:17 +0300 Subject: [PATCH 061/254] Update README.md --- fluentinterface/README.md | 48 +++++++++++-------- .../com/iluwatar/fluentinterface/app/App.java | 2 - .../lazy/LazyFluentIterable.java | 16 +++---- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/fluentinterface/README.md b/fluentinterface/README.md index 61c5f2eb5..8b3f80fae 100644 --- a/fluentinterface/README.md +++ b/fluentinterface/README.md @@ -9,23 +9,25 @@ tags: --- ## Intent -A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using -this pattern results in code that can be read nearly as human language. + +A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific +language. Using this pattern results in code that can be read nearly as human language. ## Explanation -The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those interfaces tend -to mimic domain specific languages, so they can nearly be read as human languages. +The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those +interfaces tend to mimic domain specific languages, so they can nearly be read as human languages. A fluent interface can be implemented using any of - * Method Chaining - calling a method returns some object on which further methods can be called. - * Static Factory Methods and Imports + * Method chaining - calling a method returns some object on which further methods can be called. + * Static factory methods and imports. * Named parameters - can be simulated in Java using static factory methods. Real world example -> We need to select numbers based on different criteria from the list. It's a great chance to utilize fluent interface pattern to provide readable easy-to-use developer experience. +> We need to select numbers based on different criteria from the list. It's a great chance to +> utilize fluent interface pattern to provide readable easy-to-use developer experience. In plain words @@ -33,7 +35,9 @@ In plain words Wikipedia says -> In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL). +> In software engineering, a fluent interface is an object-oriented API whose design relies +> extensively on method chaining. Its goal is to increase code legibility by creating a +> domain-specific language (DSL). **Programmatic Example** @@ -134,29 +138,35 @@ result is printed afterwards. .first(2) .last() .ifPresent(number -> LOGGER.info("Last amongst first two negatives: {}", number)); - - // The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68. - // The first three negative values are: -61, -22, -87. - // The last two positive values are: 23, 2. - // The first even number is: 14 - // A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68]. - // The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6]. - // Last amongst first two negatives: -22 +``` + +Program output: + +```java +The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68. +The first three negative values are: -61, -22, -87. +The last two positive values are: 23, 2. +The first even number is: 14 +A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68]. +The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6]. +Last amongst first two negatives: -22 ``` ## Class diagram + ![Fluent Interface](./etc/fluentinterface.png "Fluent Interface") ## Applicability + Use the Fluent Interface pattern when -* You provide an API that would benefit from a DSL-like usage -* You have objects that are difficult to configure or use +* You provide an API that would benefit from a DSL-like usage. +* You have objects that are difficult to configure or use. ## Known uses * [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html) -* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained) +* [Google Guava FluentIterable](https://github.com/google/guava/wiki/FunctionalExplained) * [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/) * [Mockito](http://mockito.org/) * [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial) diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java index 09513163c..0222fc54a 100644 --- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java @@ -23,8 +23,6 @@ package com.iluwatar.fluentinterface.app; -import static java.lang.String.valueOf; - import com.iluwatar.fluentinterface.fluentiterable.FluentIterable; import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable; import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable; diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java index 966f35287..517e6b778 100644 --- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java @@ -70,7 +70,7 @@ public class LazyFluentIterable implements FluentIterable { return new LazyFluentIterable<>() { @Override public Iterator iterator() { - return new DecoratingIterator(iterable.iterator()) { + return new DecoratingIterator<>(iterable.iterator()) { @Override public E computeNext() { while (fromIterator.hasNext()) { @@ -107,10 +107,10 @@ public class LazyFluentIterable implements FluentIterable { */ @Override public FluentIterable first(int count) { - return new LazyFluentIterable() { + return new LazyFluentIterable<>() { @Override public Iterator iterator() { - return new DecoratingIterator(iterable.iterator()) { + return new DecoratingIterator<>(iterable.iterator()) { int currentIndex; @Override @@ -149,10 +149,10 @@ public class LazyFluentIterable implements FluentIterable { */ @Override public FluentIterable last(int count) { - return new LazyFluentIterable() { + return new LazyFluentIterable<>() { @Override public Iterator iterator() { - return new DecoratingIterator(iterable.iterator()) { + return new DecoratingIterator<>(iterable.iterator()) { private int stopIndex; private int totalElementsCount; private List list; @@ -194,10 +194,10 @@ public class LazyFluentIterable implements FluentIterable { */ @Override public FluentIterable map(Function function) { - return new LazyFluentIterable() { + return new LazyFluentIterable<>() { @Override public Iterator iterator() { - return new DecoratingIterator(null) { + return new DecoratingIterator<>(null) { final Iterator oldTypeIterator = iterable.iterator(); @Override @@ -226,7 +226,7 @@ public class LazyFluentIterable implements FluentIterable { @Override public Iterator iterator() { - return new DecoratingIterator(iterable.iterator()) { + return new DecoratingIterator<>(iterable.iterator()) { @Override public E computeNext() { return fromIterator.hasNext() ? fromIterator.next() : null; From f3fd49870c6762682a1544654d9860587db29078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:05:30 +0300 Subject: [PATCH 062/254] Update README.md --- flyweight/README.md | 53 +++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/flyweight/README.md b/flyweight/README.md index 7b52ef800..fbefd3740 100644 --- a/flyweight/README.md +++ b/flyweight/README.md @@ -10,25 +10,32 @@ tags: --- ## Intent -Use sharing to support large numbers of fine-grained objects -efficiently. + +Use sharing to support large numbers of fine-grained objects efficiently. ## Explanation + Real world example -> Alchemist's shop has shelves full of magic potions. Many of the potions are the same so there is no need to create new object for each of them. Instead one object instance can represent multiple shelf items so memory footprint remains small. +> Alchemist's shop has shelves full of magic potions. Many of the potions are the same so there is +> no need to create new object for each of them. Instead one object instance can represent multiple +> shelf items so memory footprint remains small. In plain words -> It is used to minimize memory usage or computational expenses by sharing as much as possible with similar objects. +> It is used to minimize memory usage or computational expenses by sharing as much as possible with +> similar objects. Wikipedia says -> In computer programming, flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. +> In computer programming, flyweight is a software design pattern. A flyweight is an object that +> minimizes memory use by sharing as much data as possible with other similar objects; it is a way +> to use objects in large numbers when a simple repeated representation would use an unacceptable +> amount of memory. **Programmatic example** -Translating our alchemist shop example from above. First of all we have different potion types +Translating our alchemist shop example from above. First of all we have different potion types: ```java public interface Potion { @@ -60,7 +67,7 @@ public class InvisibilityPotion implements Potion { } ``` -Then the actual Flyweight object which is the factory for creating potions +Then the actual Flyweight class `PotionFactory`, which is the factory for creating potions. ```java public class PotionFactory { @@ -96,7 +103,7 @@ public class PotionFactory { } ``` -And it can be used as below +And it can be used as below: ```java var factory = new PotionFactory(); @@ -108,19 +115,33 @@ factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potio factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364) ``` +Program output: + +```java +You become invisible. (Potion=6566818) +You feel healed. (Potion=648129364) +You become invisible. (Potion=6566818) +You feel blessed. (Potion=1104106489) +You feel blessed. (Potion=1104106489) +You feel healed. (Potion=648129364) +``` + ## Class diagram + ![alt text](./etc/flyweight.urm.png "Flyweight pattern class diagram") ## Applicability -The Flyweight pattern's effectiveness depends heavily on how -and where it's used. Apply the Flyweight pattern when all of the following are -true -* an application uses a large number of objects -* storage costs are high because of the sheer quantity of objects -* most object state can be made extrinsic -* many groups of objects may be replaced by relatively few shared objects once extrinsic state is removed -* the application doesn't depend on object identity. Since flyweight objects may be shared, identity tests will return true for conceptually distinct objects. +The Flyweight pattern's effectiveness depends heavily on how and where it's used. Apply the +Flyweight pattern when all of the following are true: + +* An application uses a large number of objects. +* Storage costs are high because of the sheer quantity of objects. +* Most object state can be made extrinsic. +* Many groups of objects may be replaced by relatively few shared objects once extrinsic state is +removed. +* The application doesn't depend on object identity. Since flyweight objects may be shared, identity +tests will return true for conceptually distinct objects. ## Real world examples From 6606d6cd0883c7ad5b00dcdb7ec81181f02b7c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:21:01 +0300 Subject: [PATCH 063/254] Update README.md --- game-loop/README.md | 145 ++++++++++-------- .../java/com/iluwatar/gameloop/GameLoop.java | 4 +- 2 files changed, 84 insertions(+), 65 deletions(-) diff --git a/game-loop/README.md b/game-loop/README.md index 5f2cd9653..e967ff52d 100644 --- a/game-loop/README.md +++ b/game-loop/README.md @@ -8,31 +8,39 @@ tags: - Game programming --- -## Intent -A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates -the game state, and renders the game. It tracks the passage of time to control the rate of gameplay. +## Intent + +A game loop runs continuously during gameplay. Each turn of the loop, it processes user input +without blocking, updates the game state, and renders the game. It tracks the passage of time to +control the rate of gameplay. This pattern decouples progression of game time from user input and processor speed. -## Applicability +## Applicability + This pattern is used in every game engine. ## Explanation + Real world example -> Game loop is the main process of all the game rendering threads. It's present in all modern games. It drives input process, internal status update, rendering, AI and all the other processes. +> Game loop is the main process of all the game rendering threads. It's present in all modern games. +> It drives input process, internal status update, rendering, AI and all the other processes. In plain words -> Game Loop pattern ensures that game time progresses in equal speed in all different hardware setups. +> Game Loop pattern ensures that game time progresses in equal speed in all different hardware +> setups. Wikipedia says -> The central component of any game, from a programming standpoint, is the game loop. The game loop allows the game to run smoothly regardless of a user's input or lack thereof. +> The central component of any game, from a programming standpoint, is the game loop. The game loop +> allows the game to run smoothly regardless of a user's input, or lack thereof. **Programmatic Example** -Let's start with something simple. Here's a bullet that will move in our game. For demonstration it's enough that it has 1-dimensional position. +Let's start with something simple. Here's `Bullet` class. Bullets will move in our game. For +demonstration purposes it's enough that it has 1-dimensional position. ```java public class Bullet { @@ -53,7 +61,7 @@ public class Bullet { } ``` -GameController is responsible for moving objects in the game. Including the aforementioned bullet. +`GameController` is responsible for moving objects in the game, including the aforementioned bullet. ```java public class GameController { @@ -75,7 +83,8 @@ public class GameController { } ``` -Now we introduce the game loop. Or actually in this demo we have 3 different game loops. +Now we introduce the game loop. Or actually in this demo we have 3 different game loops. Let's see +the base class `GameLoop` first. ```java public enum GameStatus { @@ -100,7 +109,7 @@ public abstract class GameLoop { public void run() { status = GameStatus.RUNNING; - gameThread = new Thread(() -> processGameLoop()); + gameThread = new Thread(this::processGameLoop); gameThread.start(); } @@ -128,7 +137,11 @@ public abstract class GameLoop { protected abstract void processGameLoop(); } +``` +Here's the first game loop implementation, `FrameBasedGameLoop`: + +```java public class FrameBasedGameLoop extends GameLoop { @Override @@ -144,59 +157,9 @@ public class FrameBasedGameLoop extends GameLoop { controller.moveBullet(0.5f); } } - -public class VariableStepGameLoop extends GameLoop { - - @Override - protected void processGameLoop() { - var lastFrameTime = System.currentTimeMillis(); - while (isGameRunning()) { - processInput(); - var currentFrameTime = System.currentTimeMillis(); - var elapsedTime = currentFrameTime - lastFrameTime; - update(elapsedTime); - lastFrameTime = currentFrameTime; - render(); - } - } - - protected void update(Long elapsedTime) { - controller.moveBullet(0.5f * elapsedTime / 1000); - } -} - -public class FixedStepGameLoop extends GameLoop { - - private static final long MS_PER_FRAME = 20; - - @Override - protected void processGameLoop() { - var previousTime = System.currentTimeMillis(); - var lag = 0L; - while (isGameRunning()) { - var currentTime = System.currentTimeMillis(); - var elapsedTime = currentTime - previousTime; - previousTime = currentTime; - lag += elapsedTime; - - processInput(); - - while (lag >= MS_PER_FRAME) { - update(); - lag -= MS_PER_FRAME; - } - - render(); - } - } - - protected void update() { - controller.moveBullet(0.5f * MS_PER_FRAME / 1000); - } -} ``` -Finally we can show all these game loops in action. +Finally, we show all the game loops in action. ```java try { @@ -226,10 +189,66 @@ Finally we can show all these game loops in action. } ``` +Program output: + +```java +Start frame-based game loop: +Current bullet position: 0.5 +Current bullet position: 1.0 +Current bullet position: 1.5 +Current bullet position: 2.0 +Current bullet position: 2.5 +Current bullet position: 3.0 +Current bullet position: 3.5 +Current bullet position: 4.0 +Current bullet position: 4.5 +Current bullet position: 5.0 +Current bullet position: 5.5 +Current bullet position: 6.0 +Stop frame-based game loop. +Start variable-step game loop: +Current bullet position: 6.5 +Current bullet position: 0.038 +Current bullet position: 0.084 +Current bullet position: 0.145 +Current bullet position: 0.1805 +Current bullet position: 0.28 +Current bullet position: 0.32 +Current bullet position: 0.42549998 +Current bullet position: 0.52849996 +Current bullet position: 0.57799995 +Current bullet position: 0.63199997 +Current bullet position: 0.672 +Current bullet position: 0.778 +Current bullet position: 0.848 +Current bullet position: 0.8955 +Current bullet position: 0.9635 +Stop variable-step game loop. +Start fixed-step game loop: +Current bullet position: 0.0 +Current bullet position: 1.086 +Current bullet position: 0.059999995 +Current bullet position: 0.12999998 +Current bullet position: 0.24000004 +Current bullet position: 0.33999994 +Current bullet position: 0.36999992 +Current bullet position: 0.43999985 +Current bullet position: 0.5399998 +Current bullet position: 0.65999967 +Current bullet position: 0.68999964 +Current bullet position: 0.7299996 +Current bullet position: 0.79999954 +Current bullet position: 0.89999944 +Current bullet position: 0.98999935 +Stop variable-step game loop. +``` + ## Class diagram + ![alt text](./etc/game-loop.urm.png "Game Loop pattern class diagram") -## Credits +## Credits + * [Game Programming Patterns - Game Loop](http://gameprogrammingpatterns.com/game-loop.html) * [Game Programming Patterns](https://www.amazon.com/gp/product/0990582906/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0990582906&linkId=1289749a703b3fe0e24cd8d604d7c40b) * [Game Engine Architecture, Third Edition](https://www.amazon.com/gp/product/1138035459/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1138035459&linkId=94502746617211bc40e0ef49d29333ac) diff --git a/game-loop/src/main/java/com/iluwatar/gameloop/GameLoop.java b/game-loop/src/main/java/com/iluwatar/gameloop/GameLoop.java index cbb456ccf..5f47ef1dd 100644 --- a/game-loop/src/main/java/com/iluwatar/gameloop/GameLoop.java +++ b/game-loop/src/main/java/com/iluwatar/gameloop/GameLoop.java @@ -36,7 +36,7 @@ public abstract class GameLoop { protected volatile GameStatus status; - protected GameController controller; + protected final GameController controller; private Thread gameThread; @@ -53,7 +53,7 @@ public abstract class GameLoop { */ public void run() { status = GameStatus.RUNNING; - gameThread = new Thread(() -> processGameLoop()); + gameThread = new Thread(this::processGameLoop); gameThread.start(); } From bcca9beb4d650c447e6625d1820a55958f694426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:29:15 +0300 Subject: [PATCH 064/254] Update README.md --- iterator/README.md | 40 +++++++++++++------ .../main/java/com/iluwatar/iterator/App.java | 2 +- .../java/com/iluwatar/iterator/bst/README.md | 15 +++---- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/iterator/README.md b/iterator/README.md index a98010c5a..71ad807cd 100644 --- a/iterator/README.md +++ b/iterator/README.md @@ -9,29 +9,34 @@ tags: --- ## Also known as + Cursor ## Intent -Provide a way to access the elements of an aggregate object -sequentially without exposing its underlying representation. +Provide a way to access the elements of an aggregate object sequentially without exposing its +underlying representation. ## Explanation Real world example -> Treasure chest contains a set of magical items. There multiple types of items such as rings, potions and weapons. The items can be browsed by type using an iterator the treasure chest provides. +> Treasure chest contains a set of magical items. There multiple types of items such as rings, +> potions and weapons. The items can be browsed by type using an iterator the treasure chest +> provides. In plain words -> Containers can provide a representation agnostic iterator interface to provide access to the elements. +> Containers can provide a representation agnostic iterator interface to provide access to the +> elements. Wikipedia says -> In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. +> In object-oriented programming, the iterator pattern is a design pattern in which an iterator is +> used to traverse a container and access the container's elements. **Programmatic Example** -The main class in our example is the treasure chest that contains items. +The main class in our example is the `TreasureChest` that contains items. ```java public class TreasureChest { @@ -60,7 +65,11 @@ public class TreasureChest { return new ArrayList<>(items); } } +``` +Here's the `Item` class: + +```java public class Item { private ItemType type; @@ -92,7 +101,7 @@ public enum ItemType { } ``` -The iterator interface is extremely simple. +The `Iterator` interface is extremely simple. ```java public interface Iterator { @@ -110,19 +119,26 @@ var itemIterator = TREASURE_CHEST.iterator(ItemType.RING); while (itemIterator.hasNext()) { LOGGER.info(itemIterator.next().toString()); } -// Ring of shadows -// Ring of armor +``` + +Program output: + +```java +Ring of shadows +Ring of armor ``` ## Class diagram + ![alt text](./etc/iterator_1.png "Iterator") ## Applicability + Use the Iterator pattern -* to access an aggregate object's contents without exposing its internal representation -* to support multiple traversals of aggregate objects -* to provide a uniform interface for traversing different aggregate structures +* To access an aggregate object's contents without exposing its internal representation. +* To support multiple traversals of aggregate objects. +* To provide a uniform interface for traversing different aggregate structures. ## Real world examples diff --git a/iterator/src/main/java/com/iluwatar/iterator/App.java b/iterator/src/main/java/com/iluwatar/iterator/App.java index b81e765be..053b5c4fb 100644 --- a/iterator/src/main/java/com/iluwatar/iterator/App.java +++ b/iterator/src/main/java/com/iluwatar/iterator/App.java @@ -62,7 +62,7 @@ public class App { LOGGER.info("------------------------"); LOGGER.info("BST Iterator: "); var root = buildIntegerBst(); - var bstIterator = new BstIterator(root); + var bstIterator = new BstIterator<>(root); while (bstIterator.hasNext()) { LOGGER.info("Next node: " + bstIterator.next().getVal()); } diff --git a/iterator/src/main/java/com/iluwatar/iterator/bst/README.md b/iterator/src/main/java/com/iluwatar/iterator/bst/README.md index 816d1a4fe..07bcbf84f 100644 --- a/iterator/src/main/java/com/iluwatar/iterator/bst/README.md +++ b/iterator/src/main/java/com/iluwatar/iterator/bst/README.md @@ -1,8 +1,11 @@ # BSTIterator -An implementation of the Iterator design pattern, for the Binary Search Tree -data structure. A great explanation of BSTs can be found in this [video tutorial](https://www.youtube.com/watch?v=i_Q0v_Ct5lY). -### What it Does +An implementation of the Iterator design pattern, for the Binary Search Tree data structure. A great +explanation of BSTs can be found in this +[video tutorial](https://www.youtube.com/watch?v=i_Q0v_Ct5lY). + +### What It Does + This iterator assumes that the given binary search tree inserts nodes of smaller value to the left, and nodes of larger value to the right of current node. Accordingly, this iterator will return nodes according to "In Order" binary tree traversal. @@ -12,6 +15,7 @@ return values in order: 1, 3, 4, 6, 7, 8, 10, 13, 14. ![BST](../../../../../../../etc/bst.jpg "Binary Search Tree") ### How It's Done + **The trivial solution** to a binary search tree iterator would be to construct a List (or similar linear data structure) when you construct the BSTIterator. This would require traversing the entire BST, adding each node value to your list as you go. The downside to the trivial solution is twofold. @@ -80,7 +84,4 @@ In Big O terms, here are the costs for our improved solution, where h is the hei * Extra Space: O(h) As you can see, this solution more evenly distributes the work. It yields the same amortized -runtime for `next()`, reduces the run time of the constructor, and uses less extra space. - - - \ No newline at end of file +runtime for `next()`, reduces the run time of the constructor, and uses less extra space. From 3544a8366f5f961337f4bb623e477cee53e795c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:38:58 +0300 Subject: [PATCH 065/254] Update README.md --- layers/README.md | 33 ++++++++++++------- .../layers/service/CakeBakingServiceImpl.java | 24 ++++---------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/layers/README.md b/layers/README.md index 1e309f92b..d29ad40d0 100644 --- a/layers/README.md +++ b/layers/README.md @@ -10,26 +10,33 @@ tags: --- ## Intent -Layers is an architectural pattern where software responsibilities are - divided among the different layers of the application. + +Layers is an architectural pattern where software responsibilities are divided among the different +layers of the application. ## Explanation Real world example -> Consider a web site displaying decorated cakes for weddings and such. Instead of the web page directly reaching into the database, it relies on a service to deliver this information. The service then queries the data layer to assimilate the needed information. +> Consider a web site displaying decorated cakes for weddings and such. Instead of the web page +> directly reaching into the database, it relies on a service to deliver this information. The +> service then queries the data layer to assimilate the needed information. -In Plain Words +In plain words -> With Layers architectural pattern different concerns reside on separate layers. View layer is interested only in rendering, service layer assembles the requested data from various sources, and data layer gets the bits from the data storage. +> With Layers architectural pattern different concerns reside on separate layers. View layer is +> interested only in rendering, service layer assembles the requested data from various sources, and +> data layer gets the bits from the data storage. Wikipedia says -> In software engineering, multitier architecture (often referred to as n-tier architecture) or multilayered architecture is a client–server architecture in which presentation, application processing, and data management functions are physically separated. +> In software engineering, multitier architecture (often referred to as n-tier architecture) or +> multilayered architecture is a client–server architecture in which presentation, application +> processing, and data management functions are physically separated. **Programmatic Example** -On the data layer, we keep our cake building blocks. Cakes consist of layers and topping. +On the data layer, we keep our cake building blocks. `Cake` consist of layers and topping. ```java @Entity @@ -47,7 +54,7 @@ public class Cake { } ``` -The service layer offers CakeBakingService for easy access to different aspects of cakes. +The service layer offers `CakeBakingService` for easy access to different aspects of cakes. ```java public interface CakeBakingService { @@ -66,7 +73,7 @@ public interface CakeBakingService { } ``` -On the top we have our view responsible of rendering the cakes. +On the top we have our `View` responsible of rendering the cakes. ```java public interface View { @@ -92,14 +99,16 @@ public class CakeViewImpl implements View { ``` ## Class diagram + ![alt text](./etc/layers.png "Layers") ## Applicability + Use the Layers architecture when -* you want clearly divide software responsibilities into different parts of the program -* you want to prevent a change from propagating throughout the application -* you want to make your application more maintainable and testable +* You want clearly divide software responsibilities into different parts of the program. +* You want to prevent a change from propagating throughout the application. +* You want to make your application more maintainable and testable. ## Credits diff --git a/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java b/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java index 14fee4dfa..4694082fa 100644 --- a/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java +++ b/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java @@ -35,9 +35,7 @@ import com.iluwatar.layers.entity.CakeTopping; import com.iluwatar.layers.exception.CakeBakingException; import java.util.ArrayList; import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.springframework.context.support.AbstractApplicationContext; @@ -72,7 +70,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { Set foundLayers = new HashSet<>(); for (var info : cakeInfo.cakeLayerInfos) { var found = allLayers.stream().filter(layer -> layer.getName().equals(info.name)).findFirst(); - if (!found.isPresent()) { + if (found.isEmpty()) { throw new CakeBakingException(String.format("Layer %s is not available", info.name)); } else { foundLayers.add(found.get()); @@ -114,9 +112,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { private List getAvailableToppingEntities() { var bean = context.getBean(CakeToppingDao.class); List result = new ArrayList<>(); - var iterator = bean.findAll().iterator(); - while (iterator.hasNext()) { - var topping = iterator.next(); + for (CakeTopping topping : bean.findAll()) { if (topping.getCake() == null) { result.add(topping); } @@ -128,9 +124,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { public List getAvailableToppings() { var bean = context.getBean(CakeToppingDao.class); List result = new ArrayList<>(); - var iterator = bean.findAll().iterator(); - while (iterator.hasNext()) { - var next = iterator.next(); + for (CakeTopping next : bean.findAll()) { if (next.getCake() == null) { result.add(new CakeToppingInfo(next.getId(), next.getName(), next.getCalories())); } @@ -141,9 +135,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { private List getAvailableLayerEntities() { var bean = context.getBean(CakeLayerDao.class); List result = new ArrayList<>(); - var iterator = bean.findAll().iterator(); - while (iterator.hasNext()) { - var next = iterator.next(); + for (CakeLayer next : bean.findAll()) { if (next.getCake() == null) { result.add(next); } @@ -155,9 +147,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { public List getAvailableLayers() { var bean = context.getBean(CakeLayerDao.class); List result = new ArrayList<>(); - var iterator = bean.findAll().iterator(); - while (iterator.hasNext()) { - var next = iterator.next(); + for (CakeLayer next : bean.findAll()) { if (next.getCake() == null) { result.add(new CakeLayerInfo(next.getId(), next.getName(), next.getCalories())); } @@ -169,9 +159,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { public List getAllCakes() { var cakeBean = context.getBean(CakeDao.class); List result = new ArrayList<>(); - var iterator = cakeBean.findAll().iterator(); - while (iterator.hasNext()) { - var cake = iterator.next(); + for (Cake cake : cakeBean.findAll()) { var cakeToppingInfo = new CakeToppingInfo(cake.getTopping().getId(), cake.getTopping().getName(), cake .getTopping().getCalories()); From 74360a7ecba4f226b867fb00fd84804ed9972efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:51:32 +0300 Subject: [PATCH 066/254] Update README.md --- memento/README.md | 89 ++++++++----------- .../java/com/iluwatar/memento/StarType.java | 3 +- 2 files changed, 36 insertions(+), 56 deletions(-) diff --git a/memento/README.md b/memento/README.md index 8bbebd36a..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** @@ -38,23 +44,13 @@ public enum StarType { 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; - } + 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 { @@ -123,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 -> + ... } } ``` @@ -172,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 + ![alt text](./etc/memento.png "Memento") ## 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/src/main/java/com/iluwatar/memento/StarType.java b/memento/src/main/java/com/iluwatar/memento/StarType.java index aa92bf6e6..58fd935f2 100644 --- a/memento/src/main/java/com/iluwatar/memento/StarType.java +++ b/memento/src/main/java/com/iluwatar/memento/StarType.java @@ -31,8 +31,7 @@ public enum StarType { RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), - DEAD("dead star"), - UNDEFINED(""); + DEAD("dead star"); private final String title; From b5c6a89ec9a14d39ad8aafa149710dc83ab21619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 21:55:51 +0300 Subject: [PATCH 067/254] Update README.md --- multiton/README.md | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) 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 + ![alt text](./etc/multiton.png "Multiton") ## 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. From bc35911475259bf2955fa1440d1d657ba15b3e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 22:02:10 +0300 Subject: [PATCH 068/254] Update README.md --- null-object/README.md | 48 +++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/null-object/README.md b/null-object/README.md index f5d92a7fc..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,7 +142,6 @@ public final class NullNode implements Node { // Do nothing } } - ``` Then we can construct and traverse the binary tree without errors as follows. @@ -152,18 +158,24 @@ Then we can construct and traverse the binary tree without errors as follows. ) ); root.walk(); - - // 1 - // 11 - // 111 - // 12 - // 122 +``` + +Program output: + +``` +1 +11 +111 +12 +122 ``` ## Class diagram + ![alt text](./etc/null-object.png "Null Object") ## Applicability + Use the Null Object pattern when * You want to avoid explicit null checks and keep the algorithm elegant and easy to read. From 67d1d16e1f9f5af3eb21d44deed760b4aaca58b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Aug 2020 22:13:55 +0300 Subject: [PATCH 069/254] Update README.md --- object-pool/README.md | 44 +++++++++--- observer/README.md | 70 ++++++++++++------- .../iluwatar/observer/generic/Observable.java | 2 +- 3 files changed, 77 insertions(+), 39 deletions(-) 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 + ![alt text](./etc/object-pool.png "Object Pool") ## 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/observer/README.md b/observer/README.md index d0ddf3c00..cbde540ab 100644 --- a/observer/README.md +++ b/observer/README.md @@ -10,17 +10,21 @@ 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 @@ -28,11 +32,13 @@ In plain words 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 { @@ -58,11 +64,12 @@ public class Hobbits implements WeatherObserver { public void update(WeatherType currentWeather) { switch (currentWeather) { 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 { @@ -109,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 facing rainy weather now - // The hobbits are facing rainy weather now - weather.timePasses(); - // The weather changed to windy. - // The orcs are facing windy weather now - // The hobbits are facing windy weather now - weather.timePasses(); - // The weather changed to cold. - // The orcs are facing cold weather now - // The hobbits are facing cold weather now - weather.timePasses(); - // The weather changed to sunny. - // The orcs are facing sunny weather now - // The hobbits are facing sunny weather now +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 + ![alt text](./etc/observer.png "Observer") ## 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/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<>(); From b80b9354c6acaa7f581b54b982c07fad2b0fb165 Mon Sep 17 00:00:00 2001 From: Subhrodip Mohanta Date: Sun, 30 Aug 2020 02:31:06 +0530 Subject: [PATCH 070/254] Update maven-ci.yml --- .github/workflows/maven-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 19291fa41..9c9f4fad3 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -37,6 +37,9 @@ jobs: steps: - uses: actions/checkout@v2 + with: + # Disabling shallow clone for improving relevancy of SonarQube reporting + fetch-depth: 0 - name: Set up JDK 11 uses: actions/setup-java@v1 with: From 3c4ae6c4ca897d5f741d5741f454a010646b05ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 30 Aug 2020 19:17:45 +0300 Subject: [PATCH 071/254] Update README.md --- pipeline/README.md | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/pipeline/README.md b/pipeline/README.md index fd03cd7b9..d7f0f749b 100644 --- a/pipeline/README.md +++ b/pipeline/README.md @@ -9,19 +9,22 @@ tags: --- ## Intent -Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be -used by the next stages. + +Allows processing of data in a series of stages by giving in an initial input and passing the +processed output to be used by the next stages. ## Explanation -The Pipeline pattern uses ordered stages to process a sequence of input values. Each implemented task is represented by -a stage of the pipeline. You can think of pipelines as similar to assembly lines in a factory, where each item in the -assembly line is constructed in stages. The partially assembled item is passed from one assembly stage to another. The -outputs of the assembly line occur in the same order as that of the inputs. +The Pipeline pattern uses ordered stages to process a sequence of input values. Each implemented +task is represented by a stage of the pipeline. You can think of pipelines as similar to assembly +lines in a factory, where each item in the assembly line is constructed in stages. The partially +assembled item is passed from one assembly stage to another. The outputs of the assembly line occur +in the same order as that of the inputs. Real world example -> Suppose we wanted to pass through a string to a series of filtering stages and convert it as a char array on the last stage. +> Suppose we wanted to pass through a string to a series of filtering stages and convert it as a +> char array on the last stage. In plain words @@ -29,7 +32,9 @@ In plain words Wikipedia says -> In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline. +> In software engineering, a pipeline consists of a chain of processing elements (processes, +> threads, coroutines, functions, etc.), arranged so that the output of each element is the input +> of the next; the name is by analogy to a physical pipeline. **Programmatic Example** @@ -88,14 +93,17 @@ And here's the `Pipeline` in action processing the string. ``` ## Class diagram + ![alt text](./etc/pipeline.urm.png "Pipeline pattern class diagram") ## Applicability + Use the Pipeline pattern when you want to -* Execute individual stages that yields a final value -* Add readability to complex sequence of operations by providing a fluent builder as an interface -* Improve testability of code since stages will most likely be doing a single thing, complying to the [Single Responsibility Principle (SRP)](https://java-design-patterns.com/principles/#single-responsibility-principle) +* Execute individual stages that yields a final value. +* Add readability to complex sequence of operations by providing a fluent builder as an interface. +* Improve testability of code since stages will most likely be doing a single thing, complying to +the [Single Responsibility Principle (SRP)](https://java-design-patterns.com/principles/#single-responsibility-principle) ## Known uses From 9b71479d041fc303cc4cf6541b626c114ba6c44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 30 Aug 2020 19:34:10 +0300 Subject: [PATCH 072/254] Update README.md --- poison-pill/README.md | 104 +++++++++++++----------------------------- 1 file changed, 31 insertions(+), 73 deletions(-) diff --git a/poison-pill/README.md b/poison-pill/README.md index a6cd2fe80..05cd8c2a0 100644 --- a/poison-pill/README.md +++ b/poison-pill/README.md @@ -10,14 +10,17 @@ tags: --- ## Intent -Poison Pill is known predefined data item that allows to provide graceful shutdown for separate distributed consumption -process. + +Poison Pill is known predefined data item that allows to provide graceful shutdown for separate +distributed consumption process. ## Explanation Real world example -> Let's think about a message queue with one producer and one consumer. The producer keeps pushing new messages in the queue and the consumer keeps reading them. Finally when it's time to gracefully shut down the producer sends the poison pill message. +> Let's think about a message queue with one producer and one consumer. The producer keeps pushing +> new messages in the queue and the consumer keeps reading them. Finally when it's time to +> gracefully shut down the producer sends the poison pill message. In plain words @@ -25,43 +28,13 @@ In plain words **Programmatic Example** -Let's define the message structure first. +Let's define the message structure first. There's interface `Message` and implementation +`SimpleMessage`. ```java public interface Message { - Message POISON_PILL = new Message() { - - @Override - public void addHeader(Headers header, String value) { - throw poison(); - } - - @Override - public String getHeader(Headers header) { - throw poison(); - } - - @Override - public Map getHeaders() { - throw poison(); - } - - @Override - public void setBody(String body) { - throw poison(); - } - - @Override - public String getBody() { - throw poison(); - } - - private RuntimeException poison() { - return new UnsupportedOperationException("Poison"); - } - - }; + ... enum Headers { DATE, SENDER @@ -110,7 +83,9 @@ public class SimpleMessage implements Message { } ``` -Next we define the types related to the message queue. +To pass messages we are using message queues. Here we define the types related to the message queue: +`MqPublishPoint`, `MqSubscribePoint` and `MessageQueue`. `SimpleMessageQueue` implements all these +interfaces. ```java public interface MqPublishPoint { @@ -146,29 +121,15 @@ public class SimpleMessageQueue implements MessageQueue { } ``` -Now we need to create the message producer and consumer. +Next we need message `Producer` and `Consumer`. Internally they use the message queues from above. +It's important to notice that when `Producer` stops, it sends out the poison pill to inform +`Consumer` that the messaging has finished. ```java public class Producer { + + ... - private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class); - - private final MqPublishPoint queue; - private final String name; - private boolean isStopped; - - /** - * Constructor. - */ - public Producer(String name, MqPublishPoint queue) { - this.name = name; - this.queue = queue; - this.isStopped = false; - } - - /** - * Send message to queue. - */ public void send(String body) { if (isStopped) { throw new IllegalStateException(String.format( @@ -187,9 +148,6 @@ public class Producer { } } - /** - * Stop system by sending poison pill. - */ public void stop() { isStopped = true; try { @@ -203,19 +161,8 @@ public class Producer { public class Consumer { - private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); + ... - private final MqSubscribePoint queue; - private final String name; - - public Consumer(String name, MqSubscribePoint queue) { - this.name = name; - this.queue = queue; - } - - /** - * Consume message. - */ public void consume() { while (true) { try { @@ -255,13 +202,24 @@ Finally we are ready to present the whole example in action. }).start(); ``` +Program output: + +``` +Message [hand shake] from [PRODUCER_1] received by [CONSUMER_1] +Message [some very important information] from [PRODUCER_1] received by [CONSUMER_1] +Message [bye!] from [PRODUCER_1] received by [CONSUMER_1] +Consumer CONSUMER_1 receive request to terminate. +``` + ## Class diagram + ![alt text](./etc/poison-pill.png "Poison Pill") ## Applicability -Use the Poison Pill idiom when -* Need to send signal from one thread/process to another to terminate +Use the Poison Pill idiom when: + +* There's a need to send signal from one thread/process to another to terminate. ## Real world examples From 82842d614b0fb76c4adaeba7b69e656621dbbf0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 30 Aug 2020 20:08:34 +0300 Subject: [PATCH 073/254] Update README.md --- priority-queue/README.md | 192 +++++++++++++++++- .../iluwatar/priority/queue/Application.java | 7 +- .../iluwatar/priority/queue/QueueManager.java | 2 +- 3 files changed, 192 insertions(+), 9 deletions(-) diff --git a/priority-queue/README.md b/priority-queue/README.md index 924d7169f..8481915be 100644 --- a/priority-queue/README.md +++ b/priority-queue/README.md @@ -10,19 +10,203 @@ tags: --- ## Intent -Prioritize requests sent to services so that requests with a higher priority are received and processed more quickly than those of a lower priority. This pattern is useful in applications that offer different service level guarantees to individual clients. + +Prioritize requests sent to services so that requests with a higher priority are received and +processed more quickly than those of a lower priority. This pattern is useful in applications that +offer different service level guarantees to individual clients. ## Explanation -Applications may delegate specific tasks to other services; for example, to perform background processing or to integrate with other applications or services. In the cloud, a message queue is typically used to delegate tasks to background processing. In many cases the order in which requests are received by a service is not important. However, in some cases it may be necessary to prioritize specific requests. These requests should be processed earlier than others of a lower priority that may have been sent previously by the application. + +Applications may delegate specific tasks to other services; for example, to perform background +processing or to integrate with other applications or services. In the cloud, a message queue is +typically used to delegate tasks to background processing. In many cases the order in which requests +are received by a service is not important. However, in some cases it may be necessary to prioritize +specific requests. These requests should be processed earlier than others of a lower priority that +may have been sent previously by the application. + +Real world example + +> Imagine a video processing service with free and premium customers. The requests coming from the +> paying premium customers should be prioritized over the others. + +In plain words + +> Priority Queue enables processing of high priority messages first, regardless of queue size or +> message age. + +Wikipedia says + +> In computer science, a priority queue is an abstract data type similar to regular queue or stack +> data structure in which each element additionally has a "priority" associated with it. In a +> priority queue, an element with high priority is served before an element with low priority. + +**Programmatic Example** + +Looking at the video processing example from above, let's first see the `Message` structure. + +```java +public class Message implements Comparable { + + private final String message; + private final int priority; // define message priority in queue + + public Message(String message, int priority) { + this.message = message; + this.priority = priority; + } + + @Override + public int compareTo(Message o) { + return priority - o.priority; + } + ... +} +``` + +Here's `PriorityMessageQueue` that handles storing the messages and serving them in priority +order. + +```java +public class PriorityMessageQueue { + + ... + + public T remove() { + if (isEmpty()) { + return null; + } + + final var root = queue[0]; + queue[0] = queue[size - 1]; + size--; + maxHeapifyDown(); + return root; + } + + public void add(T t) { + ensureCapacity(); + queue[size] = t; + size++; + maxHeapifyUp(); + } + + ... +} +``` + +`QueueManager` has a `PriorityMessageQueue` and makes it easy to `publishMessage` and +`receiveMessage`. + +```java +public class QueueManager { + + private final PriorityMessageQueue messagePriorityMessageQueue; + + public QueueManager(int initialCapacity) { + messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]); + } + + public void publishMessage(Message message) { + messagePriorityMessageQueue.add(message); + } + + public Message receiveMessage() { + if (messagePriorityMessageQueue.isEmpty()) { + return null; + } + return messagePriorityMessageQueue.remove(); + } +} +``` + +`Worker` constantly polls `QueueManager` for highest priority message and processes it. + +```java +public class Worker { + + private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class); + + private final QueueManager queueManager; + + public Worker(QueueManager queueManager) { + this.queueManager = queueManager; + } + + public void run() throws Exception { + while (true) { + var message = queueManager.receiveMessage(); + if (message == null) { + LOGGER.info("No Message ... waiting"); + Thread.sleep(200); + } else { + processMessage(message); + } + } + } + + private void processMessage(Message message) { + LOGGER.info(message.toString()); + } +} +``` + +Here's the full example how we create an instance of `QueueManager` and process messages using +`Worker`. + +```java + var queueManager = new QueueManager(100); + + for (var i = 0; i < 100; i++) { + queueManager.publishMessage(new Message("Low Message Priority", 0)); + } + + for (var i = 0; i < 100; i++) { + queueManager.publishMessage(new Message("High Message Priority", 1)); + } + + var worker = new Worker(queueManager); + worker.run(); +``` + +Program output: + +``` +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +No Message ... waiting +No Message ... waiting +No Message ... waiting +``` + ## Class diagram + ![alt text](./etc/priority-queue.urm.png "Priority Queue pattern class diagram") ## Applicability -Use the Priority Queue pattern when + +Use the Priority Queue pattern when: * The system must handle multiple tasks that might have different priorities. -* Different users or tenants should be served with different priority.. +* Different users or tenants should be served with different priority. ## Credits diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java index 433a72d74..cdef90ab8 100644 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java +++ b/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java @@ -37,20 +37,19 @@ public class Application { */ public static void main(String[] args) throws Exception { - var queueManager = new QueueManager(100); + var queueManager = new QueueManager(10); // push some message to queue // Low Priority message - for (var i = 0; i < 100; i++) { + for (var i = 0; i < 10; i++) { queueManager.publishMessage(new Message("Low Message Priority", 0)); } // High Priority message - for (var i = 0; i < 100; i++) { + for (var i = 0; i < 10; i++) { queueManager.publishMessage(new Message("High Message Priority", 1)); } - // run worker var worker = new Worker(queueManager); worker.run(); diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java index 0b4be910f..3a0761f4a 100644 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java +++ b/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java @@ -45,7 +45,7 @@ public class QueueManager { /** - * recive message from queue. + * Receive message from queue. */ public Message receiveMessage() { if (messagePriorityMessageQueue.isEmpty()) { From 20fac32ac20c098b89e479f6ec8007e4dd5468ef Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 31 Aug 2020 17:13:14 +0800 Subject: [PATCH 074/254] finish Chinese translation of observer and strategy --- zh/observer/README.md | 159 ++++++++++++++++++++++++++++++++++++++++++ zh/strategy/README.md | 136 ++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 zh/observer/README.md create mode 100644 zh/strategy/README.md diff --git a/zh/observer/README.md b/zh/observer/README.md new file mode 100644 index 000000000..8a4b80a07 --- /dev/null +++ b/zh/observer/README.md @@ -0,0 +1,159 @@ +--- +layout: pattern +title: Observer +folder: observer +permalink: /patterns/observer/ +categories: Behavioral +tags: + - Gang Of Four + - Reactive +--- + +## Also known as +## 又被称为 + +家属,发布订阅模式 + +## 目的 + +定义一种一对多的对象依赖关系这样当一个对象改变状态时,所有依赖它的对象都将自动通知或更新。 + +## 解释 + +真实世界例子 + +> 在遥远的土地上生活着霍比特人和兽人的种族。他们都是户外生活的人所以他们密切关注天气的变化。可以说他们不断地关注着天气。 + +通俗的说 + +> 注册成为一个观察者以接收对象状态的改变。 + +维基百科说 + +> 观察者模式是这样的一种软件设计模式:它有一个被称为主题的对象,维护着一个所有依赖于它的依赖者清单,也就是观察者清单,当主题的状态发生改变时,主题通常会调用观察者的方法来自动通知观察者们。 + +**编程示例** + +让我们先来介绍天气观察者的接口以及我们的种族,兽人和霍比特人。 + +```java +public interface WeatherObserver { + + void update(WeatherType currentWeather); +} + +public class Orcs implements WeatherObserver { + + private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class); + + @Override + public void update(WeatherType currentWeather) { + LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now"); + } +} + +public class Hobbits implements WeatherObserver { + + private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class); + + @Override + public void update(WeatherType currentWeather) { + switch (currentWeather) { + LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now"); + } +} +``` + +然后这里是不断变化的天气。 + +```java +public class Weather { + + private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class); + + private WeatherType currentWeather; + private final List observers; + + public Weather() { + observers = new ArrayList<>(); + currentWeather = WeatherType.SUNNY; + } + + public void addObserver(WeatherObserver obs) { + observers.add(obs); + } + + public void removeObserver(WeatherObserver obs) { + observers.remove(obs); + } + + /** + * Makes time pass for weather. + */ + public void timePasses() { + var enumValues = WeatherType.values(); + currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; + LOGGER.info("The weather changed to {}.", currentWeather); + notifyObservers(); + } + + private void notifyObservers() { + for (var obs : observers) { + obs.update(currentWeather); + } + } +} +``` + +这是完整的示例。 + +```java + var weather = new Weather(); + weather.addObserver(new Orcs()); + weather.addObserver(new Hobbits()); + + weather.timePasses(); + // The weather changed to rainy. + // The orcs are facing rainy weather now + // The hobbits are facing rainy weather now + weather.timePasses(); + // The weather changed to windy. + // The orcs are facing windy weather now + // The hobbits are facing windy weather now + weather.timePasses(); + // The weather changed to cold. + // The orcs are facing cold weather now + // The hobbits are facing cold weather now + weather.timePasses(); + // The weather changed to sunny. + // The orcs are facing sunny weather now + // The hobbits are facing sunny weather now +``` + +## Class diagram +![alt text](../../observer/etc/observer.png "Observer") + +## 应用 +在下面任何一种情况下都可以使用观察者模式 + +* 当抽象具有两个方面时,一个方面依赖于另一个方面。将这些方面封装在单独的对象中,可以使你分别进行更改和重用 +* 当一个对象的改变的同时需要改变其他对象,同时你又不知道有多少对象需要改变时 +* 当一个对象可以通知其他对象而无需假设这些对象是谁时。换句话说,你不想让这些对象紧耦合。 + +## 典型用例 + +* 一个对象的改变导致其他对象的改变 + +## Java中的例子 + +* [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html) +* [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html) +* [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html) +* [RxJava](https://github.com/ReactiveX/RxJava) + +## 鸣谢 + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Java Generics and Collections](https://www.amazon.com/gp/product/0596527756/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596527756&linkCode=as2&tag=javadesignpat-20&linkId=246e5e2c26fe1c3ada6a70b15afcb195) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) diff --git a/zh/strategy/README.md b/zh/strategy/README.md new file mode 100644 index 000000000..29fe2e4eb --- /dev/null +++ b/zh/strategy/README.md @@ -0,0 +1,136 @@ +--- +layout: pattern +title: Strategy +folder: strategy +permalink: /patterns/strategy/ +categories: Behavioral +tags: + - Gang of Four +--- + +## 又被称为 +政策(方针)模式 + +## 目的 + +定义一个家族算法,并封装好其中每一个,使它们可以互相替换。策略模式使算法的变化独立于使用它的客户。 + +## 解释 + +现实世界例子 + +> 屠龙是一项危险的职业。有经验将会使它变得简单。经验丰富的屠龙者对不同类型的龙有不同的战斗策略。 + +直白点说 + +> 策略模式允许在运行时选择最匹配的算法。 + +维基百科上说 + +> 在程序编程领域,策略模式(又叫政策模式)是一种启用在运行时选择算法的行为型软件设计模式。 + +**编程实例** + +让我们先介绍屠龙的策略模式接口和它的实现。 + +```java +@FunctionalInterface +public interface DragonSlayingStrategy { + + void execute(); +} + +public class MeleeStrategy implements DragonSlayingStrategy { + + private static final Logger LOGGER = LoggerFactory.getLogger(MeleeStrategy.class); + + @Override + public void execute() { + LOGGER.info("With your Excalibur you sever the dragon's head!"); + } +} + +public class ProjectileStrategy implements DragonSlayingStrategy { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProjectileStrategy.class); + + @Override + public void execute() { + LOGGER.info("You shoot the dragon with the magical crossbow and it falls dead on the ground!"); + } +} + +public class SpellStrategy implements DragonSlayingStrategy { + + private static final Logger LOGGER = LoggerFactory.getLogger(SpellStrategy.class); + + @Override + public void execute() { + LOGGER.info("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!"); + } +} +``` + +现在有一个强力的屠龙者要基于上面的组件来选择他的战斗策略。 + +```java +public class DragonSlayer { + + private DragonSlayingStrategy strategy; + + public DragonSlayer(DragonSlayingStrategy strategy) { + this.strategy = strategy; + } + + public void changeStrategy(DragonSlayingStrategy strategy) { + this.strategy = strategy; + } + + public void goToBattle() { + strategy.execute(); + } +} +``` + +最后是屠龙者的行动。 + +```java + LOGGER.info("Green dragon spotted ahead!"); + var dragonSlayer = new DragonSlayer(new MeleeStrategy()); + dragonSlayer.goToBattle(); + LOGGER.info("Red dragon emerges."); + dragonSlayer.changeStrategy(new ProjectileStrategy()); + dragonSlayer.goToBattle(); + LOGGER.info("Black dragon lands before you."); + dragonSlayer.changeStrategy(new SpellStrategy()); + dragonSlayer.goToBattle(); + + // Green dragon spotted ahead! + // With your Excalibur you sever the dragon's head! + // Red dragon emerges. + // You shoot the dragon with the magical crossbow and it falls dead on the ground! + // Black dragon lands before you. + // You cast the spell of disintegration and the dragon vaporizes in a pile of dust! +``` + +## 类图 +![alt text](../../strategy/etc/strategy_1.png "Strategy") + +## 应用 +使用策略模式当 + +* 许多相关的类只是行为不同。策略模式提供了一种为一种类配置多种行为的能力。 +* 你需要一种算法的不同变体。比如,你可能定义反应不用时间空间权衡的算法。当这些算法的变体使用类的层次结构来实现时就可以使用策略模式。 +* 一个算法使用的数据客户不应该对其知晓。使用策略模式来避免暴露复杂的,特定于算法的数据结构。 +* 一个类定义了许多行为,这些行为在其操作中展现为多个条件语句。移动相关的条件分支到它们分别的策略类中来代替这些条件语句。 + +## 教学 + +* [Strategy Pattern Tutorial](https://www.journaldev.com/1754/strategy-design-pattern-in-java-example-tutorial) + +## 鸣谢 + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) From aebdb88a83498eaeb82f6ae7c41107c996f72311 Mon Sep 17 00:00:00 2001 From: Fedor Skvorcov <43882212+fedorskvorcov@users.noreply.github.com> Date: Tue, 1 Sep 2020 09:51:46 +0300 Subject: [PATCH 075/254] Fix typo in comment --- .../main/java/com/iluwatar/servicelocator/ServiceLocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java index 4e787d34c..fad1dafe7 100644 --- a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java +++ b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java @@ -50,7 +50,7 @@ public final class ServiceLocator { return serviceObj; } else { /* - * If we are unable to retrive anything from cache, then lookup the service and add it in the + * If we are unable to retrieve anything from cache, then lookup the service and add it in the * cache map */ var ctx = new InitContext(); From 7aca64a3c9cd67958ebc4c22057834c8f3133ffc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 13:39:32 +0000 Subject: [PATCH 076/254] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 95fe7a912..e64d4c15b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-129-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-130-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -263,6 +263,7 @@ This project is licensed under the terms of the MIT license.
Stefan Birkner

💻 +
Fedor Skvorcov

💻 From daa94c7b6d4d0f5dc61826b4e0c8ab86f8d5df69 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2020 13:39:33 +0000 Subject: [PATCH 077/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 65eb0bf92..e0ef0200b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1176,6 +1176,15 @@ "contributions": [ "code" ] + }, + { + "login": "fedorskvorcov", + "name": "Fedor Skvorcov", + "avatar_url": "https://avatars3.githubusercontent.com/u/43882212?v=4", + "profile": "https://github.com/fedorskvorcov", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From b9b6777d15a8dff0bc304888bc1c122a74cb89c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 1 Sep 2020 19:55:22 +0300 Subject: [PATCH 078/254] Update README.md --- private-class-data/README.md | 5 ++- promise/README.md | 41 ++++++++++--------- .../main/java/com/iluwatar/promise/App.java | 2 +- .../java/com/iluwatar/promise/Promise.java | 2 +- .../com/iluwatar/promise/PromiseSupport.java | 3 +- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/private-class-data/README.md b/private-class-data/README.md index d4788d2dd..5d0e6eb51 100644 --- a/private-class-data/README.md +++ b/private-class-data/README.md @@ -9,6 +9,7 @@ tags: --- ## Intent + Private Class Data design pattern seeks to reduce exposure of attributes by limiting their visibility. It reduces the number of class attributes by encapsulating them in single Data object. @@ -124,9 +125,11 @@ immutableStew.mix(); // Mixing the immutable stew we find: 2 potatoes, 4 carrot ``` ## Class diagram + ![alt text](./etc/private-class-data.png "Private Class Data") ## Applicability + Use the Private Class Data pattern when -* You want to prevent write access to class data members +* You want to prevent write access to class data members. diff --git a/promise/README.md b/promise/README.md index 993d29a9f..73dce13ec 100644 --- a/promise/README.md +++ b/promise/README.md @@ -14,23 +14,25 @@ CompletableFuture ## Intent -A Promise represents a proxy for a value not necessarily known when the promise is created. It allows you to associate -dependent promises to an asynchronous action's eventual success value or failure reason. Promises are a way to write -async code that still appears as though it is executing in a synchronous way. +A Promise represents a proxy for a value not necessarily known when the promise is created. It +allows you to associate dependent promises to an asynchronous action's eventual success value or +failure reason. Promises are a way to write async code that still appears as though it is executing +in a synchronous way. ## Explanation -The Promise object is used for asynchronous computations. A Promise represents an operation that hasn't completed yet, -but is expected in the future. +The Promise object is used for asynchronous computations. A Promise represents an operation that +hasn't completed yet, but is expected in the future. Promises provide a few advantages over callback objects: - * Functional composition and error handling - * Prevents callback hell and provides callback aggregation + * Functional composition and error handling. + * Prevents callback hell and provides callback aggregation. Real world example -> We are developing a software solution that downloads files and calculates the number of lines and character -frequencies in those files. Promise is an ideal solution to make the code concise and easy to understand. +> We are developing a software solution that downloads files and calculates the number of lines and +> character frequencies in those files. Promise is an ideal solution to make the code concise and +> easy to understand. In plain words @@ -38,14 +40,15 @@ In plain words Wikipedia says -> In computer science, future, promise, delay, and deferred refer to constructs used for synchronizing program -execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is -initially unknown, usually because the computation of its value is not yet complete. +> In computer science, future, promise, delay, and deferred refer to constructs used for +> synchronizing program execution in some concurrent programming languages. They describe an object +> that acts as a proxy for a result that is initially unknown, usually because the computation of +> its value is not yet complete. **Programmatic Example** -In the example a file is downloaded and its line count is calculated. The calculated line count is then consumed and -printed on console. +In the example a file is downloaded and its line count is calculated. The calculated line count is +then consumed and printed on console. Let's first introduce a support class we need for implementation. Here's `PromiseSupport`. @@ -195,7 +198,7 @@ public class Promise extends PromiseSupport { public Promise thenApply(Function func) { Promise dest = new Promise<>(); - fulfillmentAction = new TransformAction(this, dest, func); + fulfillmentAction = new TransformAction<>(this, dest, func); return dest; } @@ -246,8 +249,8 @@ public class Promise extends PromiseSupport { } ``` -Now we can show the full example in action. Here's how to download and count the number of lines in a file using -`Promise`. +Now we can show the full example in action. Here's how to download and count the number of lines in +a file using `Promise`. ```java countLines().thenAccept( @@ -280,8 +283,8 @@ Now we can show the full example in action. Here's how to download and count the ## Applicability -Promise pattern is applicable in concurrent programming when some work needs to be done asynchronously -and: +Promise pattern is applicable in concurrent programming when some work needs to be done +asynchronously and: * Code maintainability and readability suffers due to callback hell. * You need to compose promises and need better error handling for asynchronous tasks. diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index fb2f14bd5..6c0921936 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -81,7 +81,7 @@ public class App { * @throws InterruptedException if main thread is interrupted. * @throws ExecutionException if an execution error occurs. */ - public static void main(String[] args) throws InterruptedException, ExecutionException { + public static void main(String[] args) throws InterruptedException { var app = new App(); try { app.promiseUsage(); diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index e81cccb58..5b79ebcd6 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -141,7 +141,7 @@ public class Promise extends PromiseSupport { */ public Promise thenApply(Function func) { Promise dest = new Promise<>(); - fulfillmentAction = new TransformAction(this, dest, func); + fulfillmentAction = new TransformAction<>(this, dest, func); return dest; } diff --git a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java index 7a12f0a0f..01e9926a0 100644 --- a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java +++ b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java @@ -26,7 +26,6 @@ package com.iluwatar.promise; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -114,4 +113,4 @@ class PromiseSupport implements Future { } throw new ExecutionException(exception); } -} \ No newline at end of file +} From 25cca3547d9a7fa07342ba696ded72bb17f3d0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 1 Sep 2020 20:06:47 +0300 Subject: [PATCH 079/254] Update README.md --- prototype/README.md | 35 +++++--- proxy/README.md | 60 +++++++++----- .../java/com/iluwatar/proxy/IvoryTower.java | 80 +++++++++---------- 3 files changed, 105 insertions(+), 70 deletions(-) diff --git a/prototype/README.md b/prototype/README.md index 472e8330c..9128ccb2c 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -10,16 +10,19 @@ tags: --- ## Intent -Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype. + +Specify the kinds of objects to create using a prototypical instance, and create new objects by +copying this prototype. ## Explanation -First it should be noted that Prototype pattern is not used to gain performance benefits. It's only used for creating -new objects from prototype instance. +First it should be noted that Prototype pattern is not used to gain performance benefits. It's only +used for creating new objects from prototype instance. Real world example -> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is that it is all about cloning. +> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is +> that it is all about cloning. In plain words @@ -27,9 +30,12 @@ In plain words Wikipedia says -> The prototype pattern is a creational design pattern in software development. It is used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. +> The prototype pattern is a creational design pattern in software development. It is used when the +> type of objects to create is determined by a prototypical instance, which is cloned to produce new +> objects. -In short, it allows you to create a copy of an existing object and modify it to your needs, instead of going through the trouble of creating an object from scratch and setting it up. +In short, it allows you to create a copy of an existing object and modify it to your needs, instead +of going through the trouble of creating an object from scratch and setting it up. **Programmatic Example** @@ -52,7 +58,7 @@ class Sheep implements Cloneable { } ``` -Then it can be cloned like below +Then it can be cloned like below: ```java var original = new Sheep("Jolly"); @@ -65,15 +71,20 @@ System.out.println(cloned.getName()); // Dolly ``` ## Class diagram + ![alt text](./etc/prototype.urm.png "Prototype pattern class diagram") ## Applicability -Use the Prototype pattern when a system should be independent of how its products are created, composed and represented; and -* When the classes to instantiate are specified at run-time, for example, by dynamic loading -* To avoid building a class hierarchy of factories that parallels the class hierarchy of products -* When instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually, each time with the appropriate state -* When object creation is expensive compared to cloning +Use the Prototype pattern when a system should be independent of how its products are created, +composed, represented and + +* When the classes to instantiate are specified at run-time, for example, by dynamic loading. +* To avoid building a class hierarchy of factories that parallels the class hierarchy of products. +* When instances of a class can have one of only a few different combinations of state. It may be +more convenient to install a corresponding number of prototypes and clone them rather than +instantiating the class manually, each time with the appropriate state. +* When object creation is expensive compared to cloning. ## Real world examples diff --git a/proxy/README.md b/proxy/README.md index ddcc4e784..edf223b23 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -10,16 +10,20 @@ tags: --- ## Also known as + Surrogate ## Intent -Provide a surrogate or placeholder for another object to control -access to it. + +Provide a surrogate or placeholder for another object to control access to it. ## Explanation + Real world example -> Imagine a tower where the local wizards go to study their spells. The ivory tower can only be accessed through a proxy which ensures that only the first three wizards can enter. Here the proxy represents the functionality of the tower and adds access control to it. +> Imagine a tower where the local wizards go to study their spells. The ivory tower can only be +> accessed through a proxy which ensures that only the first three wizards can enter. Here the proxy +> represents the functionality of the tower and adds access control to it. In plain words @@ -27,11 +31,17 @@ In plain words Wikipedia says -> A proxy, in its most general form, is a class functioning as an interface to something else. A proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked. +> A proxy, in its most general form, is a class functioning as an interface to something else. +> A proxy is a wrapper or agent object that is being called by the client to access the real serving +> object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can +> provide additional logic. In the proxy extra functionality can be provided, for example caching +> when operations on the real object are resource intensive, or checking preconditions before +> operations on the real object are invoked. **Programmatic Example** -Taking our wizard tower example from above. Firstly we have the wizard tower interface and the ivory tower class +Taking our wizard tower example from above. Firstly we have the `WizardTower` interface and the +`IvoryTower` class. ```java public interface WizardTower { @@ -50,7 +60,7 @@ public class IvoryTower implements WizardTower { } ``` -Then a simple wizard class +Then a simple `Wizard` class. ```java public class Wizard { @@ -68,7 +78,7 @@ public class Wizard { } ``` -Then we have the proxy to add access control to wizard tower +Then we have the `WizardTowerProxy` to add access control to `WizardTower`. ```java public class WizardTowerProxy implements WizardTower { @@ -97,28 +107,41 @@ public class WizardTowerProxy implements WizardTower { } ``` -And here is tower entering scenario +And here is the tower entering scenario. ```java var proxy = new WizardTowerProxy(new IvoryTower()); -proxy.enter(new Wizard("Red wizard")); // Red wizard enters the tower. -proxy.enter(new Wizard("White wizard")); // White wizard enters the tower. -proxy.enter(new Wizard("Black wizard")); // Black wizard enters the tower. -proxy.enter(new Wizard("Green wizard")); // Green wizard is not allowed to enter! -proxy.enter(new Wizard("Brown wizard")); // Brown wizard is not allowed to enter! +proxy.enter(new Wizard("Red wizard")); +proxy.enter(new Wizard("White wizard")); +proxy.enter(new Wizard("Black wizard")); +proxy.enter(new Wizard("Green wizard")); +proxy.enter(new Wizard("Brown wizard")); +``` + +Program output: + +``` +Red wizard enters the tower. +White wizard enters the tower. +Black wizard enters the tower. +Green wizard is not allowed to enter! +Brown wizard is not allowed to enter! ``` ## Class diagram + ![alt text](./etc/proxy.urm.png "Proxy pattern class diagram") ## Applicability -Proxy is applicable whenever there is a need for a more -versatile or sophisticated reference to an object than a simple pointer. Here -are several common situations in which the Proxy pattern is applicable + +Proxy is applicable whenever there is a need for a more versatile or sophisticated reference to an +object than a simple pointer. Here are several common situations in which the Proxy pattern is +applicable. * Remote proxy provides a local representative for an object in a different address space. * Virtual proxy creates expensive objects on demand. -* Protection proxy controls access to the original object. Protection proxies are useful when objects should have different access rights. +* Protection proxy controls access to the original object. Protection proxies are useful when +objects should have different access rights. ## Typical Use Case @@ -136,7 +159,8 @@ are several common situations in which the Proxy pattern is applicable * [java.lang.reflect.Proxy](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html) * [Apache Commons Proxy](https://commons.apache.org/proper/commons-proxy/) -* Mocking frameworks Mockito, Powermock, EasyMock +* Mocking frameworks [Mockito](https://site.mockito.org/), +[Powermock](https://powermock.github.io/), [EasyMock](https://easymock.org/) ## Related patterns diff --git a/proxy/src/main/java/com/iluwatar/proxy/IvoryTower.java b/proxy/src/main/java/com/iluwatar/proxy/IvoryTower.java index 658b19949..2523af8b8 100644 --- a/proxy/src/main/java/com/iluwatar/proxy/IvoryTower.java +++ b/proxy/src/main/java/com/iluwatar/proxy/IvoryTower.java @@ -1,40 +1,40 @@ -/* - * The MIT License - * Copyright © 2014-2019 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.proxy; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The object to be proxyed. - */ -public class IvoryTower implements WizardTower { - - private static final Logger LOGGER = LoggerFactory.getLogger(IvoryTower.class); - - public void enter(Wizard wizard) { - LOGGER.info("{} enters the tower.", wizard); - } - -} +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.proxy; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The object to be proxied. + */ +public class IvoryTower implements WizardTower { + + private static final Logger LOGGER = LoggerFactory.getLogger(IvoryTower.class); + + public void enter(Wizard wizard) { + LOGGER.info("{} enters the tower.", wizard); + } + +} From 3f4d63751042d6cf271611721a751657b5271f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 1 Sep 2020 20:18:10 +0300 Subject: [PATCH 080/254] Update README.md --- repository/README.md | 153 +++++------------- .../com/iluwatar/repository/AppConfig.java | 3 +- .../repository/PersonSpecifications.java | 2 +- 3 files changed, 43 insertions(+), 115 deletions(-) diff --git a/repository/README.md b/repository/README.md index ad603ee2b..ab13934bd 100644 --- a/repository/README.md +++ b/repository/README.md @@ -9,26 +9,33 @@ tags: --- ## Intent -Repository layer is added between the domain and data mapping layers to isolate domain objects from details of the -database access code and to minimize scattering and duplication of query code. The Repository pattern is especially -useful in systems where number of domain classes is large or heavy querying is utilized. + +Repository layer is added between the domain and data mapping layers to isolate domain objects from +details of the database access code and to minimize scattering and duplication of query code. The +Repository pattern is especially useful in systems where number of domain classes is large or heavy +querying is utilized. ## Explanation + Real world example -> Let's say we need a persistent data store for persons. Adding new persons and searching for them according to different criteria must be easy. +> Let's say we need a persistent data store for persons. Adding new persons and searching for them +> according to different criteria must be easy. In plain words -> Repository architectural pattern creates a uniform layer of data repositories that can be used for CRUD operations. +> Repository architectural pattern creates a uniform layer of data repositories that can be used for +> CRUD operations. [Microsoft documentation](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design) says -> Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer. +> Repositories are classes or components that encapsulate the logic required to access data sources. +> They centralize common data access functionality, providing better maintainability and decoupling +> the infrastructure or technology used to access databases from the domain model layer. **Programmatic Example** -Let's first look at the person class that we need to persist. +Let's first look at the person entity that we need to persist. ```java @Entity @@ -39,107 +46,23 @@ public class Person { private Long id; private String name; private String surname; - private int age; public Person() { } - /** - * Constructor. - */ public Person(String name, String surname, int age) { this.name = name; this.surname = surname; this.age = age; } - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getSurname() { - return surname; - } - - public void setSurname(String surname) { - this.surname = surname; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - @Override - public String toString() { - return "Person [id=" + id + ", name=" + name + ", surname=" + surname + ", age=" + age + "]"; - } - - @Override - public int hashCode() { - final var prime = 31; - var result = 1; - result = prime * result + age; - result = prime * result + (id == null ? 0 : id.hashCode()); - result = prime * result + (name == null ? 0 : name.hashCode()); - result = prime * result + (surname == null ? 0 : surname.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - var other = (Person) obj; - if (age != other.age) { - return false; - } - if (id == null) { - if (other.id != null) { - return false; - } - } else if (!id.equals(other.id)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (surname == null) { - return other.surname == null; - } - return surname.equals(other.surname); - } + // getters and setters -> + ... } ``` -We are using Spring Data to create the repository so it becomes really simple. +We are using Spring Data to create the `PersonRepository` so it becomes really simple. ```java @Repository @@ -150,7 +73,7 @@ public interface PersonRepository } ``` -Additionally we define a helper class for specification queries. +Additionally we define a helper class `PersonSpecifications` for specification queries. ```java public class PersonSpecifications { @@ -189,7 +112,7 @@ public class PersonSpecifications { } ``` -And here's the repository in action. +And here's the repository example in action. ```java var peter = new Person("Peter", "Sagan", 17); @@ -226,30 +149,36 @@ And here's the repository in action. persons.stream().map(Person::toString).forEach(LOGGER::info); repository.deleteAll(); - - // Count Person records: 4 - // Person [id=1, name=Peter, surname=Sagan, age=17] - // Person [id=2, name=Nasta, surname=Kuzminova, age=25] - // Person [id=3, name=John, surname=lawrence, age=35] - // Person [id=4, name=Terry, surname=Law, age=36] - // Find by id 2: Person [id=2, name=Barbora, surname=Spotakova, age=25] - // Count Person records: 3 - // Find by John is Person [id=3, name=John, surname=lawrence, age=35] - // Find Person with age between 20,40: - // Person [id=3, name=John, surname=lawrence, age=35] - // Person [id=4, name=Terry, surname=Law, age=36] +``` + +Program output: + +``` +Count Person records: 4 +Person [id=1, name=Peter, surname=Sagan, age=17] +Person [id=2, name=Nasta, surname=Kuzminova, age=25] +Person [id=3, name=John, surname=lawrence, age=35] +Person [id=4, name=Terry, surname=Law, age=36] +Find by id 2: Person [id=2, name=Barbora, surname=Spotakova, age=25] +Count Person records: 3 +Find by John is Person [id=3, name=John, surname=lawrence, age=35] +Find Person with age between 20,40: +Person [id=3, name=John, surname=lawrence, age=35] +Person [id=4, name=Terry, surname=Law, age=36] ``` ## Class diagram + ![alt text](./etc/repository.png "Repository") ## Applicability + Use the Repository pattern when -* The number of domain objects is large -* You want to avoid duplication of query code -* You want to keep the database querying code in single place -* You have multiple data sources +* The number of domain objects is large. +* You want to avoid duplication of query code. +* You want to keep the database querying code in single place. +* You have multiple data sources. ## Real world examples diff --git a/repository/src/main/java/com/iluwatar/repository/AppConfig.java b/repository/src/main/java/com/iluwatar/repository/AppConfig.java index 50a23026f..81d158d23 100644 --- a/repository/src/main/java/com/iluwatar/repository/AppConfig.java +++ b/repository/src/main/java/com/iluwatar/repository/AppConfig.java @@ -23,7 +23,6 @@ package com.iluwatar.repository; -import java.sql.SQLException; import java.util.List; import java.util.Properties; import javax.sql.DataSource; @@ -89,7 +88,7 @@ public class AppConfig { * Get transaction manager. */ @Bean - public JpaTransactionManager transactionManager() throws SQLException { + public JpaTransactionManager transactionManager() { var transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); return transactionManager; diff --git a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java index 919b746be..823fa2d3d 100644 --- a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java +++ b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java @@ -60,7 +60,7 @@ public class PersonSpecifications { */ public static class NameEqualSpec implements Specification { - public String name; + public final String name; public NameEqualSpec(String name) { this.name = name; From 19378f3fddb407ad7a0c68cc51338fc980ce9823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 1 Sep 2020 20:25:39 +0300 Subject: [PATCH 081/254] Update README.md --- retry/README.md | 110 ++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/retry/README.md b/retry/README.md index 056674a18..8cf6bb94f 100644 --- a/retry/README.md +++ b/retry/README.md @@ -10,39 +10,40 @@ tags: --- ## Intent -Transparently retry certain operations that involve communication with external resources, particularly over the -network, isolating calling code from the retry implementation details. + +Transparently retry certain operations that involve communication with external resources, +particularly over the network, isolating calling code from the retry implementation details. ## Explanation -Retry pattern consists retrying operations on remote resources over the -network a set number of times. It closely depends on both business and technical -requirements: how much time will the business allow the end user to wait while -the operation finishes? What are the performance characteristics of the -remote resource during peak loads as well as our application as more threads -are waiting for the remote resource's availability? Among the errors returned -by the remote service, which can be safely ignored in order to retry? Is the -operation [idempotent](https://en.wikipedia.org/wiki/Idempotence)? -Another concern is the impact on the calling code by implementing the retry -mechanism. The retry mechanics should ideally be completely transparent to the -calling code (service interface remains unaltered). There are two general -approaches to this problem: from an enterprise architecture standpoint -(strategic), and a shared library standpoint (tactical). +Retry pattern consists retrying operations on remote resources over the network a set number of +times. It closely depends on both business and technical requirements: How much time will the +business allow the end user to wait while the operation finishes? What are the performance +characteristics of the remote resource during peak loads as well as our application as more threads +are waiting for the remote resource's availability? Among the errors returned by the remote service, +which can be safely ignored in order to retry? Is the operation +[idempotent](https://en.wikipedia.org/wiki/Idempotence)? -From a strategic point of view, this would be solved by having requests -be redirected to a separate intermediary system, traditionally an -[ESB](https://en.wikipedia.org/wiki/Enterprise_service_bus), but more recently -a [Service Mesh](https://medium.com/microservices-in-practice/service-mesh-for-microservices-2953109a3c9a). +Another concern is the impact on the calling code by implementing the retry mechanism. The retry +mechanics should ideally be completely transparent to the calling code (service interface remains +unaltered). There are two general approaches to this problem: From an enterprise architecture +standpoint (strategic), and a shared library standpoint (tactical). -From a tactical point of view, this would be solved by reusing shared libraries -like [Hystrix](https://github.com/Netflix/Hystrix) (please note that *Hystrix* is a complete implementation of -the [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) pattern, of which the Retry pattern -can be considered a subset of.). This is the type of solution showcased in the simple example that accompanies this -*README*. +From a strategic point of view, this would be solved by having requests redirected to a separate +intermediary system, traditionally an [ESB](https://en.wikipedia.org/wiki/Enterprise_service_bus), +but more recently a [Service Mesh](https://medium.com/microservices-in-practice/service-mesh-for-microservices-2953109a3c9a). + +From a tactical point of view, this would be solved by reusing shared libraries like +[Hystrix](https://github.com/Netflix/Hystrix) (please note that Hystrix is a complete implementation +of the [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) pattern, of +which the Retry pattern can be considered a subset of). This is the type of solution showcased in +the simple example that accompanies this `README.md`. Real world example -> Our application uses a service providing customer information. Once in a while the service seems to be flaky and can return errors or sometimes it just times out. To circumvent these problems we apply the retry pattern. +> Our application uses a service providing customer information. Once in a while the service seems +> to be flaky and can return errors or sometimes it just times out. To circumvent these problems we +> apply the retry pattern. In plain words @@ -50,11 +51,14 @@ In plain words [Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry) says -> Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application. +> Enable an application to handle transient failures when it tries to connect to a service or +> network resource, by transparently retrying a failed operation. This can improve the stability of +> the application. **Programmatic Example** -In our hypothetical application, we have a generic interface for all operations on remote interfaces. +In our hypothetical application, we have a generic interface for all operations on remote +interfaces. ```java public interface BusinessOperation { @@ -73,16 +77,14 @@ public final class FindCustomer implements BusinessOperation { } ``` -Our `FindCustomer` implementation can be configured to throw -`BusinessException`s before returning the customer's ID, thereby simulating a -'flaky' service that intermittently fails. Some exceptions, like the -`CustomerNotFoundException`, are deemed to be recoverable after some -hypothetical analysis because the root cause of the error stems from "some -database locking issue". However, the `DatabaseNotAvailableException` is -considered to be a definite showstopper - the application should not attempt -to recover from this error. +Our `FindCustomer` implementation can be configured to throw `BusinessException`s before returning +the customer's ID, thereby simulating a flaky service that intermittently fails. Some exceptions, +like the `CustomerNotFoundException`, are deemed to be recoverable after some hypothetical analysis +because the root cause of the error stems from "some database locking issue". However, the +`DatabaseNotAvailableException` is considered to be a definite showstopper - the application should +not attempt to recover from this error. -We can model a 'recoverable' scenario by instantiating `FindCustomer` like this: +We can model a recoverable scenario by instantiating `FindCustomer` like this: ```java final var op = new FindCustomer( @@ -93,15 +95,12 @@ final var op = new FindCustomer( ); ``` -In this configuration, `FindCustomer` will throw `CustomerNotFoundException` -three times, after which it will consistently return the customer's ID -(`12345`). +In this configuration, `FindCustomer` will throw `CustomerNotFoundException` three times, after +which it will consistently return the customer's ID (`12345`). -In our hypothetical scenario, our analysts indicate that this operation -typically fails 2-4 times for a given input during peak hours, and that each -worker thread in the database subsystem typically needs 50ms to -"recover from an error". Applying these policies would yield something like -this: +In our hypothetical scenario, our analysts indicate that this operation typically fails 2-4 times +for a given input during peak hours, and that each worker thread in the database subsystem typically +needs 50ms to "recover from an error". Applying these policies would yield something like this: ```java final var op = new Retry<>( @@ -117,26 +116,27 @@ final var op = new Retry<>( ); ``` -Executing `op` *once* would automatically trigger at most 5 retry attempts, -with a 100 millisecond delay between attempts, ignoring any -`CustomerNotFoundException` thrown while trying. In this particular scenario, -due to the configuration for `FindCustomer`, there will be 1 initial attempt +Executing `op` once would automatically trigger at most 5 retry attempts, with a 100 millisecond +delay between attempts, ignoring any `CustomerNotFoundException` thrown while trying. In this +particular scenario, due to the configuration for `FindCustomer`, there will be 1 initial attempt and 3 additional retries before finally returning the desired result `12345`. -If our `FindCustomer` operation were instead to throw a fatal -`DatabaseNotFoundException`, which we were instructed not to ignore, but -more importantly we did *not* instruct our `Retry` to ignore, then the operation -would have failed immediately upon receiving the error, not matter how many -attempts were left. +If our `FindCustomer` operation were instead to throw a fatal `DatabaseNotFoundException`, which we +were instructed not to ignore, but more importantly we did not instruct our `Retry` to ignore, then +the operation would have failed immediately upon receiving the error, not matter how many attempts +were left. ## Class diagram + ![alt text](./etc/retry.png "Retry") ## Applicability -Whenever an application needs to communicate with an external resource, particularly in a cloud environment, and if -the business requirements allow it. + +Whenever an application needs to communicate with an external resource, particularly in a cloud +environment, and if the business requirements allow it. ## Consequences + **Pros:** * Resiliency From e231cd8d1a859cfe17612adbf1b77b44e6381467 Mon Sep 17 00:00:00 2001 From: Fedor Date: Wed, 2 Sep 2020 12:32:02 +0300 Subject: [PATCH 082/254] Remove unnecessary word from text --- singleton/src/main/java/com/iluwatar/singleton/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singleton/src/main/java/com/iluwatar/singleton/App.java b/singleton/src/main/java/com/iluwatar/singleton/App.java index 319e077ef..2cea2edd3 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/App.java +++ b/singleton/src/main/java/com/iluwatar/singleton/App.java @@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory; *

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.

* *

There are many ways to implement the Singleton. The first one is the eagerly initialized From 46b23f322fff5fc3ece1f92f126ac7dd4573aa33 Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Wed, 2 Sep 2020 13:46:53 +0100 Subject: [PATCH 083/254] Add Simple Factory Pattern implementation Java source code demonstrate simple factory design pattern --- pom.xml | 1 + .../java/com/iluwatar/simplefactory/App.java | 16 ++++++++++ .../java/com/iluwatar/simplefactory/Car.java | 10 +++++++ .../simplefactory/CarSimpleFactory.java | 29 +++++++++++++++++++ .../com/iluwatar/simplefactory/Ferrari.java | 14 +++++++++ .../java/com/iluwatar/simplefactory/Ford.java | 14 +++++++++ 6 files changed, 84 insertions(+) create mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/App.java create mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java create mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java create mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java create mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java diff --git a/pom.xml b/pom.xml index 6d779700f..cc59a846a 100644 --- a/pom.xml +++ b/pom.xml @@ -195,6 +195,7 @@ arrange-act-assert transaction-script filterer + simple-factory diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/App.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/App.java new file mode 100644 index 000000000..898efe6d3 --- /dev/null +++ b/simple-factory/src/main/java/com/iluwatar/simplefactory/App.java @@ -0,0 +1,16 @@ +package com.iluwatar.simplefactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + public static void main(String[] args) { + Car car1 = CarSimpleFactory.getCar(CarSimpleFactory.carTypes.FORD); + Car car2 = CarSimpleFactory.getCar(CarSimpleFactory.carTypes.FERRARI); + LOGGER.info(car1.getDescription()); + LOGGER.info(car2.getDescription()); + } +} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java new file mode 100644 index 000000000..82ff4ebe0 --- /dev/null +++ b/simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java @@ -0,0 +1,10 @@ +package com.iluwatar.simplefactory; + +/** + * Car interface + */ +public interface Car { + + public String getDescription(); + +} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java new file mode 100644 index 000000000..33dbe7b88 --- /dev/null +++ b/simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java @@ -0,0 +1,29 @@ +package com.iluwatar.simplefactory; + + +/** + * Factory of cars + */ +public class CarSimpleFactory { + + /* + * Enumeration for different types of cars + */ + static enum carTypes { + FORD, FERRARI + }; + + /* + * Factory method takes as parameter a car type and initiate the appropriate class + */ + public static Car getCar(carTypes type) { + switch (type) { + case FORD: + return new Ford(); + case FERRARI: + return new Ferrari(); + default: + throw new IllegalArgumentException("Model not supported."); + } + } +} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java new file mode 100644 index 000000000..f9f1d8492 --- /dev/null +++ b/simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java @@ -0,0 +1,14 @@ +package com.iluwatar.simplefactory; + +/** + * Ferrari implementation + */ +public class Ferrari implements Car { + + static final String DESCRIPTION = "This is Ferrari."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java new file mode 100644 index 000000000..0adf4b66b --- /dev/null +++ b/simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java @@ -0,0 +1,14 @@ +package com.iluwatar.simplefactory; + +/** + * Ford implementation + */ +public class Ford implements Car { + + static final String DESCRIPTION = "This is Ford."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} From ac98b31b68fcdf3133041d64e38fd2478202c227 Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Wed, 2 Sep 2020 14:09:44 +0100 Subject: [PATCH 084/254] Add Maven Assembly plugin to pom.xml --- simple-factory/pom.xml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 simple-factory/pom.xml diff --git a/simple-factory/pom.xml b/simple-factory/pom.xml new file mode 100644 index 000000000..e7d28511f --- /dev/null +++ b/simple-factory/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.24.0-SNAPSHOT + + simple-factory + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.abstractfactory.App + + + + + + + + + \ No newline at end of file From b423fd30d4b0d1fd6db2681c35f7c49ce447b1e5 Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Wed, 2 Sep 2020 18:12:42 +0100 Subject: [PATCH 085/254] Fix bugs, clean the code and add unit tests. --- simple-factory/etc/simple-factory.urm.puml | 35 +++++++++++++++ simple-factory/pom.xml | 13 +++++- .../java/com/iluwatar/simplefactory/App.java | 44 +++++++++++++++---- .../java/com/iluwatar/simplefactory/Car.java | 8 ++-- .../simplefactory/CarSimpleFactory.java | 42 ++++++++---------- .../com/iluwatar/simplefactory/Ferrari.java | 16 +++---- .../java/com/iluwatar/simplefactory/Ford.java | 12 ++--- .../com/iluwatar/simplefactory/AppTest.java | 14 ++++++ .../simplefactory/CarSimpleFactoryTest.java | 15 +++++++ 9 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 simple-factory/etc/simple-factory.urm.puml create mode 100644 simple-factory/src/test/java/com/iluwatar/simplefactory/AppTest.java create mode 100644 simple-factory/src/test/java/com/iluwatar/simplefactory/CarSimpleFactoryTest.java diff --git a/simple-factory/etc/simple-factory.urm.puml b/simple-factory/etc/simple-factory.urm.puml new file mode 100644 index 000000000..77fee4b5b --- /dev/null +++ b/simple-factory/etc/simple-factory.urm.puml @@ -0,0 +1,35 @@ +@startuml +package com.iluwatar.simplefactory { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface Car { + + getDescription() : String {abstract} + } + class CarSimpleFactory { + + CarSimpleFactory() + + getCar(type : CarType) : Car {static} + } + ~enum CarType { + + FERRARI {static} + + FORD {static} + + valueOf(name : String) : CarType {static} + + values() : CarType[] {static} + } + class Ferrari { + ~ DESCRIPTION : String {static} + + Ferrari() + + getDescription() : String + } + class Ford { + ~ DESCRIPTION : String {static} + + Ford() + + getDescription() : String + } +} +CarType ..+ CarSimpleFactory +Ferrari ..|> Car +Ford ..|> Car +@enduml \ No newline at end of file diff --git a/simple-factory/pom.xml b/simple-factory/pom.xml index e7d28511f..ca7c0547d 100644 --- a/simple-factory/pom.xml +++ b/simple-factory/pom.xml @@ -6,6 +6,17 @@ 1.24.0-SNAPSHOT simple-factory + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.factory.App + + + + + + + + + \ No newline at end of file diff --git a/factory/src/main/java/com/iluwatar/factory/App.java b/factory/src/main/java/com/iluwatar/factory/App.java new file mode 100644 index 000000000..13f217646 --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/App.java @@ -0,0 +1,51 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.factory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Factory is an object for creating other objects, it providing Providing a static method to + * create and return objects of varying classes, in order to hide the implementation logic + * and makes client code focus on usage rather then objects initialization and management. + * + *

In this example the CarFactory is the factory class and it provides a static method to + * create different cars. + */ + +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * Program main entry point. + */ + public static void main(String[] args) { + var car1 = CarsFactory.getCar(CarsFactory.CarType.FORD); + var car2 = CarsFactory.getCar(CarsFactory.CarType.FERRARI); + LOGGER.info(car1.getDescription()); + LOGGER.info(car2.getDescription()); + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/Car.java b/factory/src/main/java/com/iluwatar/factory/Car.java new file mode 100644 index 000000000..6f564233c --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/Car.java @@ -0,0 +1,10 @@ +package com.iluwatar.factory; + +/** + * Car interface. + */ +public interface Car { + + public String getDescription(); + +} diff --git a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java new file mode 100644 index 000000000..01ad157ca --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java @@ -0,0 +1,25 @@ +package com.iluwatar.factory; + +/** + * Factory of cars. + */ +public class CarsFactory { + + /** + * Enumeration for different types of cars. + */ + static enum CarType { + FORD, FERRARI + } + + /** + * Factory method takes as parameter a car type and initiate the appropriate class. + */ + public static Car getCar(CarType type) { + switch (type) { + case FORD: return new Ford(); + case FERRARI: return new Ferrari(); + default: throw new IllegalArgumentException("Model not supported."); + } + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/Ferrari.java b/factory/src/main/java/com/iluwatar/factory/Ferrari.java new file mode 100644 index 000000000..590167f81 --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/Ferrari.java @@ -0,0 +1,14 @@ +package com.iluwatar.factory; + +/** + * Ferrari implementation. + */ +public class Ferrari implements Car { + + static final String DESCRIPTION = "This is Ferrari."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/Ford.java b/factory/src/main/java/com/iluwatar/factory/Ford.java new file mode 100644 index 000000000..13ae7a49e --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/Ford.java @@ -0,0 +1,14 @@ +package com.iluwatar.factory; + +/** + * Ford implementation. + */ +public class Ford implements Car { + + static final String DESCRIPTION = "This is Ford."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} diff --git a/factory/src/test/java/com/iluwatar/factory/AppTest.java b/factory/src/test/java/com/iluwatar/factory/AppTest.java new file mode 100644 index 000000000..d29ffb6a2 --- /dev/null +++ b/factory/src/test/java/com/iluwatar/factory/AppTest.java @@ -0,0 +1,14 @@ +package com.iluwatar.factory; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void shouldExecuteWithoutExceptions() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } + +} diff --git a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java new file mode 100644 index 000000000..eae75919a --- /dev/null +++ b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java @@ -0,0 +1,15 @@ +package com.iluwatar.factory; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class CarsFactoryTest { + + @Test + void shouldReturnFerrariInstance() { + final var ferrari = CarsFactory.getCar(CarsFactory.CarType.FERRARI); + assertTrue(ferrari instanceof Ferrari); + } + +} From 2bb252e08f3dbf74a0a11cd443fc9ac8241fa53a Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Thu, 3 Sep 2020 22:41:55 +0100 Subject: [PATCH 090/254] Clean the code --- simple-factory/README.md | 128 ------------------ simple-factory/etc/simple-factory.urm.puml | 35 ----- simple-factory/pom.xml | 41 ------ .../java/com/iluwatar/simplefactory/App.java | 42 ------ .../java/com/iluwatar/simplefactory/Car.java | 10 -- .../simplefactory/CarSimpleFactory.java | 25 ---- .../com/iluwatar/simplefactory/Ferrari.java | 14 -- .../java/com/iluwatar/simplefactory/Ford.java | 14 -- .../com/iluwatar/simplefactory/AppTest.java | 14 -- .../simplefactory/CarSimpleFactoryTest.java | 15 -- 10 files changed, 338 deletions(-) delete mode 100644 simple-factory/README.md delete mode 100644 simple-factory/etc/simple-factory.urm.puml delete mode 100644 simple-factory/pom.xml delete mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/App.java delete mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java delete mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java delete mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java delete mode 100644 simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java delete mode 100644 simple-factory/src/test/java/com/iluwatar/simplefactory/AppTest.java delete mode 100644 simple-factory/src/test/java/com/iluwatar/simplefactory/CarSimpleFactoryTest.java diff --git a/simple-factory/README.md b/simple-factory/README.md deleted file mode 100644 index 1d069a6dd..000000000 --- a/simple-factory/README.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -layout: pattern -title: Simple Factory -folder: simple-factory -permalink: /patterns/simple-factory/ -categories: Creational -tags: - - Gang of Four ---- - -## Also known as - -* Factory -* Static Factory Method - -## Intent - -Providing a static method encapsulated in a class called factory, in order to hide the implementation logic and makes client code focus on usage rather then initialization new objects. - -## Explanation - -Real world example - -> Lets say we have a web application connected to SQLServer, but now we want to switch to Oracle. To do so without modifying existing source code, we need to implements Simple Factory pattern, in which a static method can be invoked to create connection to a given database. - -Wikipedia says - -> Factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class. - -**Programmatic Example** - -We have an interface "Car" and tow implementations "Ford" and "Ferrari". - -```java -/** - * Car interface. - */ -public interface Car { - - public String getDescription(); - -} - -/** - * Ford implementation. - */ -public class Ford implements Car { - - static final String DESCRIPTION = "This is Ford."; - - @Override - public String getDescription() { - return DESCRIPTION; - } -} - -/** - * Ferrari implementation. - */ -public class Ferrari implements Car { - - static final String DESCRIPTION = "This is Ferrari."; - - @Override - public String getDescription() { - return DESCRIPTION; - } -} -``` - -Then we have the static method "getCar" to create car objects encapsulated in the factory class "CarSimpleFactory". - -```java -/** - * Factory of cars. - */ -public class CarSimpleFactory { - - /** - * Enumeration for different types of cars. - */ - static enum CarType { - FORD, FERRARI - } - - /** - * Factory method takes as parameter a car type and initiate the appropriate class. - */ - public static Car getCar(CarType type) { - switch (type) { - case FORD: return new Ford(); - case FERRARI: return new Ferrari(); - default: throw new IllegalArgumentException("Model not supported."); - } - } -} -``` - -Now on the client code we can create differentes types of cars(Ford or Ferrari) using the factory class. - -```java -Car car1 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FORD); -Car car2 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FERRARI); -LOGGER.info(car1.getDescription()); -LOGGER.info(car2.getDescription()); -``` - -Program output: - -```java -This is Ford. -This Ferrari. -``` -## Applicability - -Use the Simple Factory pattern when you only care about the creation of a object, not how to create and manage it. - -## Disadvantages: - -The code becomes more complicated than it should be. - -## Related patterns - -[Factory Method](https://java-design-patterns.com/patterns/factory-method/) -[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) -[Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) - - diff --git a/simple-factory/etc/simple-factory.urm.puml b/simple-factory/etc/simple-factory.urm.puml deleted file mode 100644 index 77fee4b5b..000000000 --- a/simple-factory/etc/simple-factory.urm.puml +++ /dev/null @@ -1,35 +0,0 @@ -@startuml -package com.iluwatar.simplefactory { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - interface Car { - + getDescription() : String {abstract} - } - class CarSimpleFactory { - + CarSimpleFactory() - + getCar(type : CarType) : Car {static} - } - ~enum CarType { - + FERRARI {static} - + FORD {static} - + valueOf(name : String) : CarType {static} - + values() : CarType[] {static} - } - class Ferrari { - ~ DESCRIPTION : String {static} - + Ferrari() - + getDescription() : String - } - class Ford { - ~ DESCRIPTION : String {static} - + Ford() - + getDescription() : String - } -} -CarType ..+ CarSimpleFactory -Ferrari ..|> Car -Ford ..|> Car -@enduml \ No newline at end of file diff --git a/simple-factory/pom.xml b/simple-factory/pom.xml deleted file mode 100644 index ca7c0547d..000000000 --- a/simple-factory/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.24.0-SNAPSHOT - - simple-factory - - - org.junit.jupiter - junit-jupiter-engine - test - - - junit - junit - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.simplefactory.App - - - - - - - - - \ No newline at end of file diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/App.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/App.java deleted file mode 100644 index f13566ba6..000000000 --- a/simple-factory/src/main/java/com/iluwatar/simplefactory/App.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * The MIT License - * Copyright © 2014-2019 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.simplefactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class App { - - private static final Logger LOGGER = LoggerFactory.getLogger(App.class); - - /** - * Program main entry point. - */ - public static void main(String[] args) { - Car car1 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FORD); - Car car2 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FERRARI); - LOGGER.info(car1.getDescription()); - LOGGER.info(car2.getDescription()); - } -} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java deleted file mode 100644 index b87070040..000000000 --- a/simple-factory/src/main/java/com/iluwatar/simplefactory/Car.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.iluwatar.simplefactory; - -/** - * Car interface. - */ -public interface Car { - - public String getDescription(); - -} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java deleted file mode 100644 index 911fe610f..000000000 --- a/simple-factory/src/main/java/com/iluwatar/simplefactory/CarSimpleFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.iluwatar.simplefactory; - -/** - * Factory of cars. - */ -public class CarSimpleFactory { - - /** - * Enumeration for different types of cars. - */ - static enum CarType { - FORD, FERRARI - } - - /** - * Factory method takes as parameter a car type and initiate the appropriate class. - */ - public static Car getCar(CarType type) { - switch (type) { - case FORD: return new Ford(); - case FERRARI: return new Ferrari(); - default: throw new IllegalArgumentException("Model not supported."); - } - } -} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java deleted file mode 100644 index d6e865182..000000000 --- a/simple-factory/src/main/java/com/iluwatar/simplefactory/Ferrari.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.iluwatar.simplefactory; - -/** - * Ferrari implementation. - */ -public class Ferrari implements Car { - - static final String DESCRIPTION = "This is Ferrari."; - - @Override - public String getDescription() { - return DESCRIPTION; - } -} diff --git a/simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java b/simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java deleted file mode 100644 index 19cbea2ae..000000000 --- a/simple-factory/src/main/java/com/iluwatar/simplefactory/Ford.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.iluwatar.simplefactory; - -/** - * Ford implementation. - */ -public class Ford implements Car { - - static final String DESCRIPTION = "This is Ford."; - - @Override - public String getDescription() { - return DESCRIPTION; - } -} diff --git a/simple-factory/src/test/java/com/iluwatar/simplefactory/AppTest.java b/simple-factory/src/test/java/com/iluwatar/simplefactory/AppTest.java deleted file mode 100644 index 4465b3b8c..000000000 --- a/simple-factory/src/test/java/com/iluwatar/simplefactory/AppTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.iluwatar.simplefactory; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; - -class AppTest { - - @Test - void shouldExecuteWithoutExceptions() { - assertDoesNotThrow(() -> App.main(new String[]{})); - } - -} diff --git a/simple-factory/src/test/java/com/iluwatar/simplefactory/CarSimpleFactoryTest.java b/simple-factory/src/test/java/com/iluwatar/simplefactory/CarSimpleFactoryTest.java deleted file mode 100644 index 394b652b6..000000000 --- a/simple-factory/src/test/java/com/iluwatar/simplefactory/CarSimpleFactoryTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.iluwatar.simplefactory; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; - -class CarSimpleFactoryTest { - - @Test - void shouldReturnFerrariInstance() { - final var ferrari = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FERRARI); - assertTrue(ferrari instanceof Ferrari); - } - -} From 8b26452c75a8529ef3407d643fa33a1a2799a825 Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Thu, 3 Sep 2020 22:58:15 +0100 Subject: [PATCH 091/254] bug fixing --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cc59a846a..da3084ab2 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ arrange-act-assert transaction-script filterer - simple-factory + factory From bd48d6ce1046c51aaf93ee48f4887ba4b04e89fd Mon Sep 17 00:00:00 2001 From: Vladislav Golubinov Date: Fri, 4 Sep 2020 17:31:50 +0300 Subject: [PATCH 092/254] refactor --- .../com/iluwatar/abstractfactory/App.java | 82 +++++-------------- .../com/iluwatar/abstractfactory/Kingdom.java | 38 +++++++++ .../abstractfactory/AbstractFactoryTest.java | 47 ++++++----- 3 files changed, 88 insertions(+), 79 deletions(-) create mode 100644 abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index 6cdaf865f..71af19b37 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -23,12 +23,8 @@ package com.iluwatar.abstractfactory; -import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType; import lombok.Getter; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that @@ -45,55 +41,10 @@ import org.slf4j.LoggerFactory; * both concrete implementations to create a king, a castle and an army. */ @Slf4j -public class App { +public class App implements Runnable { - @Setter @Getter - private King king; - - @Setter - @Getter - private Castle castle; - - @Setter - @Getter - private Army army; - - /** - * Creates kingdom. - */ - public void createKingdom(final KingdomFactory factory) { - setKing(factory.createKing()); - setCastle(factory.createCastle()); - setArmy(factory.createArmy()); - } - - /** - * The factory of kingdom factories. - */ - public static class FactoryMaker { - - /** - * Enumeration for the different types of Kingdoms. - */ - public enum KingdomType { - ELF, ORC - } - - /** - * The factory method to create KingdomFactory concrete objects. - */ - public static KingdomFactory makeFactory(KingdomType type) { - switch (type) { - case ELF: - return new ElfKingdomFactory(); - case ORC: - return new OrcKingdomFactory(); - default: - throw new IllegalArgumentException("KingdomType not supported."); - } - } - } + private final Kingdom kingdom = new Kingdom(); /** * Program entry point. @@ -101,19 +52,30 @@ public class App { * @param args command line args */ public static void main(String[] args) { - var app = new App(); + } + @Override + public void run() { log.info("Elf Kingdom"); - app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF)); - log.info(app.getArmy().getDescription()); - log.info(app.getCastle().getDescription()); - log.info(app.getKing().getDescription()); + createKingdom(Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ELF)); + log.info(kingdom.getArmy().getDescription()); + log.info(kingdom.getCastle().getDescription()); + log.info(kingdom.getKing().getDescription()); log.info("Orc Kingdom"); - app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC)); - log.info(app.getArmy().getDescription()); - log.info(app.getCastle().getDescription()); - log.info(app.getKing().getDescription()); + createKingdom(Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ORC)); + log.info(kingdom.getArmy().getDescription()); + log.info(kingdom.getCastle().getDescription()); + log.info(kingdom.getKing().getDescription()); + } + + /** + * Creates kingdom. + */ + public void createKingdom(final KingdomFactory factory) { + kingdom.setKing(factory.createKing()); + kingdom.setCastle(factory.createCastle()); + kingdom.setArmy(factory.createArmy()); } } \ No newline at end of file diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java new file mode 100644 index 000000000..6e24005ab --- /dev/null +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java @@ -0,0 +1,38 @@ +package com.iluwatar.abstractfactory; + +import lombok.Data; + +@Data +public class Kingdom { + + private King king; + private Castle castle; + private Army army; + + /** + * The factory of kingdom factories. + */ + public static class FactoryMaker { + + /** + * Enumeration for the different types of Kingdoms. + */ + public enum KingdomType { + ELF, ORC + } + + /** + * The factory method to create KingdomFactory concrete objects. + */ + public static KingdomFactory makeFactory(KingdomType type) { + switch (type) { + case ELF: + return new ElfKingdomFactory(); + case ORC: + return new OrcKingdomFactory(); + default: + throw new IllegalArgumentException("KingdomType not supported."); + } + } + } +} diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java index 1506844cf..db6fd04ee 100644 --- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java +++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java @@ -23,14 +23,13 @@ package com.iluwatar.abstractfactory; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.iluwatar.abstractfactory.App.FactoryMaker; -import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType; +import lombok.val; 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.assertTrue; + /** * Test for abstract factory. */ @@ -42,19 +41,21 @@ public class AbstractFactoryTest { @BeforeEach public void setUp() { - elfFactory = FactoryMaker.makeFactory(KingdomType.ELF); - orcFactory = FactoryMaker.makeFactory(KingdomType.ORC); + elfFactory = Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ELF); + orcFactory = Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ORC); } @Test public void king() { app.createKingdom(elfFactory); - final var elfKing = app.getKing(); + val kingdom = app.getKingdom(); + + val elfKing = kingdom.getKing(); assertTrue(elfKing instanceof ElfKing); assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription()); app.createKingdom(orcFactory); - final var orcKing = app.getKing(); + val orcKing = kingdom.getKing(); assertTrue(orcKing instanceof OrcKing); assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription()); } @@ -62,12 +63,14 @@ public class AbstractFactoryTest { @Test public void castle() { app.createKingdom(elfFactory); - final var elfCastle = app.getCastle(); + val kingdom = app.getKingdom(); + + val elfCastle = kingdom.getCastle(); assertTrue(elfCastle instanceof ElfCastle); assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription()); app.createKingdom(orcFactory); - final var orcCastle = app.getCastle(); + val orcCastle = kingdom.getCastle(); assertTrue(orcCastle instanceof OrcCastle); assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription()); } @@ -75,12 +78,14 @@ public class AbstractFactoryTest { @Test public void army() { app.createKingdom(elfFactory); - final var elfArmy = app.getArmy(); + val kingdom = app.getKingdom(); + + val elfArmy = kingdom.getArmy(); assertTrue(elfArmy instanceof ElfArmy); assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription()); app.createKingdom(orcFactory); - final var orcArmy = app.getArmy(); + val orcArmy = kingdom.getArmy(); assertTrue(orcArmy instanceof OrcArmy); assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription()); } @@ -88,9 +93,11 @@ public class AbstractFactoryTest { @Test public void createElfKingdom() { app.createKingdom(elfFactory); - final var king = app.getKing(); - final var castle = app.getCastle(); - final var army = app.getArmy(); + val kingdom = app.getKingdom(); + + val king = kingdom.getKing(); + val castle = kingdom.getCastle(); + val army = kingdom.getArmy(); assertTrue(king instanceof ElfKing); assertEquals(ElfKing.DESCRIPTION, king.getDescription()); assertTrue(castle instanceof ElfCastle); @@ -102,9 +109,11 @@ public class AbstractFactoryTest { @Test public void createOrcKingdom() { app.createKingdom(orcFactory); - final var king = app.getKing(); - final var castle = app.getCastle(); - final var army = app.getArmy(); + val kingdom = app.getKingdom(); + + val king = kingdom.getKing(); + val castle = kingdom.getCastle(); + val army = kingdom.getArmy(); assertTrue(king instanceof OrcKing); assertEquals(OrcKing.DESCRIPTION, king.getDescription()); assertTrue(castle instanceof OrcCastle); From 6caf78e4e57fe98fde7813f9129437f530022f63 Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Fri, 4 Sep 2020 21:21:51 +0100 Subject: [PATCH 093/254] updates : - Using lambda expression to create cars - Using spaces instead of tabs in pom.xml --- factory/README.md | 45 ++++++++++++------- factory/pom.xml | 42 ++++++++--------- .../main/java/com/iluwatar/factory/App.java | 4 +- .../java/com/iluwatar/factory/CarType.java | 22 +++++++++ .../com/iluwatar/factory/CarsFactory.java | 13 +----- .../com/iluwatar/factory/CarsFactoryTest.java | 2 +- 6 files changed, 76 insertions(+), 52 deletions(-) create mode 100644 factory/src/main/java/com/iluwatar/factory/CarType.java diff --git a/factory/README.md b/factory/README.md index 42c8838a3..62478e4a9 100644 --- a/factory/README.md +++ b/factory/README.md @@ -68,41 +68,52 @@ public class Ferrari implements Car { } ``` +Enumeration above represents types of cars that we support(Ford and Ferrari). + +```java +public enum CarType { + + /** + * Enumeration for different types of cars. + */ + FORD(Ford::new), + FERRARI(Ferrari::new); + + private final Supplier constructor; + + CarType(Supplier constructor) { + this.constructor = constructor; + } + + public Supplier getConstructor() { + return this.constructor; + } +} +``` Then we have the static method "getCar" to create car objects encapsulated in the factory class "CarSimpleFactory". ```java /** * Factory of cars. */ -public class CarSimpleFactory { - - /** - * Enumeration for different types of cars. - */ - static enum CarType { - FORD, FERRARI - } +public class CarsFactory { /** * Factory method takes as parameter a car type and initiate the appropriate class. */ public static Car getCar(CarType type) { - switch (type) { - case FORD: return new Ford(); - case FERRARI: return new Ferrari(); - default: throw new IllegalArgumentException("Model not supported."); - } + return type.getConstructor().get(); } } ``` -Now on the client code we can create differentes types of cars(Ford or Ferrari) using the factory class. +Now on the client code we can create different types of cars using the factory class. ```java -Car car1 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FORD); -Car car2 = CarSimpleFactory.getCar(CarSimpleFactory.CarType.FERRARI); +var car1 = CarsFactory.getCar(CarType.FORD); +var car2 = CarsFactory.getCar(CarType.FERRARI); LOGGER.info(car1.getDescription()); -LOGGER.info(car2.getDescription()); +LOGGER.info(car2.getDescription());; ``` Program output: diff --git a/factory/pom.xml b/factory/pom.xml index fbca994a7..2a422db90 100644 --- a/factory/pom.xml +++ b/factory/pom.xml @@ -1,23 +1,25 @@ - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.24.0-SNAPSHOT - - factory - - - org.junit.jupiter - junit-jupiter-engine - test - - - junit - junit - - - + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.24.0-SNAPSHOT + + factory + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + + + diff --git a/factory/src/main/java/com/iluwatar/factory/App.java b/factory/src/main/java/com/iluwatar/factory/App.java index 13f217646..22c50d86d 100644 --- a/factory/src/main/java/com/iluwatar/factory/App.java +++ b/factory/src/main/java/com/iluwatar/factory/App.java @@ -43,8 +43,8 @@ public class App { * Program main entry point. */ public static void main(String[] args) { - var car1 = CarsFactory.getCar(CarsFactory.CarType.FORD); - var car2 = CarsFactory.getCar(CarsFactory.CarType.FERRARI); + var car1 = CarsFactory.getCar(CarType.FORD); + var car2 = CarsFactory.getCar(CarType.FERRARI); LOGGER.info(car1.getDescription()); LOGGER.info(car2.getDescription()); } diff --git a/factory/src/main/java/com/iluwatar/factory/CarType.java b/factory/src/main/java/com/iluwatar/factory/CarType.java new file mode 100644 index 000000000..5878025bd --- /dev/null +++ b/factory/src/main/java/com/iluwatar/factory/CarType.java @@ -0,0 +1,22 @@ +package com.iluwatar.factory; + +import java.util.function.Supplier; + +public enum CarType { + + /** + * Enumeration for different types of cars. + */ + FORD(Ford::new), + FERRARI(Ferrari::new); + + private final Supplier constructor; + + CarType(Supplier constructor) { + this.constructor = constructor; + } + + public Supplier getConstructor() { + return this.constructor; + } +} diff --git a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java index 01ad157ca..76b83d0be 100644 --- a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java +++ b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java @@ -5,21 +5,10 @@ package com.iluwatar.factory; */ public class CarsFactory { - /** - * Enumeration for different types of cars. - */ - static enum CarType { - FORD, FERRARI - } - /** * Factory method takes as parameter a car type and initiate the appropriate class. */ public static Car getCar(CarType type) { - switch (type) { - case FORD: return new Ford(); - case FERRARI: return new Ferrari(); - default: throw new IllegalArgumentException("Model not supported."); - } + return type.getConstructor().get(); } } diff --git a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java index eae75919a..fc823c6d4 100644 --- a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java +++ b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java @@ -8,7 +8,7 @@ class CarsFactoryTest { @Test void shouldReturnFerrariInstance() { - final var ferrari = CarsFactory.getCar(CarsFactory.CarType.FERRARI); + final var ferrari = CarsFactory.getCar(CarType.FERRARI); assertTrue(ferrari instanceof Ferrari); } From b3ef214cd62f80368698929f8814099c0ad0a3ad Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Fri, 4 Sep 2020 22:02:19 +0100 Subject: [PATCH 094/254] Change tabs to spaces in pom.xml --- factory/pom.xml | 82 ++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/factory/pom.xml b/factory/pom.xml index 2a422db90..fff262458 100644 --- a/factory/pom.xml +++ b/factory/pom.xml @@ -1,43 +1,43 @@ - 4.0.0 - - com.iluwatar - java-design-patterns - 1.24.0-SNAPSHOT - - factory - - - org.junit.jupiter - junit-jupiter-engine - test - - - junit - junit - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.factory.App - - - - - - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + com.iluwatar + java-design-patterns + 1.24.0-SNAPSHOT + + factory + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.factory.App + + + + + + + + \ No newline at end of file From bf41b1d9c98782dbb3368c44cbba934c257f483a Mon Sep 17 00:00:00 2001 From: Samil Ayoub Date: Sat, 5 Sep 2020 18:39:28 +0100 Subject: [PATCH 095/254] Updates README.md: - Adding class diagram - Adding Pros and Cons - replace "" with '' --- factory/README.md | 17 +++++++++++------ factory/etc/factory.urm.png | Bin 0 -> 25438 bytes 2 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 factory/etc/factory.urm.png diff --git a/factory/README.md b/factory/README.md index 62478e4a9..9ab61b579 100644 --- a/factory/README.md +++ b/factory/README.md @@ -29,7 +29,7 @@ Wikipedia says **Programmatic Example** -We have an interface "Car" and tow implementations "Ford" and "Ferrari". +We have an interface 'Car' and tow implementations 'Ford' and 'Ferrari'. ```java /** @@ -68,7 +68,7 @@ public class Ferrari implements Car { } ``` -Enumeration above represents types of cars that we support(Ford and Ferrari). +Enumeration above represents types of cars that we support (Ford and Ferrari). ```java public enum CarType { @@ -90,7 +90,7 @@ public enum CarType { } } ``` -Then we have the static method "getCar" to create car objects encapsulated in the factory class "CarSimpleFactory". +Then we have the static method 'getCar' to create car objects encapsulated in the factory class 'CarSimpleFactory'. ```java /** @@ -122,13 +122,18 @@ Program output: This is Ford. This Ferrari. ``` -## Applicability +## Class Diagram +![alt text](./etc/factory.urm.png "Factory pattern class diagram") +## Applicability Use the Simple Factory pattern when you only care about the creation of a object, not how to create and manage it. -## Disadvantages: +## Pros +* Allows keeping all objects creation in one place and avoid of spreading 'new' key value across codebase. +* Allows to writs loosely coupled code. Some of its main advantages include better testability, easy-to-understand code, swappable components, scalability and isolated features. -The code becomes more complicated than it should be. +## Cons +* The code becomes more complicated than it should be. ## Related patterns diff --git a/factory/etc/factory.urm.png b/factory/etc/factory.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba39a571c4efd3d5cfd45854f0d26c843fafd8e GIT binary patch literal 25438 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 literal 0 HcmV?d00001 From 2e36a11e24b09f43c0a6983f29191596d50c18e9 Mon Sep 17 00:00:00 2001 From: Vladislav Golubinov Date: Sun, 6 Sep 2020 11:42:39 +0300 Subject: [PATCH 096/254] remove lombok, related to #1503 --- abstract-factory/pom.xml | 5 --- .../com/iluwatar/abstractfactory/App.java | 14 +++++--- .../com/iluwatar/abstractfactory/Kingdom.java | 27 ++++++++++++-- .../abstractfactory/AbstractFactoryTest.java | 35 +++++++++---------- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index e10a9436f..2328c60a8 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -31,11 +31,6 @@ junit-jupiter-engine test - - org.projectlombok - lombok - 1.18.12 - diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index 71af19b37..bebf5c894 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -23,8 +23,10 @@ package com.iluwatar.abstractfactory; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; /** * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that @@ -40,12 +42,16 @@ import lombok.extern.slf4j.Slf4j; * and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses * both concrete implementations to create a king, a castle and an army. */ -@Slf4j public class App implements Runnable { - @Getter + private static Logger log = LoggerFactory.getLogger(App.class); + private final Kingdom kingdom = new Kingdom(); + public Kingdom getKingdom() { + return kingdom; + } + /** * Program entry point. * diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java index 6e24005ab..82fa0b368 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java @@ -1,14 +1,35 @@ package com.iluwatar.abstractfactory; -import lombok.Data; - -@Data public class Kingdom { private King king; private Castle castle; private Army army; + public King getKing() { + return king; + } + + public Castle getCastle() { + return castle; + } + + public Army getArmy() { + return army; + } + + public void setKing(King king) { + this.king = king; + } + + public void setCastle(Castle castle) { + this.castle = castle; + } + + public void setArmy(Army army) { + this.army = army; + } + /** * The factory of kingdom factories. */ diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java index db6fd04ee..54c3b68f1 100644 --- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java +++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java @@ -23,7 +23,6 @@ package com.iluwatar.abstractfactory; -import lombok.val; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,14 +47,14 @@ public class AbstractFactoryTest { @Test public void king() { app.createKingdom(elfFactory); - val kingdom = app.getKingdom(); + final var kingdom = app.getKingdom(); - val elfKing = kingdom.getKing(); + final var elfKing = kingdom.getKing(); assertTrue(elfKing instanceof ElfKing); assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription()); app.createKingdom(orcFactory); - val orcKing = kingdom.getKing(); + final var orcKing = kingdom.getKing(); assertTrue(orcKing instanceof OrcKing); assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription()); } @@ -63,14 +62,14 @@ public class AbstractFactoryTest { @Test public void castle() { app.createKingdom(elfFactory); - val kingdom = app.getKingdom(); + final var kingdom = app.getKingdom(); - val elfCastle = kingdom.getCastle(); + final var elfCastle = kingdom.getCastle(); assertTrue(elfCastle instanceof ElfCastle); assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription()); app.createKingdom(orcFactory); - val orcCastle = kingdom.getCastle(); + final var orcCastle = kingdom.getCastle(); assertTrue(orcCastle instanceof OrcCastle); assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription()); } @@ -78,14 +77,14 @@ public class AbstractFactoryTest { @Test public void army() { app.createKingdom(elfFactory); - val kingdom = app.getKingdom(); + final var kingdom = app.getKingdom(); - val elfArmy = kingdom.getArmy(); + final var elfArmy = kingdom.getArmy(); assertTrue(elfArmy instanceof ElfArmy); assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription()); app.createKingdom(orcFactory); - val orcArmy = kingdom.getArmy(); + final var orcArmy = kingdom.getArmy(); assertTrue(orcArmy instanceof OrcArmy); assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription()); } @@ -93,11 +92,11 @@ public class AbstractFactoryTest { @Test public void createElfKingdom() { app.createKingdom(elfFactory); - val kingdom = app.getKingdom(); + final var kingdom = app.getKingdom(); - val king = kingdom.getKing(); - val castle = kingdom.getCastle(); - val army = kingdom.getArmy(); + final var king = kingdom.getKing(); + final var castle = kingdom.getCastle(); + final var army = kingdom.getArmy(); assertTrue(king instanceof ElfKing); assertEquals(ElfKing.DESCRIPTION, king.getDescription()); assertTrue(castle instanceof ElfCastle); @@ -109,11 +108,11 @@ public class AbstractFactoryTest { @Test public void createOrcKingdom() { app.createKingdom(orcFactory); - val kingdom = app.getKingdom(); + final var kingdom = app.getKingdom(); - val king = kingdom.getKing(); - val castle = kingdom.getCastle(); - val army = kingdom.getArmy(); + final var king = kingdom.getKing(); + final var castle = kingdom.getCastle(); + final var army = kingdom.getArmy(); assertTrue(king instanceof OrcKing); assertEquals(OrcKing.DESCRIPTION, king.getDescription()); assertTrue(castle instanceof OrcCastle); From 87cf6b791cefcba99a5894141078464d2805c870 Mon Sep 17 00:00:00 2001 From: Vladislav Golubinov Date: Sun, 6 Sep 2020 11:48:40 +0300 Subject: [PATCH 097/254] refactor --- .../com/iluwatar/abstractfactory/App.java | 16 ++++++------ .../abstractfactory/AbstractFactoryTest.java | 25 ++++++------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index bebf5c894..05aa8d118 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -26,8 +26,6 @@ package com.iluwatar.abstractfactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; - /** * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that * have a common theme without specifying their concrete classes. In normal usage, the client @@ -64,13 +62,13 @@ public class App implements Runnable { @Override public void run() { log.info("Elf Kingdom"); - createKingdom(Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ELF)); + createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); log.info(kingdom.getArmy().getDescription()); log.info(kingdom.getCastle().getDescription()); log.info(kingdom.getKing().getDescription()); log.info("Orc Kingdom"); - createKingdom(Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ORC)); + createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); log.info(kingdom.getArmy().getDescription()); log.info(kingdom.getCastle().getDescription()); log.info(kingdom.getKing().getDescription()); @@ -78,10 +76,12 @@ public class App implements Runnable { /** * Creates kingdom. + * @param kingdomType */ - public void createKingdom(final KingdomFactory factory) { - kingdom.setKing(factory.createKing()); - kingdom.setCastle(factory.createCastle()); - kingdom.setArmy(factory.createArmy()); + public void createKingdom(final Kingdom.FactoryMaker.KingdomType kingdomType) { + final KingdomFactory kingdomFactory = Kingdom.FactoryMaker.makeFactory(kingdomType); + kingdom.setKing(kingdomFactory.createKing()); + kingdom.setCastle(kingdomFactory.createCastle()); + kingdom.setArmy(kingdomFactory.createArmy()); } } \ No newline at end of file diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java index 54c3b68f1..17c09be88 100644 --- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java +++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java @@ -23,7 +23,6 @@ package com.iluwatar.abstractfactory; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -35,25 +34,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class AbstractFactoryTest { private final App app = new App(); - private KingdomFactory elfFactory; - private KingdomFactory orcFactory; - - @BeforeEach - public void setUp() { - elfFactory = Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ELF); - orcFactory = Kingdom.FactoryMaker.makeFactory(Kingdom.FactoryMaker.KingdomType.ORC); - } @Test public void king() { - app.createKingdom(elfFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); final var kingdom = app.getKingdom(); final var elfKing = kingdom.getKing(); assertTrue(elfKing instanceof ElfKing); assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription()); - app.createKingdom(orcFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); final var orcKing = kingdom.getKing(); assertTrue(orcKing instanceof OrcKing); assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription()); @@ -61,14 +52,14 @@ public class AbstractFactoryTest { @Test public void castle() { - app.createKingdom(elfFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); final var kingdom = app.getKingdom(); final var elfCastle = kingdom.getCastle(); assertTrue(elfCastle instanceof ElfCastle); assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription()); - app.createKingdom(orcFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); final var orcCastle = kingdom.getCastle(); assertTrue(orcCastle instanceof OrcCastle); assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription()); @@ -76,14 +67,14 @@ public class AbstractFactoryTest { @Test public void army() { - app.createKingdom(elfFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); final var kingdom = app.getKingdom(); final var elfArmy = kingdom.getArmy(); assertTrue(elfArmy instanceof ElfArmy); assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription()); - app.createKingdom(orcFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); final var orcArmy = kingdom.getArmy(); assertTrue(orcArmy instanceof OrcArmy); assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription()); @@ -91,7 +82,7 @@ public class AbstractFactoryTest { @Test public void createElfKingdom() { - app.createKingdom(elfFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); final var kingdom = app.getKingdom(); final var king = kingdom.getKing(); @@ -107,7 +98,7 @@ public class AbstractFactoryTest { @Test public void createOrcKingdom() { - app.createKingdom(orcFactory); + app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); final var kingdom = app.getKingdom(); final var king = kingdom.getKing(); From 29eecfd0489c79c8c86850039e55b3bff008d377 Mon Sep 17 00:00:00 2001 From: Vladislav Golubinov Date: Sun, 6 Sep 2020 11:52:16 +0300 Subject: [PATCH 098/254] forgot to run the App --- .../src/main/java/com/iluwatar/abstractfactory/App.java | 1 + 1 file changed, 1 insertion(+) diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index 05aa8d118..2d49768ec 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -57,6 +57,7 @@ public class App implements Runnable { */ public static void main(String[] args) { var app = new App(); + app.run(); } @Override From bab48efd7c24ee74ba4ad599d08b9942814a57ca Mon Sep 17 00:00:00 2001 From: Vladislav Golubinov Date: Sun, 6 Sep 2020 12:01:48 +0300 Subject: [PATCH 099/254] fix style --- .../src/main/java/com/iluwatar/abstractfactory/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index 2d49768ec..baf2d7569 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -77,7 +77,7 @@ public class App implements Runnable { /** * Creates kingdom. - * @param kingdomType + * @param kingdomType type of Kingdom */ public void createKingdom(final Kingdom.FactoryMaker.KingdomType kingdomType) { final KingdomFactory kingdomFactory = Kingdom.FactoryMaker.makeFactory(kingdomType); From d72206ba72736013b24803d703fffcab4fa1c686 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:35:57 +0000 Subject: [PATCH 100/254] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e64d4c15b..4a214d770 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-130-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-131-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -264,6 +264,7 @@ This project is licensed under the terms of the MIT license.
Stefan Birkner

💻
Fedor Skvorcov

💻 +
samilAyoub

💻 From b9db3c476306cde8090756490cb006bf56200bb8 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:35:58 +0000 Subject: [PATCH 101/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index e0ef0200b..6b8a654ae 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1185,6 +1185,15 @@ "contributions": [ "code" ] + }, + { + "login": "samilAyoub", + "name": "samilAyoub", + "avatar_url": "https://avatars0.githubusercontent.com/u/61546990?v=4", + "profile": "https://github.com/samilAyoub", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From 3205dc2cf022c9c0678413b42dd06992565b6e66 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:37:03 +0000 Subject: [PATCH 102/254] docs: update README.md [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a11ce5f89..f0966bfd9 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ This project is licensed under the terms of the MIT license.
Nishant Arora

💻
Peeyush

💻 -
Rakesh

💻 +
Rakesh

💻 👀 From 8d6738b729b9e953e987149fd2f0e6440dba7b60 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:37:04 +0000 Subject: [PATCH 103/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7f632c157..5a1c8f57c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1082,7 +1082,8 @@ "avatar_url": "https://avatars1.githubusercontent.com/u/10645273?v=4", "profile": "https://github.com/ravening", "contributions": [ - "code" + "code", + "review" ] } ], From a1da1e4973d82ebf958175b34b27710a8ec0b715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 6 Sep 2020 19:46:13 +0300 Subject: [PATCH 104/254] Cleanup factory --- factory/README.md | 51 +++++++------------ .../main/java/com/iluwatar/factory/Car.java | 2 +- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/factory/README.md b/factory/README.md index 9ab61b579..5fd97ccae 100644 --- a/factory/README.md +++ b/factory/README.md @@ -15,35 +15,31 @@ tags: ## Intent -Providing a static method encapsulated in a class called factory, in order to hide the implementation logic and makes client code focus on usage rather then initialization new objects. +Providing a static method encapsulated in a class called factory, in order to hide the +implementation logic and makes client code focus on usage rather then initialization new objects. ## Explanation Real world example -> Lets say we have a web application connected to SQLServer, but now we want to switch to Oracle. To do so without modifying existing source code, we need to implements Simple Factory pattern, in which a static method can be invoked to create connection to a given database. +> Lets say we have a web application connected to SQLServer, but now we want to switch to Oracle. To +> do so without modifying existing source code, we need to implements Simple Factory pattern, in +> which a static method can be invoked to create connection to a given database. Wikipedia says -> Factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class. +> Factory is an object for creating other objects – formally a factory is a function or method that +> returns objects of a varying prototype or class. **Programmatic Example** -We have an interface 'Car' and tow implementations 'Ford' and 'Ferrari'. +We have an interface `Car` and two implementations `Ford` and `Ferrari`. ```java -/** - * Car interface. - */ public interface Car { - - public String getDescription(); - + String getDescription(); } -/** - * Ford implementation. - */ public class Ford implements Car { static final String DESCRIPTION = "This is Ford."; @@ -54,9 +50,6 @@ public class Ford implements Car { } } -/** - * Ferrari implementation. - */ public class Ferrari implements Car { static final String DESCRIPTION = "This is Ferrari."; @@ -68,14 +61,11 @@ public class Ferrari implements Car { } ``` -Enumeration above represents types of cars that we support (Ford and Ferrari). +Enumeration above represents types of cars that we support (`Ford` and `Ferrari`). ```java public enum CarType { - /** - * Enumeration for different types of cars. - */ FORD(Ford::new), FERRARI(Ferrari::new); @@ -90,17 +80,12 @@ public enum CarType { } } ``` -Then we have the static method 'getCar' to create car objects encapsulated in the factory class 'CarSimpleFactory'. +Then we have the static method `getCar` to create car objects encapsulated in the factory class +`CarSimpleFactory`. ```java -/** - * Factory of cars. - */ public class CarsFactory { - /** - * Factory method takes as parameter a car type and initiate the appropriate class. - */ public static Car getCar(CarType type) { return type.getConstructor().get(); } @@ -122,17 +107,21 @@ Program output: This is Ford. This Ferrari. ``` + ## Class Diagram + ![alt text](./etc/factory.urm.png "Factory pattern class diagram") ## Applicability -Use the Simple Factory pattern when you only care about the creation of a object, not how to create and manage it. -## Pros +Use the Simple Factory pattern when you only care about the creation of a object, not how to create +and manage it. + +Pros * Allows keeping all objects creation in one place and avoid of spreading 'new' key value across codebase. * Allows to writs loosely coupled code. Some of its main advantages include better testability, easy-to-understand code, swappable components, scalability and isolated features. -## Cons +Cons * The code becomes more complicated than it should be. ## Related patterns @@ -140,5 +129,3 @@ Use the Simple Factory pattern when you only care about the creation of a object [Factory Method](https://java-design-patterns.com/patterns/factory-method/) [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) - - diff --git a/factory/src/main/java/com/iluwatar/factory/Car.java b/factory/src/main/java/com/iluwatar/factory/Car.java index 6f564233c..d1d622b9b 100644 --- a/factory/src/main/java/com/iluwatar/factory/Car.java +++ b/factory/src/main/java/com/iluwatar/factory/Car.java @@ -5,6 +5,6 @@ package com.iluwatar.factory; */ public interface Car { - public String getDescription(); + String getDescription(); } From 8b5f532a50923cb334b06dd7507126f3572af4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 6 Sep 2020 19:55:38 +0300 Subject: [PATCH 105/254] Update README.md --- factory/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/factory/README.md b/factory/README.md index 5fd97ccae..8983f393c 100644 --- a/factory/README.md +++ b/factory/README.md @@ -118,10 +118,12 @@ Use the Simple Factory pattern when you only care about the creation of a object and manage it. Pros + * Allows keeping all objects creation in one place and avoid of spreading 'new' key value across codebase. * Allows to writs loosely coupled code. Some of its main advantages include better testability, easy-to-understand code, swappable components, scalability and isolated features. Cons + * The code becomes more complicated than it should be. ## Related patterns From ef326ee77e03077714f38df36f92ffa58ebaffa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 6 Sep 2020 19:56:07 +0300 Subject: [PATCH 106/254] Update README.md --- factory/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/factory/README.md b/factory/README.md index 8983f393c..a1b6208fd 100644 --- a/factory/README.md +++ b/factory/README.md @@ -128,6 +128,6 @@ Cons ## Related patterns -[Factory Method](https://java-design-patterns.com/patterns/factory-method/) -[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) -[Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) From f6942cf18dab21b354be69a3853c12f6d21b7a60 Mon Sep 17 00:00:00 2001 From: swarajsaaj Date: Thu, 10 Sep 2020 02:57:56 +0530 Subject: [PATCH 107/254] #1313 Add Separated Interface design pattern --- separated-interface/README.md | 119 ++++++++++++++++++ separated-interface/etc/class_diagram.png | Bin 0 -> 32651 bytes .../etc/separated-interface.urm.puml | 36 ++++++ separated-interface/pom.xml | 71 +++++++++++ .../com/iluwatar/separatedinterface/App.java | 61 +++++++++ .../invoice/InvoiceGenerator.java | 28 +++++ .../invoice/TaxCalculator.java | 30 +++++ .../separatedinterface/taxes/DomesticTax.java | 40 ++++++ .../separatedinterface/taxes/ForeignTax.java | 40 ++++++ .../iluwatar/separatedinterface/AppTest.java | 41 ++++++ .../invoice/InvoiceGeneratorTest.java | 25 ++++ .../taxes/DomesticTaxTest.java | 18 +++ .../taxes/ForeignTaxTest.java | 18 +++ 13 files changed, 527 insertions(+) create mode 100644 separated-interface/README.md create mode 100644 separated-interface/etc/class_diagram.png create mode 100644 separated-interface/etc/separated-interface.urm.puml create mode 100644 separated-interface/pom.xml create mode 100644 separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java create mode 100644 separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java create mode 100644 separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java create mode 100644 separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java create mode 100644 separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java create mode 100644 separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java create mode 100644 separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java create mode 100644 separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java create mode 100644 separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java diff --git a/separated-interface/README.md b/separated-interface/README.md new file mode 100644 index 000000000..11ad4a978 --- /dev/null +++ b/separated-interface/README.md @@ -0,0 +1,119 @@ +--- +layout: pattern +title: Separated Interface +folder: separated-interface +permalink: /patterns/separated-interface/ +categories: Architectural +tags: + - Decoupling +--- + + +## Intent +Separate the interface definition and implementation in different packages. This allows the client to be completly unaware of the implementation. + +## Explanation + +Real world example + +> An Invoice generator may be created with ability to use different Tax calculators that may be added in the invoice depending upon type of purchase, region etc. + +In plain words + +> Separated interface pattern encourages to keep the implementations of an interface decoupled from the client and its definition, so the client is not dependent on the implementation. + +A client code may abstract some specific functionality to an interface, and define the definition of the interface as an SPI. Another package may implement this interface definition with a concrete logic, which will be injected into the client code at runtime (with a third class, injecting the implementation in the client) or at compile time (using Plugin pattern with some configurable file). + +**Programmatic Example** + +**Client** An Invoice generator class accepts the cost of the product and calculates the total amount payable inclusive of tax + +```java +public class InvoiceGenerator { + + private final TaxCalculator taxCalculator; + + private final double amount; + + public InvoiceGenerator(double amount, TaxCalculator taxCalculator) { + this.amount = amount; + this.taxCalculator = taxCalculator; + } + + public double getAmountWithTax() { + return amount + taxCalculator.calculate(amount); + } + +} +``` +The tax calculation logic is delegated to the ```TaxCalculator``` interface + +```java + +public interface TaxCalculator { + + double calculate(double amount); + +} + +``` + +**Implementation package** +In another package (which the client is completely unaware of) there exist multiple implementations of the ```TaxCalculator``` interface +```ForeignTax``` which levies 60% tax for international products. +```java +public class ForeignTax implements TaxCalculator { + + public static final double TAX_PERCENTAGE = 60; + + @Override + public double calculate(double amount) { + return amount * TAX_PERCENTAGE / 100.0; + } + +} +``` + +```DomesticTax``` which levies 20% tax for international products. +```java +public class DomesticTax implements TaxCalculator { + + public static final double TAX_PERCENTAGE = 20; + + @Override + public double calculate(double amount) { + return amount * TAX_PERCENTAGE / 100.0; + } + +} +``` + +These both implementations are instantiated and injected in the client class by the ```App.java``` class + +```java + var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTax()); + + LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax()); + + var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTax()); + + LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax()); +``` + +## Class diagram +![alt text](./etc/class_diagram.png "Separated Interface") + +## Applicability +Use the Separated interface pattern when + +* You are developing a framework package, and your framework needs to call some application code through interfaces. +* You have separate packages implementing the functionalities which may be plugged in your client code at runtime or compile-time. +* Your code resides in a layer that is not allowed to call the interface implementation layer by rule. For example, a domain layer needs to call a data mapper. + +## Tutorial + +* [Separated Interface Tutorial](https://www.youtube.com/watch?v=d3k-hOA7k2Y) + +## Credits + +* [Martin Fowler](https://www.martinfowler.com/eaaCatalog/separatedInterface.html) diff --git a/separated-interface/etc/class_diagram.png b/separated-interface/etc/class_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..a0edbac8dac3cd5a0f1dd174fd1cfaa0bbc78e72 GIT binary patch literal 32651 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

@OZmh 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 "-taxCalculator" TaxCalculator +DomesticTax ..|> TaxCalculator +ForeignTax ..|> TaxCalculator +@enduml \ No newline at end of file diff --git a/separated-interface/pom.xml b/separated-interface/pom.xml new file mode 100644 index 000000000..da7584a93 --- /dev/null +++ b/separated-interface/pom.xml @@ -0,0 +1,71 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.24.0-SNAPSHOT + + separated-interface + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.mockito + mockito-core + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.separatedinterface.App + + + + + + + + + diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java new file mode 100644 index 000000000..e0a385c9e --- /dev/null +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java @@ -0,0 +1,61 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.separatedinterface; + +import com.iluwatar.separatedinterface.invoice.InvoiceGenerator; +import com.iluwatar.separatedinterface.taxes.DomesticTax; +import com.iluwatar.separatedinterface.taxes.ForeignTax; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + *

The Strategy pattern (also known as the policy pattern) is a software design pattern that + * enables an algorithm's behavior to be selected at runtime.

+ * + *

Before Java 8 the Strategies needed to be separate classes forcing the developer + * to write lots of boilerplate code. With modern Java it is easy to pass behavior with method + * references and lambdas making the code shorter and more readable.

+ * + */ +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + public static final double PRODUCT_COST = 50.0; + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + //Create the invoice generator with product cost as 50 and foreign product tax + var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTax()); + LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax()); + + //Create the invoice generator with product cost as 50 and domestic product tax + var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTax()); + LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax()); + } +} diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java new file mode 100644 index 000000000..f73ee32d8 --- /dev/null +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java @@ -0,0 +1,28 @@ +package com.iluwatar.separatedinterface.invoice; + +/** + * InvoiceGenerator class generates an invoice, accepting the product cost and calculating the total + * price payable inclusive tax (calculated by {@link TaxCalculator}) + */ +public class InvoiceGenerator { + + /** + * The TaxCalculator interface to calculate the payable tax. + */ + private final TaxCalculator taxCalculator; + + /** + * The base product amount without tax. + */ + private final double amount; + + public InvoiceGenerator(double amount, TaxCalculator taxCalculator) { + this.amount = amount; + this.taxCalculator = taxCalculator; + } + + public double getAmountWithTax() { + return amount + taxCalculator.calculate(amount); + } + +} \ No newline at end of file diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java new file mode 100644 index 000000000..aa4b81a84 --- /dev/null +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java @@ -0,0 +1,30 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.separatedinterface.invoice; + +public interface TaxCalculator { + + double calculate(double amount); + +} diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java new file mode 100644 index 000000000..ebe0e306e --- /dev/null +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java @@ -0,0 +1,40 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.separatedinterface.taxes; + +import com.iluwatar.separatedinterface.invoice.TaxCalculator; + +/** + * TaxCalculator for Domestic goods with 20% tax. + */ +public class DomesticTax implements TaxCalculator { + + public static final double TAX_PERCENTAGE = 20; + + @Override + public double calculate(double amount) { + return amount * TAX_PERCENTAGE / 100.0; + } + +} diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java new file mode 100644 index 000000000..583f70d3b --- /dev/null +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java @@ -0,0 +1,40 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.separatedinterface.taxes; + +import com.iluwatar.separatedinterface.invoice.TaxCalculator; + +/** + * TaxCalculator for foreign goods with 60% tax. + */ +public class ForeignTax implements TaxCalculator { + + public static final double TAX_PERCENTAGE = 60; + + @Override + public double calculate(double amount) { + return amount * TAX_PERCENTAGE / 100.0; + } + +} diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java new file mode 100644 index 000000000..4114f9bb7 --- /dev/null +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java @@ -0,0 +1,41 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.separatedinterface; + +import org.junit.jupiter.api.Test; + +import com.iluwatar.separatedinterface.App; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Application test. + */ +class AppTest { + + @Test + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java new file mode 100644 index 000000000..669fb1452 --- /dev/null +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java @@ -0,0 +1,25 @@ +package com.iluwatar.separatedinterface.invoice; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.mockito.Mockito.*; + +public class InvoiceGeneratorTest { + + private InvoiceGenerator target; + + @Test + public void testGenerateTax() { + var productCost = 50.0; + var tax = 10.0; + TaxCalculator taxCalculatorMock = mock(TaxCalculator.class); + doReturn(tax).when(taxCalculatorMock).calculate(productCost); + + target = new InvoiceGenerator(productCost, taxCalculatorMock); + + Assertions.assertEquals(target.getAmountWithTax(), productCost + tax); + verify(taxCalculatorMock, times(1)).calculate(productCost); + } + +} diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java new file mode 100644 index 000000000..e562586c2 --- /dev/null +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java @@ -0,0 +1,18 @@ +package com.iluwatar.separatedinterface.taxes; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class DomesticTaxTest { + + private DomesticTax target; + + @Test + public void testTaxCaluclation(){ + target = new DomesticTax(); + + var tax=target.calculate(100.0); + Assertions.assertEquals(tax,20.0); + } + +} diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java new file mode 100644 index 000000000..86bf39e80 --- /dev/null +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java @@ -0,0 +1,18 @@ +package com.iluwatar.separatedinterface.taxes; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ForeignTaxTest { + + private ForeignTax target; + + @Test + public void testTaxCaluclation(){ + target = new ForeignTax(); + + var tax=target.calculate(100.0); + Assertions.assertEquals(tax,60.0); + } + +} From 7fd7735527c987a3f65b6c4ec57acdb1d305c3bc Mon Sep 17 00:00:00 2001 From: swarajsaaj Date: Thu, 10 Sep 2020 03:10:58 +0530 Subject: [PATCH 108/254] #1313 Add separated-interface module to parent pom --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index da3084ab2..102668588 100644 --- a/pom.xml +++ b/pom.xml @@ -196,6 +196,7 @@ transaction-script filterer factory + separated-interface From a2967c5a40bacc06f60b699507c3b66c60da6699 Mon Sep 17 00:00:00 2001 From: swarajsaaj Date: Thu, 10 Sep 2020 03:22:00 +0530 Subject: [PATCH 109/254] #1313 Add documentation and license header --- separated-interface/README.md | 2 +- .../com/iluwatar/separatedinterface/App.java | 12 ++++----- .../invoice/InvoiceGenerator.java | 25 ++++++++++++++++++- .../invoice/InvoiceGeneratorTest.java | 23 +++++++++++++++++ .../taxes/DomesticTaxTest.java | 23 +++++++++++++++++ .../taxes/ForeignTaxTest.java | 23 +++++++++++++++++ 6 files changed, 100 insertions(+), 8 deletions(-) diff --git a/separated-interface/README.md b/separated-interface/README.md index 11ad4a978..b26d5c7da 100644 --- a/separated-interface/README.md +++ b/separated-interface/README.md @@ -10,7 +10,7 @@ tags: ## Intent -Separate the interface definition and implementation in different packages. This allows the client to be completly unaware of the implementation. +Separate the interface definition and implementation in different packages. This allows the client to be completely unaware of the implementation. ## Explanation diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java index e0a385c9e..67eeec054 100644 --- a/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java @@ -30,13 +30,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - *

The Strategy pattern (also known as the policy pattern) is a software design pattern that - * enables an algorithm's behavior to be selected at runtime.

- * - *

Before Java 8 the Strategies needed to be separate classes forcing the developer - * to write lots of boilerplate code. With modern Java it is easy to pass behavior with method - * references and lambdas making the code shorter and more readable.

+ *

The Separated Interface pattern encourages to separate the interface definition and + * implementation in different packages. This allows the client to be completely unaware of the + * implementation.

* + *

In this class the {@link InvoiceGenerator} class is injected with different instances of + * {@link com.iluwatar.separatedinterface.invoice.TaxCalculator} implementations located in separate + * packages, to receive different responses for both of the implementations.

*/ public class App { diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java index f73ee32d8..c17ed5ac5 100644 --- a/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java @@ -1,8 +1,31 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.separatedinterface.invoice; /** * InvoiceGenerator class generates an invoice, accepting the product cost and calculating the total - * price payable inclusive tax (calculated by {@link TaxCalculator}) + * price payable inclusive tax (calculated by {@link TaxCalculator}). */ public class InvoiceGenerator { diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java index 669fb1452..ac75d3b70 100644 --- a/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java @@ -1,3 +1,26 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.separatedinterface.invoice; import org.junit.jupiter.api.Assertions; diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java index e562586c2..d070d8b0a 100644 --- a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java @@ -1,3 +1,26 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.separatedinterface.taxes; import org.junit.jupiter.api.Assertions; diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java index 86bf39e80..df184276c 100644 --- a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java @@ -1,3 +1,26 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.separatedinterface.taxes; import org.junit.jupiter.api.Assertions; From 93aa1046aa6b277ed29a6a498271ee6da9c63a7e Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 11 Sep 2020 09:34:11 +0800 Subject: [PATCH 110/254] translate decorator and factory method pattern in Chinese --- zh/decorator/README.md | 139 ++++++++++++++++++++++++++++++++++++ zh/factory-method/README.md | 88 +++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 zh/decorator/README.md create mode 100644 zh/factory-method/README.md diff --git a/zh/decorator/README.md b/zh/decorator/README.md new file mode 100644 index 000000000..ef23eda0b --- /dev/null +++ b/zh/decorator/README.md @@ -0,0 +1,139 @@ +--- +layout: pattern +title: Decorator +folder: decorator +permalink: /patterns/decorator/ +categories: Structural +tags: + - Gang Of Four + - Extensibility +--- + +## 或称 +包装器 + +## 目的 +动态的为对象附加额外的职责。装饰器为子类提供了灵活的替代方案,以扩展功能。 + +## 解释 + +真实世界例子 + +> 附近的山丘上住着一个愤怒的巨魔。通常它是徒手的,但有时它有武器。为了武装巨魔不必创建新的巨魔,而是用合适的武器动态的装饰它。 + +通俗的说 + +> 装饰者模式让你可以在运行时通过把对象包装进一个装饰类对象中来动态的改变一个对象的行为。 + +维基百科说 + +> 在面向对象的编程中,装饰器模式是一种设计模式,它允许将行为静态或动态地添加到单个对象中,而不会影响同一类中其他对象的行为。装饰器模式通常对于遵守单一责任原则很有用,因为它允许将功能划分到具有唯一关注领域的类之间。 + +**程序示例** + +以巨魔的为例。首先我有有一个简单的巨魔,实现了巨魔接口。 + +程序mple. First of all we have a simple troll implementing the troll interface + +```java +public interface Troll { + void attack(); + int getAttackPower(); + void fleeBattle(); +} + +public class SimpleTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleTroll.class); + + @Override + public void attack() { + LOGGER.info("The troll tries to grab you!"); + } + + @Override + public int getAttackPower() { + return 10; + } + + @Override + public void fleeBattle() { + LOGGER.info("The troll shrieks in horror and runs away!"); + } +} +``` + +下面我们想为巨魔添加球棒。我们可以用装饰者来动态的实现。 + +```java +public class ClubbedTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class); + + private final Troll decorated; + + public ClubbedTroll(Troll decorated) { + this.decorated = decorated; + } + + @Override + public void attack() { + decorated.attack(); + LOGGER.info("The troll swings at you with a club!"); + } + + @Override + public int getAttackPower() { + return decorated.getAttackPower() + 10; + } + + @Override + public void fleeBattle() { + decorated.fleeBattle(); + } +} +``` + +这里是巨魔的实战 + +```java +// simple troll +var troll = new SimpleTroll(); +troll.attack(); // The troll tries to grab you! +troll.fleeBattle(); // The troll shrieks in horror and runs away! + +// change the behavior of the simple troll by adding a decorator +var clubbedTroll = new ClubbedTroll(troll); +clubbedTroll.attack(); // The troll tries to grab you! The troll swings at you with a club! +clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away! +``` + +## 类图 +![alt text](../../decorator/etc/decorator.urm.png "Decorator pattern class diagram") + +## 适用性 +使用装饰者 + +* 动态透明地向单个对象添加职责,即不影响其他对象 +* 对于可以撤销的责任 +* 当通过子类化进行扩展是不切实际的。有时可能会有大量的独立扩展,并且会产生大量的子类来支持每种组合。 否则类定义可能被隐藏或无法用于子类化。 + +## 教程 +* [Decorator Pattern Tutorial](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example) + +## Java世界的例子 + * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), + [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) + * [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) + * [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-) + * [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-) + + +## 鸣谢 + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) diff --git a/zh/factory-method/README.md b/zh/factory-method/README.md new file mode 100644 index 000000000..420653d1b --- /dev/null +++ b/zh/factory-method/README.md @@ -0,0 +1,88 @@ +--- +layout: pattern +title: Factory Method +folder: factory-method +permalink: /patterns/factory-method/ +categories: Creational +tags: + - Extensibility + - Gang Of Four +--- + +## Also known as +# 或称 + +虚拟构造器 + +## 目的 +为创建一个对象定义一个接口,但是让子类决定实例化哪个类。工厂方法允许类将实例化延迟到子类。 + +## 解释 +真实世界例子 + +> 铁匠生产武器。精灵需要精灵武器,而兽人需要兽人武器。根据客户来召唤正确类型的铁匠。 + +通俗的说 + +> 它为类提供了一种把实例化的逻辑委托给子类的方式。 + +维基百科上说 + +> 在基于类的编程中,工厂方法模式是一种创建型设计模式用来解决创建对象的问题,而不需要指定将要创建对象的确切类。这是通过调用工厂方法创建对象来完成的,而不是通过调用构造器。该工厂方法在接口中指定并由子类实现,或者在基类实现并可以选择由子类重写。 + + **程序示例** + +以上面的铁匠为例,首先我们有铁匠的接口和一些它的实现。 + +```java +public interface Blacksmith { + Weapon manufactureWeapon(WeaponType weaponType); +} + +public class ElfBlacksmith implements Blacksmith { + public Weapon manufactureWeapon(WeaponType weaponType) { + return ELFARSENAL.get(weaponType); + } +} + +public class OrcBlacksmith implements Blacksmith { + public Weapon manufactureWeapon(WeaponType weaponType) { + return ORCARSENAL.get(weaponType); + } +} +``` + +现在随着客户的到来,会召唤出正确类型的铁匠并制造出要求的武器。 + +```java +var blacksmith = new ElfBlacksmith(); +blacksmith.manufactureWeapon(WeaponType.SPEAR); +blacksmith.manufactureWeapon(WeaponType.AXE); +// Elvish weapons are created +``` + +## 类图 +![alt text](../../factory-method/etc/factory-method.urm.png "Factory Method pattern class diagram") + +## 适用性 +使用工厂方法模式当 + +* 一个类无法预料它所要必须创建的对象的类 +* 一个类想要它的子类来指定它要创建的对象 +* 类将责任委派给几个帮助子类中的一个,而你想定位了解是具体之中的哪一个 + +## Java中的例子 + +* [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +* [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +* [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +* [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +* [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-) +* [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-) +* [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) + +## 鸣谢 + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) From 9f3f5322d2226274b3e6a7b96bdc5ca0424bb9b0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 17:00:58 +0000 Subject: [PATCH 111/254] docs: update README.md [skip ci] --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c60b27f09..ca3e8fbaa 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-131-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-132-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -246,7 +246,7 @@ This project is licensed under the terms of the MIT license.
Nishant Arora

💻
Peeyush

💻 -
Rakesh

💻 +
Rakesh

💻 👀
Wei Seng

💻 @@ -262,10 +262,10 @@ This project is licensed under the terms of the MIT license.
Michał Krzywański

💻 -
Rakesh

💻 👀
Stefan Birkner

💻
Fedor Skvorcov

💻
samilAyoub

💻 +
Vladislav Golubinov

💻 From c63af2ccbf6389d8c67e17116283d255ed977a24 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2020 17:00:59 +0000 Subject: [PATCH 112/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index c7c53aae4..7abdd7ea9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1195,6 +1195,15 @@ "contributions": [ "code" ] + }, + { + "login": "vdlald", + "name": "Vladislav Golubinov", + "avatar_url": "https://avatars0.githubusercontent.com/u/29997701?v=4", + "profile": "https://github.com/vdlald", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From 9088ac51f6105f82e4c04c31de262e7e59f3fa8e Mon Sep 17 00:00:00 2001 From: swarajsaaj Date: Sat, 12 Sep 2020 22:35:40 +0530 Subject: [PATCH 113/254] #1313 Rename DomesticTax,ForeignTax and review fixes --- separated-interface/README.md | 16 ++++++++-------- separated-interface/etc/class_diagram.png | Bin 32651 -> 32958 bytes .../etc/separated-interface.urm.puml | 12 ++++++------ .../com/iluwatar/separatedinterface/App.java | 9 +++++---- ...ticTax.java => DomesticTaxCalculator.java} | 2 +- ...eignTax.java => ForeignTaxCalculator.java} | 2 +- ...st.java => DomesticTaxCalculatorTest.java} | 8 ++++---- ...est.java => ForeignTaxCalculatorTest.java} | 8 ++++---- 8 files changed, 29 insertions(+), 28 deletions(-) rename separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/{DomesticTax.java => DomesticTaxCalculator.java} (95%) rename separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/{ForeignTax.java => ForeignTaxCalculator.java} (96%) rename separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/{DomesticTaxTest.java => DomesticTaxCalculatorTest.java} (89%) rename separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/{ForeignTaxTest.java => ForeignTaxCalculatorTest.java} (89%) diff --git a/separated-interface/README.md b/separated-interface/README.md index b26d5c7da..ca7a12e44 100644 --- a/separated-interface/README.md +++ b/separated-interface/README.md @@ -3,7 +3,7 @@ layout: pattern title: Separated Interface folder: separated-interface permalink: /patterns/separated-interface/ -categories: Architectural +categories: Structural tags: - Decoupling --- @@ -22,7 +22,7 @@ In plain words > Separated interface pattern encourages to keep the implementations of an interface decoupled from the client and its definition, so the client is not dependent on the implementation. -A client code may abstract some specific functionality to an interface, and define the definition of the interface as an SPI. Another package may implement this interface definition with a concrete logic, which will be injected into the client code at runtime (with a third class, injecting the implementation in the client) or at compile time (using Plugin pattern with some configurable file). +A client code may abstract some specific functionality to an interface, and define the definition of the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface) is an API intended and open to be implemented or extended by a third party). Another package may implement this interface definition with a concrete logic, which will be injected into the client code at runtime (with a third class, injecting the implementation in the client) or at compile time (using Plugin pattern with some configurable file). **Programmatic Example** @@ -60,9 +60,9 @@ public interface TaxCalculator { **Implementation package** In another package (which the client is completely unaware of) there exist multiple implementations of the ```TaxCalculator``` interface -```ForeignTax``` which levies 60% tax for international products. +```ForeignTaxCalculator``` which levies 60% tax for international products. ```java -public class ForeignTax implements TaxCalculator { +public class ForeignTaxCalculator implements TaxCalculator { public static final double TAX_PERCENTAGE = 60; @@ -74,9 +74,9 @@ public class ForeignTax implements TaxCalculator { } ``` -```DomesticTax``` which levies 20% tax for international products. +```DomesticTaxCalculator``` which levies 20% tax for international products. ```java -public class DomesticTax implements TaxCalculator { +public class DomesticTaxCalculator implements TaxCalculator { public static final double TAX_PERCENTAGE = 20; @@ -91,11 +91,11 @@ public class DomesticTax implements TaxCalculator { These both implementations are instantiated and injected in the client class by the ```App.java``` class ```java - var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTax()); + var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTaxCalculator()); LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax()); - var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTax()); + var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTaxCalculator()); LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax()); ``` diff --git a/separated-interface/etc/class_diagram.png b/separated-interface/etc/class_diagram.png index a0edbac8dac3cd5a0f1dd174fd1cfaa0bbc78e72..10d509801f79b7c9172c87731233d6753d597efd 100644 GIT binary patch literal 32958 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 literal 32651 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

@OZmh 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 "-taxCalculator" TaxCalculator -DomesticTax ..|> TaxCalculator -ForeignTax ..|> TaxCalculator +DomesticTaxCalculator ..|> TaxCalculator +ForeignTaxCalculator ..|> TaxCalculator @enduml \ No newline at end of file diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java index 67eeec054..1951e738b 100644 --- a/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java @@ -24,8 +24,8 @@ package com.iluwatar.separatedinterface; import com.iluwatar.separatedinterface.invoice.InvoiceGenerator; -import com.iluwatar.separatedinterface.taxes.DomesticTax; -import com.iluwatar.separatedinterface.taxes.ForeignTax; +import com.iluwatar.separatedinterface.taxes.DomesticTaxCalculator; +import com.iluwatar.separatedinterface.taxes.ForeignTaxCalculator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,11 +51,12 @@ public class App { */ public static void main(String[] args) { //Create the invoice generator with product cost as 50 and foreign product tax - var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTax()); + var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, + new ForeignTaxCalculator()); LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax()); //Create the invoice generator with product cost as 50 and domestic product tax - var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTax()); + var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTaxCalculator()); LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax()); } } diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculator.java similarity index 95% rename from separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java rename to separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculator.java index ebe0e306e..788afb90a 100644 --- a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTax.java +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculator.java @@ -28,7 +28,7 @@ import com.iluwatar.separatedinterface.invoice.TaxCalculator; /** * TaxCalculator for Domestic goods with 20% tax. */ -public class DomesticTax implements TaxCalculator { +public class DomesticTaxCalculator implements TaxCalculator { public static final double TAX_PERCENTAGE = 20; diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculator.java similarity index 96% rename from separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java rename to separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculator.java index 583f70d3b..c2b12e2f5 100644 --- a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTax.java +++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculator.java @@ -28,7 +28,7 @@ import com.iluwatar.separatedinterface.invoice.TaxCalculator; /** * TaxCalculator for foreign goods with 60% tax. */ -public class ForeignTax implements TaxCalculator { +public class ForeignTaxCalculator implements TaxCalculator { public static final double TAX_PERCENTAGE = 60; diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculatorTest.java similarity index 89% rename from separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java rename to separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculatorTest.java index d070d8b0a..dac3ec2d6 100644 --- a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxTest.java +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculatorTest.java @@ -26,13 +26,13 @@ package com.iluwatar.separatedinterface.taxes; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class DomesticTaxTest { +public class DomesticTaxCalculatorTest { - private DomesticTax target; + private DomesticTaxCalculator target; @Test - public void testTaxCaluclation(){ - target = new DomesticTax(); + public void testTaxCalculation(){ + target = new DomesticTaxCalculator(); var tax=target.calculate(100.0); Assertions.assertEquals(tax,20.0); diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculatorTest.java similarity index 89% rename from separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java rename to separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculatorTest.java index df184276c..22526b6df 100644 --- a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxTest.java +++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculatorTest.java @@ -26,13 +26,13 @@ package com.iluwatar.separatedinterface.taxes; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class ForeignTaxTest { +public class ForeignTaxCalculatorTest { - private ForeignTax target; + private ForeignTaxCalculator target; @Test - public void testTaxCaluclation(){ - target = new ForeignTax(); + public void testTaxCalculation(){ + target = new ForeignTaxCalculator(); var tax=target.calculate(100.0); Assertions.assertEquals(tax,60.0); From 74b968942f69a893d8f832e5482cf481429638a5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2020 14:23:52 +0000 Subject: [PATCH 114/254] docs: update README.md [skip ci] --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ca3e8fbaa..51ed89f82 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-132-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-133-orange.svg?style=flat-square)](#contributors-) # Introduction @@ -267,6 +267,9 @@ This project is licensed under the terms of the MIT license.
samilAyoub

💻
Vladislav Golubinov

💻 + +
Swaraj

💻 + From 6f592f5e8a7c66116d8035e16a3d299b6a1c9e82 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2020 14:23:53 +0000 Subject: [PATCH 115/254] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7abdd7ea9..43103ead1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1204,6 +1204,15 @@ "contributions": [ "code" ] + }, + { + "login": "swarajsaaj", + "name": "Swaraj", + "avatar_url": "https://avatars2.githubusercontent.com/u/6285049?v=4", + "profile": "https://github.com/swarajsaaj", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 4, From 2e98dcf2179f4aa13478d36fd8967d068a98eff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 17:39:10 +0300 Subject: [PATCH 116/254] Update README.md --- separated-interface/README.md | 43 +++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/separated-interface/README.md b/separated-interface/README.md index ca7a12e44..35c9e5fe0 100644 --- a/separated-interface/README.md +++ b/separated-interface/README.md @@ -10,23 +10,35 @@ tags: ## Intent -Separate the interface definition and implementation in different packages. This allows the client to be completely unaware of the implementation. + +Separate the interface definition and implementation in different packages. This allows the client +to be completely unaware of the implementation. ## Explanation Real world example -> An Invoice generator may be created with ability to use different Tax calculators that may be added in the invoice depending upon type of purchase, region etc. +> An Invoice generator may be created with ability to use different Tax calculators that may be +> added in the invoice depending upon type of purchase, region etc. In plain words -> Separated interface pattern encourages to keep the implementations of an interface decoupled from the client and its definition, so the client is not dependent on the implementation. +> Separated interface pattern encourages to keep the implementations of an interface decoupled from +> the client and its definition, so the client is not dependent on the implementation. -A client code may abstract some specific functionality to an interface, and define the definition of the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface) is an API intended and open to be implemented or extended by a third party). Another package may implement this interface definition with a concrete logic, which will be injected into the client code at runtime (with a third class, injecting the implementation in the client) or at compile time (using Plugin pattern with some configurable file). +A client code may abstract some specific functionality to an interface, and define the definition of +the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface) +is an API intended and open to be implemented or extended by a third party). Another package may +implement this interface definition with a concrete logic, which will be injected into the client +code at runtime (with a third class, injecting the implementation in the client) or at compile time +(using Plugin pattern with some configurable file). **Programmatic Example** -**Client** An Invoice generator class accepts the cost of the product and calculates the total amount payable inclusive of tax +**Client** + +`InvoiceGenerator` class accepts the cost of the product and calculates the total +amount payable inclusive of tax. ```java public class InvoiceGenerator { @@ -46,21 +58,23 @@ public class InvoiceGenerator { } ``` -The tax calculation logic is delegated to the ```TaxCalculator``` interface + +The tax calculation logic is delegated to the `TaxCalculator` interface. ```java - public interface TaxCalculator { double calculate(double amount); } - ``` **Implementation package** -In another package (which the client is completely unaware of) there exist multiple implementations of the ```TaxCalculator``` interface -```ForeignTaxCalculator``` which levies 60% tax for international products. + +In another package (which the client is completely unaware of) there exist multiple implementations +of the `TaxCalculator` interface. `ForeignTaxCalculator` is one of them which levies 60% tax +for international products. + ```java public class ForeignTaxCalculator implements TaxCalculator { @@ -74,7 +88,8 @@ public class ForeignTaxCalculator implements TaxCalculator { } ``` -```DomesticTaxCalculator``` which levies 20% tax for international products. +Another is `DomesticTaxCalculator` which levies 20% tax for international products. + ```java public class DomesticTaxCalculator implements TaxCalculator { @@ -88,7 +103,8 @@ public class DomesticTaxCalculator implements TaxCalculator { } ``` -These both implementations are instantiated and injected in the client class by the ```App.java``` class +These both implementations are instantiated and injected in the client class by the ```App.java``` +class. ```java var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTaxCalculator()); @@ -101,9 +117,11 @@ These both implementations are instantiated and injected in the client class by ``` ## Class diagram + ![alt text](./etc/class_diagram.png "Separated Interface") ## Applicability + Use the Separated interface pattern when * You are developing a framework package, and your framework needs to call some application code through interfaces. @@ -117,3 +135,4 @@ Use the Separated interface pattern when ## Credits * [Martin Fowler](https://www.martinfowler.com/eaaCatalog/separatedInterface.html) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=e08dfb7f2cf6153542ef1b5a00b10abc) From c204b242dfb84a1b6e43d2dddc56252ddceb47e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 17:53:50 +0300 Subject: [PATCH 117/254] Update README.md --- singleton/README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/singleton/README.md b/singleton/README.md index 60a103a3b..915b3c810 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -9,14 +9,16 @@ tags: --- ## Intent -Ensure a class only has one instance, and provide a global point of -access to it. + +Ensure a class only has one instance, and provide a global point of access to it. ## Explanation + Real world example -> There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. Ivory tower here is singleton. +> There can only be one ivory tower where the wizards study their magic. The same enchanted ivory +> tower is always used by the wizards. Ivory tower here is singleton. In plain words @@ -24,7 +26,9 @@ In plain words Wikipedia says -> In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. +> In software engineering, the singleton pattern is a software design pattern that restricts the +> instantiation of a class to one object. This is useful when exactly one object is needed to +> coordinate actions across the system. **Programmatic Example** @@ -38,7 +42,7 @@ public enum EnumIvoryTower { } ``` -Then in order to use +Then in order to use: ```java var enumIvoryTower1 = EnumIvoryTower.INSTANCE; @@ -47,9 +51,11 @@ assertEquals(enumIvoryTower1, enumIvoryTower2); // true ``` ## Class diagram + ![alt text](./etc/singleton.urm.png "Singleton pattern class diagram") ## Applicability + Use the Singleton pattern when * There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point From e6cca86e25c6571e2e98091cd4face248fafa019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 17:59:12 +0300 Subject: [PATCH 118/254] Update README.md --- spatial-partition/README.md | 31 ++++++++++++++----- .../SpatialPartitionBubbles.java | 1 - 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/spatial-partition/README.md b/spatial-partition/README.md index 29d54533d..0114fadba 100644 --- a/spatial-partition/README.md +++ b/spatial-partition/README.md @@ -10,12 +10,17 @@ tags: --- ## Intent -As explained in the book [Game Programming Patterns](http://gameprogrammingpatterns.com/spatial-partition.html) by Bob Nystrom, spatial partition pattern helps to -> efficiently locate objects by storing them in a data structure organized by their positions. +As explained in the book [Game Programming Patterns](http://gameprogrammingpatterns.com/spatial-partition.html) +by Bob Nystrom, spatial partition pattern helps to efficiently locate objects by storing them in a +data structure organized by their positions. ## Explanation -Say, you are building a war game with hundreds, or maybe even thousands of players, who are clashing on the battle field. Each player's position is getting updated every frame. The simple way to handle all interactions taking place on the field is to check each player's position against every other player's position: + +Say, you are building a war game with hundreds, or maybe even thousands of players, who are clashing +on the battle field. Each player's position is getting updated every frame. The simple way to handle +all interactions taking place on the field is to check each player's position against every other +player's position: ```java public void handleMeLee(Unit units[], int numUnits) { @@ -32,21 +37,33 @@ public void handleMeLee(Unit units[], int numUnits) { } ``` -This will include a lot of unnecessary checks between players which are too far apart to have any influence on each other. The nested loops gives this operation an O(n^2) complexity, which has to be performed every frame since many of the objects on the field may be moving each frame. -The idea behind the Spatial Partition design pattern is to enable quick location of objects using a data structure that is organised by their positions, so when performing an operation like the one above, every object's position need not be checked against all other objects' positions. The data structure can be used to store moving and static objects, though in order to keep track of the moving objects, their positions will have to be reset each time they move. This would mean having to create a new instance of the data structure each time an object moves, which would use up additional memory. The common data structures used for this design pattern are: +This will include a lot of unnecessary checks between players which are too far apart to have any +influence on each other. The nested loops gives this operation an O(n^2) complexity, which has to be +performed every frame since many of the objects on the field may be moving each frame. The idea +behind the Spatial Partition design pattern is to enable quick location of objects using a data +structure that is organised by their positions, so when performing an operation like the one above, +every object's position need not be checked against all other objects' positions. The data structure +can be used to store moving and static objects, though in order to keep track of the moving objects, +their positions will have to be reset each time they move. This would mean having to create a new +instance of the data structure each time an object moves, which would use up additional memory. The +common data structures used for this design pattern are: * Grid * Quad tree -* k-d tree +* K-d tree * BSP * Boundary volume hierarchy -In our implementation, we use the Quadtree data structure which will reduce the time complexity of finding the objects within a certain range from O(n^2) to O(nlogn), decreasing the computations required significantly in case of large number of objects. +In our implementation, we use the Quadtree data structure which will reduce the time complexity of +finding the objects within a certain range from O(n^2) to O(nlogn), decreasing the computations +required significantly in case of large number of objects. ## Class diagram + ![alt text](./etc/spatial-partition.urm.png "Spatial Partition pattern class diagram") ## Applicability + This pattern can be used: * When you need to keep track of a large number of objects' positions, which are getting updated every frame. diff --git a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java index c0eb5ecde..c543da12c 100644 --- a/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java +++ b/spatial-partition/src/main/java/com/iluwatar/spatialpartition/SpatialPartitionBubbles.java @@ -24,7 +24,6 @@ package com.iluwatar.spatialpartition; import java.util.ArrayList; -import java.util.Collection; import java.util.Hashtable; /** From 9c648cbdb86ba7e93edac9b36589cea4082e4745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 18:04:30 +0300 Subject: [PATCH 119/254] Update README.md --- specification/README.md | 68 ++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/specification/README.md b/specification/README.md index 6cc0c702f..5648a73b0 100644 --- a/specification/README.md +++ b/specification/README.md @@ -9,36 +9,46 @@ tags: --- ## Also known as + Filter, Criteria ## Intent -Specification pattern separates the statement of how to match a -candidate, from the candidate object that it is matched against. As well as its -usefulness in selection, it is also valuable for validation and for building to -order. + +Specification pattern separates the statement of how to match a candidate, from the candidate object +that it is matched against. As well as its usefulness in selection, it is also valuable for +validation and for building to order. ## Explanation Real world example -> There is a pool of different creatures and we often need to select some subset of them. -> We can write our search specification such as "creatures that can fly", "creatures heavier than 500 kilograms", or as a combination of other search specifications, and then give it to the party that will perform the filtering. +> There is a pool of different creatures and we often need to select some subset of them. We can +> write our search specification such as "creatures that can fly", "creatures heavier than 500 +> kilograms", or as a combination of other search specifications, and then give it to the party that +> will perform the filtering. In Plain Words -> Specification pattern allows us to separate the search criteria from the object that performs the search. +> Specification pattern allows us to separate the search criteria from the object that performs the +> search. Wikipedia says -> In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic. +> In computer programming, the specification pattern is a particular software design pattern, +> whereby business rules can be recombined by chaining the business rules together using boolean +> logic. **Programmatic Example** -If we look at our creature pool example from above, we have a set of creatures with certain properties. -Those properties can be part of a pre-defined, limited set (represented here by the enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a Creature). -In this case, it is more appropriate to use what we call "parameterized specification", where the property value can be given as an argument when the Creature is instantiated, allowing for more flexibility. -A third option is to combine pre-defined and/or parameterized properties using boolean logic, allowing for near-endless selection possibilities (this is called "composite specification", see below). -The pros and cons of each approach are detailed in the table at the end of this document. +If we look at our creature pool example from above, we have a set of creatures with certain +properties. Those properties can be part of a pre-defined, limited set (represented here by the +enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a +Creature). In this case, it is more appropriate to use what we call "parameterized specification", +where the property value can be given as an argument when the Creature is instantiated, allowing for +more flexibility. A third option is to combine pre-defined and/or parameterized properties using +boolean logic, allowing for near-endless selection possibilities (this is called "composite +specification", see below). The pros and cons of each approach are detailed in the table at the end +of this document. ```java public interface Creature { @@ -50,7 +60,7 @@ public interface Creature { } ``` -And ``Dragon`` implementation looks like this. +And `Dragon` implementation looks like this. ```java public class Dragon extends AbstractCreature { @@ -61,7 +71,8 @@ public class Dragon extends AbstractCreature { } ``` -Now that we want to select some subset of them, we use selectors. To select creatures that fly, we should use ``MovementSelector``. +Now that we want to select some subset of them, we use selectors. To select creatures that fly, we +should use `MovementSelector`. ```java public class MovementSelector extends AbstractSelector { @@ -79,7 +90,8 @@ public class MovementSelector extends AbstractSelector { } ``` -On the other hand, when selecting creatures heavier than a chosen amount, we use ``MassGreaterThanSelector``. +On the other hand, when selecting creatures heavier than a chosen amount, we use +`MassGreaterThanSelector`. ```java public class MassGreaterThanSelector extends AbstractSelector { @@ -111,7 +123,8 @@ But we could also use our parameterized selector like this: .collect(Collectors.toList()); ``` -Our third option is to combine multiple selectors together. Performing a search for special creatures (defined as red, flying, and not small) could be done as follows: +Our third option is to combine multiple selectors together. Performing a search for special +creatures (defined as red, flying, and not small) could be done as follows: ```java var specialCreaturesSelector = @@ -123,8 +136,9 @@ Our third option is to combine multiple selectors together. Performing a search **More on Composite Specification** -In Composite Specification, we will create custom instances of ``AbstractSelector`` by combining other selectors (called "leaves") using the three basic logical operators. -These are implemented in ``ConjunctionSelector``, ``DisjunctionSelector`` and ``NegationSelector``. +In Composite Specification, we will create custom instances of `AbstractSelector` by combining +other selectors (called "leaves") using the three basic logical operators. These are implemented in +`ConjunctionSelector`, `DisjunctionSelector` and `NegationSelector`. ```java public abstract class AbstractSelector implements Predicate { @@ -163,12 +177,14 @@ public class ConjunctionSelector extends AbstractSelector { } ``` -All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that are as generic as possible, -and we will be able to instantiate the ``AbstractSelector`` class by combining any amount of selectors, as exemplified above. -We should be careful though, as it is easy to make a mistake when combining many logical operators; in particular, we should pay attention to the priority of the operations.\ -In general, Composite Specification is a great way to write more reusable code, as there is no need to create a Selector class for each filtering operation. -Instead, we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf" selectors and some basic boolean logic. - +All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that +are as generic as possible, and we will be able to instantiate the ``AbstractSelector`` class by +combining any amount of selectors, as exemplified above. We should be careful though, as it is easy +to make a mistake when combining many logical operators; in particular, we should pay attention to +the priority of the operations. In general, Composite Specification is a great way to write more +reusable code, as there is no need to create a Selector class for each filtering operation. Instead, +we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf" +selectors and some basic boolean logic. **Comparison of the different approaches** @@ -181,9 +197,11 @@ Instead, we just create an instance of ``AbstractSelector`` "on the spot", using | | | + Supports logical operations | - You still need to create the base classes used as leaves | ## Class diagram + ![alt text](./etc/specification.png "Specification") ## Applicability + Use the Specification pattern when * You need to select a subset of objects based on some criteria, and to refresh the selection at various times. From 9cbc509c3ad3a75f0935e01b2d3b636968cf5832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 18:09:18 +0300 Subject: [PATCH 120/254] Update README.md --- state/README.md | 33 ++++++++++++----- state/etc/state.png | Bin 17753 -> 0 bytes state/etc/state.ucls | 80 ------------------------------------------ state/etc/state_1.png | Bin 33886 -> 0 bytes 4 files changed, 24 insertions(+), 89 deletions(-) delete mode 100644 state/etc/state.png delete mode 100644 state/etc/state.ucls delete mode 100644 state/etc/state_1.png diff --git a/state/README.md b/state/README.md index a8dd2b5fc..7ee201be2 100644 --- a/state/README.md +++ b/state/README.md @@ -9,15 +9,21 @@ tags: --- ## Also known as + Objects for States ## Intent -Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. + +Allow an object to alter its behavior when its internal state changes. The object will appear to +change its class. ## Explanation + Real world example -> When observing a mammoth in its natural habitat it seems to change its behavior based on the situation. It may first appear calm but over time when it detects a threat it gets angry and dangerous to its surroundings. +> When observing a mammoth in its natural habitat it seems to change its behavior based on the +> situation. It may first appear calm but over time when it detects a threat it gets angry and +> dangerous to its surroundings. In plain words @@ -25,7 +31,10 @@ In plain words Wikipedia says -> The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface. +> The state pattern is a behavioral software design pattern that allows an object to alter its +> behavior when its internal state changes. This pattern is close to the concept of finite-state +> machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a +> strategy through invocations of methods defined in the pattern's interface. **Programmatic Example** @@ -126,17 +135,23 @@ And here is the full example how the mammoth behaves over time. mammoth.observe(); mammoth.timePasses(); mammoth.observe(); - - // The mammoth gets angry! - // The mammoth is furious! - // The mammoth calms down. - // The mammoth is calm and peaceful. +``` + +Program output: + +```java + The mammoth gets angry! + The mammoth is furious! + The mammoth calms down. + The mammoth is calm and peaceful. ``` ## Class diagram -![alt text](./etc/state_1.png "State") + +![alt text](./etc/state_urm.png "State") ## Applicability + Use the State pattern in either of the following cases * An object's behavior depends on its state, and it must change its behavior at run-time depending on that state diff --git a/state/etc/state.png b/state/etc/state.png deleted file mode 100644 index fb1648238e78e123a3e2f60540ae7701dd45ee8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17753 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 diff --git a/state/etc/state.ucls b/state/etc/state.ucls deleted file mode 100644 index e0be8d712..000000000 --- a/state/etc/state.ucls +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/state/etc/state_1.png b/state/etc/state_1.png deleted file mode 100644 index 112bb9aff904f93f769583ab2a33d3f7b2181a9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33886 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

iUE7!eElOdtCT0kf!Fdl4hr*FaKHszv z_E7y^bDF@q{QY1e$3$R;kVg{O-YW_K9~njI!6 zyTjyeea6ZbUD&iZDs+;rfAqyh#7mDauU>uJ-SP`1nkz8Epf=#hhfxQ4g4gooTH)-(?f2d8iS>|4iORpRjlB#BvE0%3kZCm{j}W*&%v$F2*_}gL zQ+{Y~(l7j#c`a`{vvSyF$(^*Oj14ju>&pC@nVUXPdPY&bpQDv}Hjt9{?boEGOP6fK zC8|rye|m3`MB`A7GRgRU@|gIkpvTSG;(=06N$?Ii2A> zC`lS=Zz4OuCS+1jF=fwNUl$i9Dt>LJ)gfo^>}&#M$+XYpIl)h##^V!n_Hxcv@bh;m zzt$SvpLUFka{s7VU& z%>k>C=2do`d9$=47BlVd8Fp17vYj@(&x$V#`nnG-o_&c9k^Py6x~+lSx#!_c(61k z4sl59xi|N3jXrbEG$)+1>`e9@AOBh7K+O03fEj^ZW0L{x_ZcJ1{+Zo4ivXi$&L9S3 zhSe{hsbu)`Bj;=CvOfCwX zDC`-!vjrY2=0_7QqmD^PRCCZGAwmDB&4PUUK)8~Jle49NePdyvS&kT%4JqSD9JLY^ zRHCb^b*ZW~JYCmz!&li<0F`gu&LFvY@}<|o*S3|!GilYfz3ehFPY%bkzh6;{(#OLE zfiEUVlyzt{o(WGltvw2?TiZJ)#Ez7X7OpI~X44w30hMVBs}GSR7%|6%-W!x0*d3LL zp5^i@y(T(`sP+AMLqhL;&M=sf^PX|4zKrsq9I+}JO5#u;tdy%$JiVZ9o)esx=kz<9 zROAr9O|+Ar&8!6b$k0fVi^IWm2hyaI^r^9ONH|OR(&TBuUwNkewhU7G!Rp3f1)Z4V zMRKo$pIg88P|uyMa=!&-_boxI_To!#45_JY#hwH{Q}vB4YTD!;Ikogt$KkHDdheyF z(TOJ(E88na^nGW#m|4osU*DIZq{*_zjT-rrFJ6BYEdR2wgzq67O$b@KiYE=t4A>U8 zTKRvXHM=Wzc3)wIaxaD5CmGnNHl;j`^@acM1oSWe^w-4~=}^6E@ezVV1w2?gcTKE) zxMD(5ymG)Xjf(Sv#`EJC|Dpi!H_W)0S-*C91im&EHW)4KhEvO~k5)e{D^mdT@V$1+ z-D@|3po`lvJFqS#C9GpIO~I;%ohTt6KF}DTo%=TZkD}q9+)fr(#eZu*t*E&QB z)7@D;Fv%h!ao69Y;DAzhrE^P8a9_I>bsDY#Oeyf31(5C4Z>Mat>U zj#OPrJ4X#0$n8^N+xHDRiAoy~B|LK`?FH!8C~OizfK#ZNV9R`k9}b`_I*eT%NfcV2 z-R0Q*Z~(`WrM)Q^UK8QrxRmTdhQigs$HruMPG-Fa|Gpr(V7Th{e}AvojC`H>|D6NC zxqm0`kwgUyN#gaKL73v;;Edp+aB*<58KGtk|Csc{)g67jO({gV2>--Ul2^a{Sk5%y Fe*vgP8^izr From b5fddd469a1e7139fac627785a7d8b15b1cf4b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 18:09:41 +0300 Subject: [PATCH 121/254] Update README.md --- state/etc/state_urm.png | Bin 0 -> 34673 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 state/etc/state_urm.png diff --git a/state/etc/state_urm.png b/state/etc/state_urm.png new file mode 100644 index 0000000000000000000000000000000000000000..c2cf9f562943f5395185497621565f69e56f0f53 GIT binary patch literal 34673 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 Date: Sun, 13 Sep 2020 18:15:17 +0300 Subject: [PATCH 122/254] Update README.md --- strategy/README.md | 39 +++++++++++------- strategy/etc/strategy.png | Bin 15393 -> 0 bytes strategy/etc/strategy.ucls | 75 ---------------------------------- strategy/etc/strategy_1.png | Bin 28839 -> 0 bytes strategy/etc/strategy_urm.png | Bin 0 -> 29282 bytes 5 files changed, 25 insertions(+), 89 deletions(-) delete mode 100644 strategy/etc/strategy.png delete mode 100644 strategy/etc/strategy.ucls delete mode 100644 strategy/etc/strategy_1.png create mode 100644 strategy/etc/strategy_urm.png diff --git a/strategy/README.md b/strategy/README.md index 21ac1c94b..b2330ceb8 100644 --- a/strategy/README.md +++ b/strategy/README.md @@ -9,17 +9,20 @@ tags: --- ## Also known as + Policy ## Intent -Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary -independently from clients that use it. + +Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets +the algorithm vary independently from clients that use it. ## Explanation Real world example -> Slaying dragons is a dangerous profession. With experience it becomes easier. Veteran dragonslayers have developed different fighting strategies against different types of dragons. +> Slaying dragons is a dangerous job. With experience it becomes easier. Veteran +> dragonslayers have developed different fighting strategies against different types of dragons. In plain words @@ -27,7 +30,8 @@ In plain words Wikipedia says -> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. +> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral +> software design pattern that enables selecting an algorithm at runtime. **Programmatic Example** @@ -71,7 +75,8 @@ public class SpellStrategy implements DragonSlayingStrategy { } ``` -And here is the mighty dragonslayer who is able to pick his fighting strategy based on the opponent. +And here is the mighty dragonslayer, who is able to pick his fighting strategy based on the +opponent. ```java public class DragonSlayer { @@ -92,7 +97,7 @@ public class DragonSlayer { } ``` -Finally here's dragonslayer in action. +Finally here's the dragonslayer in action. ```java LOGGER.info("Green dragon spotted ahead!"); @@ -104,19 +109,25 @@ Finally here's dragonslayer in action. LOGGER.info("Black dragon lands before you."); dragonSlayer.changeStrategy(new SpellStrategy()); dragonSlayer.goToBattle(); - - // Green dragon spotted ahead! - // With your Excalibur you sever the dragon's head! - // Red dragon emerges. - // You shoot the dragon with the magical crossbow and it falls dead on the ground! - // Black dragon lands before you. - // You cast the spell of disintegration and the dragon vaporizes in a pile of dust! +``` + +Program output: + +``` + Green dragon spotted ahead! + With your Excalibur you sever the dragon's head! + Red dragon emerges. + You shoot the dragon with the magical crossbow and it falls dead on the ground! + Black dragon lands before you. + You cast the spell of disintegration and the dragon vaporizes in a pile of dust! ``` ## Class diagram -![alt text](./etc/strategy_1.png "Strategy") + +![alt text](./etc/strategy_urm.png "Strategy") ## Applicability + Use the Strategy pattern when * Many related classes differ only in their behavior. Strategies provide a way to configure a class either one of many behaviors diff --git a/strategy/etc/strategy.png b/strategy/etc/strategy.png deleted file mode 100644 index ae7442150e3763d24c343597c879895e89544985..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15393 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�`lPQe^_gw<>6Qv9|4G2|@P8 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/strategy/etc/strategy_1.png b/strategy/etc/strategy_1.png deleted file mode 100644 index c341e58c6d94456fcfd0215d4e454049b289a154..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28839 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 Date: Sun, 13 Sep 2020 18:19:35 +0300 Subject: [PATCH 123/254] Update README.md --- template-method/README.md | 23 +++++-- template-method/etc/template-method.png | Bin 17911 -> 0 bytes template-method/etc/template-method.ucls | 66 -------------------- template-method/etc/template-method_1.png | Bin 34592 -> 0 bytes template-method/etc/template_method_urm.png | Bin 0 -> 36470 bytes 5 files changed, 17 insertions(+), 72 deletions(-) delete mode 100644 template-method/etc/template-method.png delete mode 100644 template-method/etc/template-method.ucls delete mode 100644 template-method/etc/template-method_1.png create mode 100644 template-method/etc/template_method_urm.png diff --git a/template-method/README.md b/template-method/README.md index 695644488..23dd4d242 100644 --- a/template-method/README.md +++ b/template-method/README.md @@ -9,21 +9,30 @@ tags: --- ## Intent -Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets -subclasses redefine certain steps of an algorithm without changing the algorithm's structure. + +Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template +Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's +structure. ## Explanation + Real world example -> The general steps in stealing an item are the same. First you pick the target, next you confuse him somehow and finally you steal the item. However there are many ways to implement these steps. +> The general steps in stealing an item are the same. First you pick the target, next you confuse +> him somehow and finally you steal the item. However there are many ways to implement these steps. In plain words -> Template Method pattern outlines the general steps in the parent class and lets the concrete child implementations define the details. +> Template Method pattern outlines the general steps in the parent class and lets the concrete child +> implementations define the details. Wikipedia says -> In object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al. in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method. +> In object-oriented programming, the template method is one of the behavioral design patterns +> identified by Gamma et al. in the book Design Patterns. The template method is a method in a +> superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of +> a number of high-level steps. These steps are themselves implemented by additional helper methods +> in the same class as the template method. **Programmatic Example** @@ -120,9 +129,11 @@ And finally we show how the halfling thief utilizes the different stealing metho ``` ## Class diagram -![alt text](./etc/template-method_1.png "Template Method") + +![alt text](./etc/template_method_urm.png "Template Method") ## Applicability + The Template Method pattern should be used * To implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary diff --git a/template-method/etc/template-method.png b/template-method/etc/template-method.png deleted file mode 100644 index e197813398efe850f7c292d052b9efef8d9563e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17911 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 PkmRJ4B=f~zefs|ZY{Hvt diff --git a/template-method/etc/template-method.ucls b/template-method/etc/template-method.ucls deleted file mode 100644 index ec0ce620a..000000000 --- a/template-method/etc/template-method.ucls +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/template-method/etc/template-method_1.png b/template-method/etc/template-method_1.png deleted file mode 100644 index f7cd1a07771cc6da554474967af2418b13ef0112..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34592 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 P1%FC%NZCATQ~&=1?cAFf diff --git a/template-method/etc/template_method_urm.png b/template-method/etc/template_method_urm.png new file mode 100644 index 0000000000000000000000000000000000000000..b7babccff96da7d88fb99ae5a705c7d4f025904c GIT binary patch literal 36470 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∈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 U>vZmeO~f^#f|76Z__aR&f82J0kN^Mx literal 0 HcmV?d00001 From 87093cf2214df0ff58eea3f07697443fd88a46e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Sep 2020 18:23:54 +0300 Subject: [PATCH 124/254] Update README.md --- thread-pool/README.md | 34 ++++++++++----- thread-pool/etc/thread-pool.png | Bin 14796 -> 0 bytes thread-pool/etc/thread-pool.ucls | 62 ---------------------------- thread-pool/etc/thread_pool_urm.png | Bin 0 -> 30120 bytes 4 files changed, 23 insertions(+), 73 deletions(-) delete mode 100644 thread-pool/etc/thread-pool.png delete mode 100644 thread-pool/etc/thread-pool.ucls create mode 100644 thread-pool/etc/thread_pool_urm.png diff --git a/thread-pool/README.md b/thread-pool/README.md index 62a2a3339..de6403fe8 100644 --- a/thread-pool/README.md +++ b/thread-pool/README.md @@ -9,16 +9,19 @@ tags: --- ## Intent -It is often the case that tasks to be executed are short-lived and -the number of tasks is large. Creating a new thread for each task would make -the system spend more time creating and destroying the threads than executing -the actual tasks. Thread Pool solves this problem by reusing existing threads -and eliminating the latency of creating new threads. + +It is often the case that tasks to be executed are short-lived and the number of tasks is large. +Creating a new thread for each task would make the system spend more time creating and destroying +the threads than executing the actual tasks. Thread Pool solves this problem by reusing existing +threads and eliminating the latency of creating new threads. ## Explanation + Real world example -> We have a large number of relatively short tasks at hand. We need to peel huge amounts of potatoes and serve mighty amount of coffee cups. Creating a new thread for each task would be a waste so we establish a thread pool. +> We have a large number of relatively short tasks at hand. We need to peel huge amounts of potatoes +> and serve mighty amount of coffee cups. Creating a new thread for each task would be a waste so we +> establish a thread pool. In plain words @@ -26,11 +29,18 @@ In plain words Wikipedia says -> In computer programming, a thread pool is a software design pattern for achieving concurrency of execution in a computer program. Often also called a replicated workers or worker-crew model, a thread pool maintains multiple threads waiting for tasks to be allocated for concurrent execution by the supervising program. By maintaining a pool of threads, the model increases performance and avoids latency in execution due to frequent creation and destruction of threads for short-lived tasks. The number of available threads is tuned to the computing resources available to the program, such as a parallel task queue after completion of execution. +> In computer programming, a thread pool is a software design pattern for achieving concurrency of +> execution in a computer program. Often also called a replicated workers or worker-crew model, +> a thread pool maintains multiple threads waiting for tasks to be allocated for concurrent +> execution by the supervising program. By maintaining a pool of threads, the model increases +> performance and avoids latency in execution due to frequent creation and destruction of threads +> for short-lived tasks. The number of available threads is tuned to the computing resources +> available to the program, such as a parallel task queue after completion of execution. **Programmatic Example** -Let's first look at our task hierarchy. We have a base class and then concrete CoffeeMakingTask and PotatoPeelingTask. +Let's first look at our task hierarchy. We have a base class and then concrete `CoffeeMakingTask` +and `PotatoPeelingTask`. ```java public abstract class Task { @@ -88,8 +98,8 @@ public class PotatoPeelingTask extends Task { } ``` -Next we present a runnable Worker class that the thread pool will utilize to handle all the potato peeling and coffee -making. +Next we present a runnable `Worker` class that the thread pool will utilize to handle all the potato +peeling and coffee making. ```java public class Worker implements Runnable { @@ -156,9 +166,11 @@ Now we are ready to show the full example in action. ``` ## Class diagram -![alt text](./etc/thread-pool.png "Thread Pool") + +![alt text](./etc/thread_pool_urm.png "Thread Pool") ## Applicability + Use the Thread Pool pattern when * You have a large number of short-lived tasks to be executed in parallel diff --git a/thread-pool/etc/thread-pool.png b/thread-pool/etc/thread-pool.png deleted file mode 100644 index 9e88a91962466ff5df7768abe04e8f5a9301625d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14796 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 ZnWDj8L-gf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/thread-pool/etc/thread_pool_urm.png b/thread-pool/etc/thread_pool_urm.png new file mode 100644 index 0000000000000000000000000000000000000000..3d433824f95a5f9a9076e7094ac81a67a1d982e4 GIT binary patch literal 30120 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 Date: Sun, 13 Sep 2020 18:26:52 +0300 Subject: [PATCH 125/254] Update README.md --- throttling/README.md | 19 +++- throttling/etc/throttling-pattern.png | Bin 50223 -> 0 bytes throttling/etc/throttling-pattern.ucls | 88 ------------------ throttling/etc/throttling_urm.png | Bin 0 -> 53754 bytes .../com/iluwatar/throttling/CallsCount.java | 1 - 5 files changed, 14 insertions(+), 94 deletions(-) delete mode 100644 throttling/etc/throttling-pattern.png delete mode 100644 throttling/etc/throttling-pattern.ucls create mode 100644 throttling/etc/throttling_urm.png diff --git a/throttling/README.md b/throttling/README.md index 257bce54a..4a77638e1 100644 --- a/throttling/README.md +++ b/throttling/README.md @@ -10,12 +10,15 @@ tags: --- ## Intent + Ensure that a given client is not able to access service resources more than the assigned limit. ## Explanation + Real world example -> A large multinational corporation offers API to its customers. The API is rate-limited and each customer can only make certain amount of calls per second. +> A large multinational corporation offers API to its customers. The API is rate-limited and each +> customer can only make certain amount of calls per second. In plain words @@ -23,7 +26,9 @@ In plain words [Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling) says -> Control the consumption of resources used by an instance of an application, an individual tenant, or an entire service. This can allow the system to continue to function and meet service level agreements, even when an increase in demand places an extreme load on resources. +> Control the consumption of resources used by an instance of an application, an individual tenant, +> or an entire service. This can allow the system to continue to function and meet service level +> agreements, even when an increase in demand places an extreme load on resources. **Programmatic Example** @@ -77,7 +82,8 @@ public final class CallsCount { } ``` -Next we introduce the service that the tenants are calling. To track the call count we use the throttler timer. +Next we introduce the service that the tenants are calling. To track the call count we use the +throttler timer. ```java public interface Throttler { @@ -134,7 +140,8 @@ class B2BService { } ``` -Now we are ready to see the full example in action. Tenant Adidas is rate-limited to 5 calls per second and Nike to 6. +Now we are ready to see the full example in action. Tenant Adidas is rate-limited to 5 calls per +second and Nike to 6. ```java public static void main(String[] args) { @@ -171,9 +178,11 @@ Now we are ready to see the full example in action. Tenant Adidas is rate-limite ## Class diagram -![alt text](./etc/throttling-pattern.png "Throttling pattern class diagram") + +![alt text](./etc/throttling_urm.png "Throttling pattern class diagram") ## Applicability + The Throttling pattern should be used: * When a service access needs to be restricted to not have high impacts on the performance of the service. diff --git a/throttling/etc/throttling-pattern.png b/throttling/etc/throttling-pattern.png deleted file mode 100644 index 59e590aaf6ddf262b0f036cc55655cd4d4e5819b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50223 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