Compare commits

..

484 Commits

Author SHA1 Message Date
06678a5888 #1617 update license headers 2021-01-24 20:07:40 +02:00
11d0912c6e #1617 merge dto pattern examples 2021-01-24 19:57:21 +02:00
3adc3cda05 update gitignore (#1632)
.checkstyle files are being tracked which should not be
2021-01-24 11:17:05 +02:00
18a1a725ee #1469 Add lambda expressions implementation for Strategy Pattern (#1631)
* #1469 Add Strategy Pattern lambda implementation

After Java 8.
Also take advantage of enum

* #1469 Update class diagrams

* #1469 Update README.md

Add lambda programmatic example

* #1469 Remove unused imports

Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2021-01-19 12:06:26 +05:30
25ed2540f4 docs: add demirhalil as a contributor (#1630)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2021-01-16 21:00:23 +02:00
aa46e119d6 Fix flag image size 2021-01-16 20:55:20 +02:00
7e56491e92 #1625 Turkish translation - initialization part (#1629)
* #1625 init Turkish translation and add the flag

* #1625 update the Main README.md for Turkish translation

* #1625 add Turkish translation for README.md

Co-authored-by: Halil Demir <halil.demir@zalando.de>
2021-01-16 20:49:35 +02:00
6918a4bac2 docs: add ignite1771 as a contributor (#1626)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2021-01-13 13:31:11 +05:30
dea7ecfb7a #1317 Special Case Pattern (#1624)
* #1317 Add Special Case Pattern

To focus on pattern itself, I implement DB and
maintenance lock by the singleton instance.

* #1317 Add special cases unit tests

Assert the logger output
(ref: https://stackoverflow.com/a/52229629)

* #1317 Add README.md

Add Special Case Pattern README

* #1317 Format: add a new line to end of file

Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2021-01-13 13:06:21 +05:30
bbc4fdfc24 docs: add tkhadir as a contributor (#1623)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2021-01-04 19:42:58 +05:30
829cd41455 #1620 french translation - initialization part (#1622)
* 🚀 init fr translation

* #1620 evo add french translation - main part

* #1620 evo add french translation - main part

* #1620 evo french translation - add french flag

* Update README.md

* Update README.md

* #1620 add cn and kr flags

* Update README.md

* Update README.md

* Update README.md

* Update README.md
2021-01-04 19:27:32 +05:30
85a05dd718 docs: add warp125 as a contributor (#1619)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-20 20:20:51 +02:00
0c66e48d81 README.md translated into Korean (#1582)
* Translate README.md via GitLocalize

* Translate README.md via GitLocalize

* Update README.md

* Translate README.md via GitLocalize

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Translate README.md via GitLocalize

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Translate README.md via GitLocalize

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Translate README.md via GitLocalize

* Update README.md

Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>
2020-12-20 20:18:23 +02:00
801006337a docs: add ruchpeanuts as a contributor (#1618)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-13 17:35:37 +02:00
2aa4c963eb Update README.md (#1598)
Factory method is updated with real world examples
2020-12-13 17:33:43 +02:00
8632962362 docs: add siavashsoleymani as a contributor (#1616)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2020-12-09 13:11:15 +05:30
5bc61c8c28 #1569 DTO pattern implementation using Enums (#1570)
* #1569 DTO pattern implemented using Enums

* #1569 DTO pattern implemented using Enums

* #1569 adding some java docs

* #1569 some changes in java doc and code style

* #1569 some changes in java doc and code style

* #1569 some changes in java doc and code style

* #1569 some changes in java doc and code style

* #1569 adding suggested extra line

* #1569 license added to pom.xml

* #1569 more checkstyle problems resolved

* #1569 more checkstyle problems resolved

* #1569 more checkstyle problems resolved

Co-authored-by: siavashsoleymani <siavash.soleimani@snapp.cab>
Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2020-12-09 12:51:24 +05:30
a94615ac54 docs: add viveksb007 as a contributor (#1613)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-08 10:58:39 +05:30
14c4710435 Implemented Registry pattern (#1543)
* #1310 Implemented registry pattern

* fixed parent pom version

* added empty line in registry.urm.puml

Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2020-12-08 10:34:42 +05:30
428cbc1027 docs: add jeff303 as a contributor (#1612)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-07 20:25:59 +02:00
a118a995ec docs: add omk13 as a contributor (#1611)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-07 19:58:05 +02:00
759c99d078 JUnit4 to JUnit5 (#1589)
* Getting @Test from JUnit5 instead of JUnit4

* Changed FixedStepGameLoopTest.java imports and tests to JUnit5

* JUnit4 to JUnit5

* JUnit4 to JUnit5

* JUnit4 to JUnit5

* JUnit4 to JUnit5
2020-12-07 19:55:13 +02:00
e9f73bcf0b Translation zh (#1610)
* add state and callback pattern

* add command and template-method pattern

* add iterator pattern

* add bridege and DI pattern

* fix issue #1600

Co-authored-by: Mike <admin@xiaod.info>
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-12-06 16:13:48 +02:00
29ceac2fb0 Update README.md (#1592) 2020-12-05 10:56:00 +02:00
7255c2c5e7 docs: add Anurag870 as a contributor (#1609)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* Update README.md

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-12-05 10:50:09 +02:00
68308dc550 Update README.md (#1590) 2020-12-05 10:34:49 +02:00
1e10951c23 Translation zh (#1597)
* add state and callback pattern

* add command and template-method pattern

* add iterator pattern

Co-authored-by: Mike <admin@xiaod.info>
2020-12-04 20:03:14 +02:00
f3c876ed2e Merge pull request #1607 from iluwatar/all-contributors/add-gkulkarni2020
docs: add gkulkarni2020 as a contributor
2020-12-04 15:48:40 +02:00
ecd1a5d07f docs: update .all-contributorsrc [skip ci] 2020-12-04 13:47:58 +00:00
8b15c24753 docs: update README.md [skip ci] 2020-12-04 13:47:57 +00:00
f5a6161044 Merge pull request #1604 from gkulkarni2020/master
Word mistake in factory/README.md #1601
closes #1601
2020-12-04 14:17:32 +05:30
76eefa80b5 Merge branch 'master' into master 2020-12-04 13:30:11 +05:30
c282ab80fd Merge pull request #1606 from iluwatar/all-contributors/add-ibrahimAlii
docs: add ibrahimAlii as a contributor
2020-12-01 22:48:24 +02:00
1edfb44642 docs: update .all-contributorsrc [skip ci] 2020-12-01 20:47:33 +00:00
e185c497ac docs: update README.md [skip ci] 2020-12-01 20:47:32 +00:00
d5a054c1f8 Merge pull request #1605 from iluwatar/all-contributors/add-OrangePants-R
docs: add OrangePants-R as a contributor
2020-11-30 16:57:52 +02:00
ced7a9deb0 docs: update .all-contributorsrc [skip ci] 2020-11-30 14:57:00 +00:00
90c6cf94d5 docs: update README.md [skip ci] 2020-11-30 14:56:59 +00:00
996bd937fb Merge pull request #1576 from OrangePants-R/master
issue 525: attach tutorialspoint link to iterator pattern
2020-11-30 16:55:19 +02:00
7931471b99 Word mistake in factory/README.md #1601 2020-11-30 15:26:01 +05:30
b8ecbaa451 Merge pull request #1603 from iluwatar/all-contributors/add-grzesiekkedzior
docs: add grzesiekkedzior as a contributor
2020-11-28 15:09:18 +02:00
fb4df48cb3 Merge branch 'master' into all-contributors/add-grzesiekkedzior 2020-11-28 15:08:15 +02:00
96fadf3bd7 docs: update .all-contributorsrc [skip ci] 2020-11-28 13:04:26 +00:00
dd599595cc docs: update README.md [skip ci] 2020-11-28 13:04:25 +00:00
fcd7785f0d Merge pull request #1568 from ohbus/master
Update Pull Requests CI trigger behaviour
2020-11-28 14:38:00 +02:00
2432d120b4 Merge pull request #1602 from iluwatar/all-contributors/add-eimanip
docs: add eimanip as a contributor
2020-11-28 14:25:41 +02:00
4b18e223cd docs: update .all-contributorsrc [skip ci] 2020-11-28 12:24:58 +00:00
13c6de036f docs: update README.md [skip ci] 2020-11-28 12:24:57 +00:00
6f979d0cb2 Fix version number class diagram not showing 2020-11-24 08:10:34 +02:00
f084f8bf41 Merge pull request #1599 from iluwatar/all-contributors/add-manannikov
docs: add manannikov as a contributor
2020-11-23 22:38:24 +02:00
6c95868b8d docs: update .all-contributorsrc [skip ci] 2020-11-23 20:37:49 +00:00
4c7f1b7822 docs: update README.md [skip ci] 2020-11-23 20:37:48 +00:00
0c44b53909 Merge pull request #1563 from manannikov/Issue#1284
#1284 Implement Version Number pattern
2020-11-23 22:35:43 +02:00
9ead3adf73 #1284 Divide tests 2020-11-23 20:59:00 +02:00
97e3a3debc #1284 Use local variable inference 2020-11-23 19:42:50 +02:00
43ed09015d Add missing license header 2020-11-22 21:14:53 +02:00
7eee546208 Update README.md 2020-11-08 19:39:21 +02:00
dc31960710 Remove unused logger objects 2020-11-08 19:37:15 +02:00
7c0fdad5a2 Merge pull request #1531 from ravening/command-functional
Refactor the command pattern to use lambda functions
2020-11-08 19:33:48 +02:00
5a8933ea17 Merge pull request #1534 from swarajsaaj/#1510-Circuit-Breaker-Refactoring
#1510 Improvements done in Circuit Breaker
2020-11-07 20:04:47 +02:00
d02233f0b7 Merge pull request #1594 from iluwatar/all-contributors/add-akashchandwani
docs: add akashchandwani as a contributor
2020-11-07 14:36:54 +02:00
d42bcab9fc docs: update .all-contributorsrc [skip ci] 2020-11-07 12:34:36 +00:00
77b2ff2150 docs: update README.md [skip ci] 2020-11-07 12:34:35 +00:00
cff072d1ca Merge pull request #1593 from iluwatar/all-contributors/add-dsibilio
docs: add dsibilio as a contributor
2020-11-07 14:34:08 +02:00
80ba0407db docs: update .all-contributorsrc [skip ci] 2020-11-07 12:33:11 +00:00
6a09b909f2 docs: update README.md [skip ci] 2020-11-07 12:33:10 +00:00
53ccc0e7e6 Merge pull request #1548 from dsibilio/patch-1
Add missing word to README.md
2020-11-07 14:31:26 +02:00
a7a8e23b01 Merge pull request #1591 from iluwatar/all-contributors/add-Ascenio
docs: add Ascenio as a contributor
2020-11-07 09:49:20 +02:00
2783251d00 docs: update .all-contributorsrc [skip ci] 2020-11-07 07:47:42 +00:00
ac432968ae docs: update README.md [skip ci] 2020-11-07 07:47:41 +00:00
26b5364cbd issue 525: attach tutorialspoint link to iterator pattern 2020-10-19 11:24:39 -06:00
f006782805 Merge pull request #1529 from mookkiah/issue_1500
issue 1500 - using JUnit 5 and resolved a build issue
2020-10-17 18:02:56 +03:00
38cc490e3f update namespaces of different steps of build job 2020-10-17 10:14:49 +05:30
911cfd64af Update maven-pr-builder.yml 2020-10-16 09:36:02 +05:30
2332520d67 #1284 Implement Version Number pattern 2020-10-13 20:17:25 +03:00
af1b611136 code refactor 2020-10-13 17:36:59 +02:00
4ff196ce35 Refactor the command pattern to use lambda functions
We can leverage the lambda expressins of Java 8 onwards
to implement command design pattern instead of traditional
non functional way
2020-10-13 16:45:19 +02:00
242ae6a412 #1510 Update class diagram 2020-10-11 00:22:28 +05:30
b689fe0a26 #1510 Fix comment length 2020-10-11 00:11:06 +05:30
7aea765dd1 #1510 Fix review comments 2020-10-10 23:57:53 +05:30
ea49cbfe94 Merge branch 'master' into #1510-Circuit-Breaker-Refactoring 2020-10-10 22:19:46 +05:30
1f4a412e70 Merge pull request #1535 from ohbus/master
Cache SonarCloud packages
2020-10-10 18:51:00 +03:00
36d0a3718c Update README.md
Missing word in sentence.
2020-10-06 18:24:47 +02:00
195a735814 #508 fix SpaceStationMir logging 2020-10-04 14:50:48 +03:00
633d45aa67 Fix typo 2020-10-04 14:33:01 +03:00
adc267e48e Merge pull request #1526 from xiaod-dev/translation-zh
Translation zh
2020-10-04 14:26:39 +03:00
cc8d209c22 Merge pull request #1545 from iluwatar/all-contributors/add-ChFlick
docs: add ChFlick as a contributor
2020-10-04 14:24:48 +03:00
578b3528d5 docs: update .all-contributorsrc [skip ci] 2020-10-04 11:23:50 +00:00
5674f3c52e docs: update README.md [skip ci] 2020-10-04 11:23:49 +00:00
4ad2bfefad Merge pull request #1525 from ChFlick/patch-1
Fix links on the event sourcing page
2020-10-04 14:21:25 +03:00
e5d219609d Add missing license headers 2020-10-04 14:17:28 +03:00
21ca47a22e Fix build 2020-10-04 14:17:10 +03:00
ebd38bcfaa Update license header 2020-10-04 14:09:36 +03:00
a3753807ae add Caching of SonarCloud packages 2020-10-01 22:23:43 +05:30
64266d63fd Merge pull request #1 from iluwatar/master
Update README.md
2020-10-01 22:18:53 +05:30
4f62070eb2 #1510 Revert pom to include all modules 2020-10-01 21:13:30 +05:30
b29bd66369 #1510 Improvments done in Circuit Breaker 2020-10-01 21:09:39 +05:30
ad435dd2fd issue 1500 - using Junit 5 and resolved a build issue 2020-09-27 09:26:19 -04:00
a125879d15 Update README.md 2020-09-26 13:01:58 +03:00
dac8e659ce add facade pattern 2020-09-22 16:50:46 +08:00
a1515b3b52 finish builder and chain pattern 2020-09-22 11:13:25 +08:00
d2e070d21d Fix links on the event sourcing page 2020-09-16 13:44:50 +02:00
82eb41b641 Update README.md 2020-09-13 18:35:23 +03:00
24e8fa1bad Update README.md 2020-09-13 18:32:12 +03:00
9017975276 Update README.md 2020-09-13 18:26:52 +03:00
87093cf221 Update README.md 2020-09-13 18:23:54 +03:00
6cb5b4a683 Update README.md 2020-09-13 18:19:35 +03:00
e6ddff5f25 Update README.md 2020-09-13 18:15:17 +03:00
b5fddd469a Update README.md 2020-09-13 18:09:41 +03:00
9cbc509c3a Update README.md 2020-09-13 18:09:18 +03:00
9c648cbdb8 Update README.md 2020-09-13 18:04:30 +03:00
e6cca86e25 Update README.md 2020-09-13 17:59:12 +03:00
c204b242df Update README.md 2020-09-13 17:53:50 +03:00
2e98dcf217 Update README.md 2020-09-13 17:39:10 +03:00
9d44eea64f Merge pull request #1524 from iluwatar/all-contributors/add-swarajsaaj
docs: add swarajsaaj as a contributor
2020-09-13 17:24:32 +03:00
6f592f5e8a docs: update .all-contributorsrc [skip ci] 2020-09-13 14:23:53 +00:00
74b968942f docs: update README.md [skip ci] 2020-09-13 14:23:52 +00:00
ebc0e8b3cd Merge pull request #1522 from swarajsaaj/master
#1313 Add Separated Interface pattern
2020-09-13 17:21:28 +03:00
9088ac51f6 #1313 Rename DomesticTax,ForeignTax and review fixes 2020-09-12 22:35:40 +05:30
c8f7a8f0e6 Merge pull request #1523 from iluwatar/all-contributors/add-vdlald
docs: add vdlald as a contributor
2020-09-12 20:02:32 +03:00
c63af2ccbf docs: update .all-contributorsrc [skip ci] 2020-09-12 17:00:59 +00:00
9f3f5322d2 docs: update README.md [skip ci] 2020-09-12 17:00:58 +00:00
5607a4974c Merge pull request #1517 from vdlald/847
847
2020-09-12 19:57:29 +03:00
93aa1046aa translate decorator and factory method pattern in Chinese 2020-09-11 09:34:11 +08:00
a2967c5a40 #1313 Add documentation and license header 2020-09-10 03:22:00 +05:30
7fd7735527 #1313 Add separated-interface module to parent pom 2020-09-10 03:10:58 +05:30
f6942cf18d #1313 Add Separated Interface design pattern 2020-09-10 02:57:56 +05:30
ef326ee77e Update README.md 2020-09-06 19:56:07 +03:00
8b5f532a50 Update README.md 2020-09-06 19:55:38 +03:00
a1da1e4973 Cleanup factory 2020-09-06 19:46:13 +03:00
9d21dff855 Merge pull request #1520 from iluwatar/all-contributors/add-ravening
docs: add ravening as a contributor
2020-09-06 19:39:08 +03:00
9d75592e8b Merge branch 'master' into all-contributors/add-ravening 2020-09-06 19:38:44 +03:00
8d6738b729 docs: update .all-contributorsrc [skip ci] 2020-09-06 16:37:04 +00:00
3205dc2cf0 docs: update README.md [skip ci] 2020-09-06 16:37:03 +00:00
16e1863ae7 Merge pull request #1519 from iluwatar/all-contributors/add-samilAyoub
docs: add samilAyoub as a contributor
2020-09-06 19:36:35 +03:00
b9db3c4763 docs: update .all-contributorsrc [skip ci] 2020-09-06 16:35:58 +00:00
d72206ba72 docs: update README.md [skip ci] 2020-09-06 16:35:57 +00:00
922c699e49 Merge pull request #1516 from samilAyoub/add-simple-factory
Add Simple Factory Pattern implementation
2020-09-06 19:33:03 +03:00
bab48efd7c fix style 2020-09-06 12:01:48 +03:00
29eecfd048 forgot to run the App 2020-09-06 11:52:16 +03:00
87cf6b791c refactor 2020-09-06 11:48:40 +03:00
2e36a11e24 remove lombok, related to #1503 2020-09-06 11:42:39 +03:00
bf41b1d9c9 Updates README.md:
- Adding class diagram
- Adding Pros and Cons
- replace "" with ''
2020-09-05 18:39:28 +01:00
b3ef214cd6 Change tabs to spaces in pom.xml 2020-09-04 22:02:19 +01:00
6caf78e4e5 updates :
- Using lambda expression to create cars
- Using spaces instead of tabs in pom.xml
2020-09-04 21:21:51 +01:00
bd48d6ce10 refactor 2020-09-04 17:31:50 +03:00
8b26452c75 bug fixing 2020-09-03 22:58:15 +01:00
2bb252e08f Clean the code 2020-09-03 22:41:55 +01:00
a023cfbb1a Merge branch 'master' into add-simple-factory 2020-09-03 22:26:49 +01:00
badf0c6b8c - README.md is added
- Change the name to factory is done
- Local variable type inference is used
2020-09-03 22:08:54 +01:00
c9718a5227 add README file 2020-09-03 21:08:28 +01:00
e89042a782 remove boilerplate code 2020-09-03 20:04:47 +03:00
fb890e80dd refactor 2020-09-03 20:02:52 +03:00
b423fd30d4 Fix bugs, clean the code and add unit tests. 2020-09-02 18:12:42 +01:00
3df8472bf8 Merge pull request #1515 from fedorskvorcov/fix-typo
Remove unnecessary word from text
2020-09-02 19:59:07 +03:00
ac98b31b68 Add Maven Assembly plugin to pom.xml 2020-09-02 14:09:44 +01:00
46b23f322f Add Simple Factory Pattern implementation
Java source code demonstrate simple factory design pattern
2020-09-02 13:46:53 +01:00
e231cd8d1a Remove unnecessary word from text 2020-09-02 12:32:02 +03:00
19378f3fdd Update README.md 2020-09-01 20:25:39 +03:00
3f4d637510 Update README.md 2020-09-01 20:18:10 +03:00
25cca3547d Update README.md 2020-09-01 20:06:47 +03:00
b9b6777d15 Update README.md 2020-09-01 19:55:22 +03:00
2a5b8c977a Merge pull request #1514 from iluwatar/all-contributors/add-fedorskvorcov
docs: add fedorskvorcov as a contributor
2020-09-01 16:40:23 +03:00
daa94c7b6d docs: update .all-contributorsrc [skip ci] 2020-09-01 13:39:33 +00:00
7aca64a3c9 docs: update README.md [skip ci] 2020-09-01 13:39:32 +00:00
6628bccecc Merge pull request #1513 from fedorskvorcov/fix-typo
Fix typo in comment
2020-09-01 16:38:44 +03:00
aebdb88a83 Fix typo in comment 2020-09-01 09:51:46 +03:00
9c0c17b87a Merge pull request #1512 from xiaod-dev/translation-zh
Translation zh
2020-08-31 20:17:39 +03:00
20fac32ac2 finish Chinese translation of observer and strategy 2020-08-31 17:18:59 +08:00
82842d614b Update README.md 2020-08-30 20:08:34 +03:00
9b71479d04 Update README.md 2020-08-30 19:34:10 +03:00
3c4ae6c4ca Update README.md 2020-08-30 19:17:45 +03:00
9ff42389c6 Merge pull request #1511 from ohbus/master
Configure build to disable shallow clone
2020-08-30 11:52:13 +03:00
b80b9354c6 Update maven-ci.yml 2020-08-30 02:31:06 +05:30
67d1d16e1f Update README.md 2020-08-29 22:13:55 +03:00
bc35911475 Update README.md 2020-08-29 22:02:10 +03:00
b5c6a89ec9 Update README.md 2020-08-29 21:55:51 +03:00
74360a7ecb Update README.md 2020-08-29 21:51:32 +03:00
3544a8366f Update README.md 2020-08-29 21:38:58 +03:00
bcca9beb4d Update README.md 2020-08-29 21:29:15 +03:00
6606d6cd08 Update README.md 2020-08-29 21:21:01 +03:00
f3fd49870c Update README.md 2020-08-29 21:05:30 +03:00
1fbef60f37 Update README.md 2020-08-29 21:00:17 +03:00
b77a05f0fb Update README.md 2020-08-29 20:46:40 +03:00
0ee03db4d0 Update README.md 2020-08-29 20:38:04 +03:00
c541176b38 Update README.md 2020-08-29 20:26:37 +03:00
b53856b64f Merge pull request #1509 from ohbus/master
Cleaning up unnecessary code from the CI yaml and CI server version upgrade
2020-08-29 20:19:42 +03:00
1973d1bc63 Update maven-pr-builder.yml
upgraded build server runtime from Ubuntu 18.04 to 20.04 LTS for the PR builder as well
2020-08-29 19:35:20 +05:30
f5886325ec Update maven-ci.yml
upgraded build server runtime from Ubuntu 18.04 to 20.04 LTS
2020-08-29 19:34:43 +05:30
8afe4c314a Update README.md 2020-08-29 16:56:52 +03:00
2dd2cfb8ca Update README.md 2020-08-29 16:49:45 +03:00
8512c65aef Update README.md 2020-08-29 16:42:46 +03:00
6373f7b115 Update README.md 2020-08-29 16:38:20 +03:00
e8b42bd135 Update README.md 2020-08-29 16:23:28 +03:00
2bb2134636 Update README.md 2020-08-29 16:17:15 +03:00
675b2f14b2 Update README.md 2020-08-29 16:10:59 +03:00
338c146c78 Update maven-pr-builder.yml 2020-08-29 17:39:50 +05:30
8135dbecdb Update maven-ci.yml 2020-08-29 17:36:31 +05:30
a4f2d14848 Update README.md 2020-08-29 12:01:23 +03:00
96c16a8f3a Update README.md 2020-08-29 11:29:30 +03:00
47e746c3ba Update maven-pr-builder.yml
removed the if checking block for building Pull Requests as this was redundant code.
2020-08-28 12:26:27 +05:30
7118ccafa9 Update maven-ci.yml
Removed if clause for building code in main codebase from the CI pipeline.
2020-08-28 12:17:38 +05:30
8983f9c11c Update README.md 2020-08-26 21:55:05 +03:00
9b464e0be1 Merge pull request #1507 from amit1307/upgrade-mockito-1486
Upgrade Mockito version
2020-08-26 21:20:11 +03:00
b07d33f332 Upgrade Mockito version to latest 2020-08-26 00:09:30 +01:00
6c4c6097be Merge branch 'master' of https://github.com/iluwatar/java-design-patterns 2020-08-25 23:21:25 +01:00
9dd46d7b4a Update README.md 2020-08-25 21:42:42 +03:00
723afb85ba Set version for next development iteration 2020-08-25 21:21:36 +03:00
a0e5d061cb Milestone 1.23.0 2020-08-25 21:20:30 +03:00
687648af0a Merge pull request #1506 from iluwatar/all-contributors/add-stefanbirkner
docs: add stefanbirkner as a contributor
2020-08-25 17:43:29 +03:00
96aa21d0e8 docs: update .all-contributorsrc [skip ci] 2020-08-25 14:42:54 +00:00
b8f83c326d docs: update README.md [skip ci] 2020-08-25 14:42:53 +00:00
15d795bf8a Merge pull request #1505 from stefanbirkner/system-lambda
Replace System Rules with System Lambda
2020-08-25 17:41:09 +03:00
3754c66604 Replace System Rules with System Lambda
System Lambda is more specific. It only wraps the part of the code that
produces the output.
2020-08-24 23:20:03 +02:00
6d83ceba28 Update README.md 2020-08-23 18:53:57 +03:00
015b418114 Update README.md 2020-08-23 18:03:29 +03:00
0cba307844 Fix readme filename 2020-08-23 17:06:37 +03:00
a66edc84a0 Merge pull request #1504 from iluwatar/all-contributors/add-mkrzywanski
docs: add mkrzywanski as a contributor
2020-08-23 17:00:32 +03:00
c18282ad5d docs: update .all-contributorsrc [skip ci] 2020-08-23 13:59:15 +00:00
7411ea86bf docs: update README.md [skip ci] 2020-08-23 13:59:14 +00:00
ef033b66a6 Merge pull request #1499 from mkrzywanski/pattern/filterer
Filterer pattern
2020-08-23 16:56:06 +03:00
e65b65257e fixing typos in readme file, introducing var local type inference where possible 2020-08-23 11:00:15 +02:00
3d9afbaeec fixed typo in read me 2020-08-22 18:24:41 +02:00
61a819aab8 Added fixes after review. Changed example pattern application to threat detection domain 2020-08-22 18:11:14 +02:00
61b95c294b Update github token 2020-08-22 14:49:56 +03:00
4068d1fead Update sonar badges 2020-08-22 14:03:21 +03:00
b284230ecf Merge pull request #1502 from iluwatar/all-contributors/add-edycutjong
docs: add edycutjong as a contributor
2020-08-21 18:01:31 +03:00
0529b77abb docs: update .all-contributorsrc [skip ci] 2020-08-21 15:00:49 +00:00
a2ae5d1324 docs: update README.md [skip ci] 2020-08-21 15:00:48 +00:00
25159ed9a8 Merge pull request #1501 from iluwatar/all-contributors/add-ToxicDreamz
docs: add ToxicDreamz as a contributor
2020-08-21 17:35:37 +03:00
7f09cd5b2d docs: update .all-contributorsrc [skip ci] 2020-08-21 14:34:24 +00:00
b388020fc0 docs: update README.md [skip ci] 2020-08-21 14:34:23 +00:00
0c552effc3 Merge pull request #1492 from ToxicDreamz/SonarCloud-Reports-Issue#1012
Fixed most reported issues by SonarCloud.
2020-08-21 17:25:16 +03:00
905b5dc6d8 Implemented filterer pattern 2020-08-21 11:51:43 +02:00
885c8a6765 Fixed a test-case issue within the dirty-flag module. 2020-08-20 01:21:03 +04:00
6b5b2ac1e8 Merge remote-tracking branch 'origin/SonarCloud-Reports-Issue#1012' into SonarCloud-Reports-Issue#1012 2020-08-20 01:03:50 +04:00
c35b98b4d7 Fixed pom.xml issues within the dirty-flag and partial-response modules that were causing build failures. 2020-08-20 01:01:03 +04:00
f5fddeb7f0 Merge branch 'master' into SonarCloud-Reports-Issue#1012 2020-08-19 23:29:36 +04:00
292ec5b8e5 Merge branch 'SonarCloud-Reports-Issue#1012'
# Conflicts:
#	pom.xml
2020-08-19 23:27:43 +04:00
60d87789a6 Merge pull request #1 from iluwatar/master
Fork Update
2020-08-19 23:26:19 +04:00
860453b46b Fixed JUnit tests causing build issues due to mixing JUnit 4 & JUnit 5 2020-08-19 23:14:37 +04:00
6921b0dce0 Fixed checkstyle errors causing build failures. 2020-08-19 13:27:08 +04:00
1e385056fc finish translate adapter pattern into chinese 2020-08-19 17:10:14 +08:00
847585334c Update README.md 2020-08-18 20:09:04 +03:00
9bb0b6fe6f Merge pull request #1498 from iluwatar/all-contributors/add-ohbus
docs: add ohbus as a contributor
2020-08-18 19:46:13 +03:00
31881f500d docs: update .all-contributorsrc [skip ci] 2020-08-18 16:45:38 +00:00
06f20570b6 docs: update README.md [skip ci] 2020-08-18 16:45:37 +00:00
017ee23793 Merge pull request #1497 from iluwatar/all-contributors/add-nahteb
docs: add nahteb as a contributor
2020-08-18 19:42:38 +03:00
6c7715ace6 docs: update .all-contributorsrc [skip ci] 2020-08-18 16:42:03 +00:00
ef43af3b23 docs: update README.md [skip ci] 2020-08-18 16:42:02 +00:00
95e513b6ec Edit readme 2020-08-17 19:49:00 +03:00
194040543e Merge pull request #1493 from ohbus/master
updated workflows
2020-08-17 19:18:39 +03:00
846a174ade Merge pull request #1496 from iluwatar/all-contributors/add-ohbus
docs: add ohbus as a contributor
2020-08-17 19:14:47 +03:00
7f60f7be25 docs: update .all-contributorsrc [skip ci] 2020-08-17 16:14:04 +00:00
cfb58191ea docs: update README.md [skip ci] 2020-08-17 16:14:03 +00:00
82bf9fdd61 Merge pull request #1494 from nahteb/fix-typo
Fix typo in README for Observer pattern
2020-08-17 19:13:25 +03:00
be552d0ece Merge pull request #1495 from iluwatar/all-contributors/add-xdvrx1
docs: add xdvrx1 as a contributor
2020-08-17 19:11:05 +03:00
d584404df6 docs: update .all-contributorsrc [skip ci] 2020-08-17 16:10:21 +00:00
353a2d9fcf docs: update README.md [skip ci] 2020-08-17 16:10:20 +00:00
8c5740563d reverted the copyright year back to 2019 2020-08-17 19:12:54 +05:30
89bda692f8 Fix typo in README
The log message in the Orcs class should say orcs instead of hobbits.

This is correct in the code example but wrong in the README.
2020-08-17 07:47:30 +01:00
241f93f3cc updated cache to v2 and removed SQ analysis 2020-08-17 11:28:33 +05:30
57e45a329f Fixed a whitespace and spelling issue that was causing the test case to fail. 2020-08-16 22:35:15 +04:00
79a6af703e updated copyright year to 2020 2020-08-16 12:49:21 +05:30
00d06871f4 updated workflows 2020-08-16 12:42:08 +05:30
133ef52898 Fixed an issue with the order of imports that was causing build failures. 2020-08-15 22:19:27 +04:00
7afb065a10 Upgrade urm plugin to latest version 2020-08-15 20:59:11 +03:00
af9f8fe4e1 Merge pull request #1491 from iluwatar/all-contributors/add-xdvrx1
docs: add xdvrx1 as a contributor
2020-08-15 20:54:25 +03:00
a1c96ede13 docs: update .all-contributorsrc [skip ci] 2020-08-15 17:53:38 +00:00
0d2c4abe5a docs: update README.md [skip ci] 2020-08-15 17:53:37 +00:00
31471acb69 Fixed most reported issues by SonarCloud. 2020-08-15 21:47:39 +04:00
e7e3ace01f Merge pull request #1489 from iluwatar/all-contributors/add-RayYH
docs: add RayYH as a contributor
2020-08-11 17:30:33 +03:00
41dacc2e2e docs: update .all-contributorsrc [skip ci] 2020-08-11 14:29:45 +00:00
dc7bf6190d docs: update README.md [skip ci] 2020-08-11 14:29:44 +00:00
98d2dc0104 Merge pull request #1487 from RayYH/master
fix word typo
2020-08-11 17:29:06 +03:00
870d44b127 Fix layout 2020-08-11 17:26:05 +03:00
834f20911b Merge pull request #1488 from iluwatar/all-contributors/add-ashishtrivedi16
docs: add ashishtrivedi16 as a contributor
2020-08-11 17:23:22 +03:00
2b7949ce6a docs: update .all-contributorsrc [skip ci] 2020-08-11 14:21:59 +00:00
4ffab7da85 docs: update README.md [skip ci] 2020-08-11 14:21:58 +00:00
1683fbdf9c Clean up Transaction Script 2020-08-11 17:17:25 +03:00
d091e369ec Merge pull request #1480 from ashishtrivedi16/master
#1321 Transaction script model implementation
2020-08-11 16:59:48 +03:00
b91bbc773d fix word typo 2020-08-11 14:19:39 +08:00
3c07a42e9d #1321 Updated UML diagram 2020-08-11 00:23:00 +05:30
e99bcf772b #1321 Added comments about TS 2020-08-11 00:21:46 +05:30
2d16e5afbf Merge branch 'master' of https://github.com/iluwatar/java-design-patterns 2020-08-10 16:27:28 +03:00
2c6f1832b0 Merge pull request #1485 from amit1307/logging-api-gateway-1338
Add logging in API Gateway
2020-08-10 16:26:18 +03:00
04a2be0c99 Update readme 2020-08-10 16:25:06 +03:00
10815b6469 Fix tags 2020-08-10 16:05:52 +03:00
75b10ed657 #1321 2020-08-10 13:21:24 +05:30
108532d8dd #1321 2020-08-10 13:12:12 +05:30
5527cf4234 #1321 Renamed main class 2020-08-10 13:06:46 +05:30
4008ae41b5 #1321 2020-08-10 13:02:35 +05:30
8166a1835d Merge remote-tracking branch 'origin/master' 2020-08-10 13:01:30 +05:30
4c9cad5475 #1321 Updated README 2020-08-10 13:01:12 +05:30
24126edd86 Update Hotel.java 2020-08-10 12:54:46 +05:30
c0edac0046 Rename TransactionScriptApp.java to App.java 2020-08-10 12:53:13 +05:30
f5c337981b Rename Readme.md to README.md 2020-08-10 12:52:37 +05:30
5441db6582 Update pom.xml 2020-08-10 12:52:15 +05:30
87f3a4d956 Delete module-info.java 2020-08-10 12:48:55 +05:30
31d753e59d Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-10 00:25:43 +05:30
6cef98d41e Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-10 00:25:01 +05:30
7450456dae Add syntax highlighting 2020-08-09 21:54:54 +03:00
45e416928d Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-10 00:24:44 +05:30
94c131f7e9 Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-10 00:24:33 +05:30
5eb9b98e78 Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-10 00:24:20 +05:30
8305e9365d Fix typos 2020-08-09 21:49:00 +03:00
04e3368a81 Merge pull request #1482 from vINCENT8888801/private-class-data-explanation
Private class data explanation
2020-08-09 21:27:34 +03:00
d219a104c7 Add logging in API Gateway 2020-08-09 18:13:24 +01:00
700f5c6d27 corrected some typo 2020-08-09 18:22:40 +08:00
f4fa73cd48 Update README.md
Increase clarity
2020-08-09 16:28:40 +08:00
e09de2fb36 #1321 2020-08-09 01:58:19 +05:30
a59c9bba97 #1321 2020-08-09 01:39:51 +05:30
7acc5fbf95 #1321
Resolved conflicts and used var wherever possible
2020-08-09 01:33:19 +05:30
bdf2145b3f Merge branch 'master' into master 2020-08-09 01:17:07 +05:30
1e90d0d645 Merge pull request #1484 from iluwatar/all-contributors/add-vINCENT8888801
docs: add vINCENT8888801 as a contributor
2020-08-08 22:44:51 +03:00
b8c0985b97 docs: update .all-contributorsrc [skip ci] 2020-08-08 19:44:04 +00:00
c40d6ae9d7 docs: update README.md [skip ci] 2020-08-08 19:44:03 +00:00
76bfc68cd6 Merge pull request #1481 from vINCENT8888801/some-minor-spelling-error
Some minor spelling error in comment
2020-08-08 22:43:05 +03:00
d0ed10a619 Merge pull request #1479 from anuragagarwal561994/java-11
Java 11 remaining pattern
2020-08-08 22:32:43 +03:00
5bfaeffecf Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-09 00:51:44 +05:30
c0acaf073b Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-09 00:51:36 +05:30
9f190c59c4 Update transaction-script/Readme.md
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
2020-08-09 00:51:28 +05:30
50ed5ca699 Some minor spelling error in comment 2020-08-09 03:15:26 +08:00
08cec0e254 Update README.md 2020-08-09 03:10:43 +08:00
1f6e6f34ea Update README.md 2020-08-09 03:09:53 +08:00
134ccdb5a1 Corrects condition 2020-08-08 11:56:34 +00:00
fa68789cd5 #1321 Updated readme and add UML diagram 2020-08-08 15:49:14 +05:30
8b92bc6bb6 Corrects README.md 2020-08-08 00:53:30 +00:00
8e060ad0ad Refactors null object pattern to java-11 2020-08-08 00:46:08 +00:00
a5038c4329 Uses java-11 in naked objects 2020-08-08 00:41:58 +00:00
b0ac4c1ca3 #590 explanation for Arrange/Act/Assert 2020-08-07 19:10:50 +03:00
0ead283f55 Merge pull request #1475 from ravening/simplify_observer
Use enums instead os switch blocks
2020-08-05 17:59:52 +03:00
888af23219 Merge pull request #1220 from anuragagarwal561994/java-11
Java 11 (patterns with m)
2020-08-05 17:38:54 +03:00
0c83ccc2fe Use enums instead os switch blocks
Its better to use enums instead of switch
blocks which makes the code longer and difficult
to maintain as and when new state appears.
2020-08-05 15:50:05 +02:00
a7095602d6 Refactors using var 2020-08-04 21:46:30 +00:00
4b38746ce9 Removes usage of Dictionary 2020-08-04 21:41:25 +00:00
cd20e7a3f4 Minor readme fixes 2020-08-04 21:45:16 +03:00
7f29c2455f #590 explanation for Ambassador 2020-08-04 21:36:08 +03:00
51e8900d31 Merge pull request #1474 from iluwatar/all-contributors/add-ravening
docs: add ravening as a contributor
2020-08-04 17:48:52 +03:00
20a5dde8a4 docs: update .all-contributorsrc [skip ci] 2020-08-04 14:48:06 +00:00
bf4706addf docs: update README.md [skip ci] 2020-08-04 14:48:05 +00:00
97285d3724 Merge pull request #1472 from ravening/command
#1324 Use interfaces in command pattern
2020-08-04 17:47:32 +03:00
f234baf258 Cleanup code 2020-08-04 16:34:41 +02:00
ca58fa3f21 #590 add related patterns to Abstract Factory 2020-08-04 17:31:33 +03:00
ca7192889d Fixes test cases for master-worker-pattern 2020-08-03 18:50:45 +00:00
fa3b93bf8d #590 fix diagram 2020-08-03 21:25:13 +03:00
a7b4194a71 #590 explanation for Aggregator Microservices 2020-08-03 21:09:31 +03:00
054b1eaac6 Resolves test failures 2020-08-03 15:59:28 +00:00
44a654a2e3 Resolves CR comments 2020-08-03 15:45:29 +00:00
10988526a2 Merge branch 'master' of github.com:iluwatar/java-design-patterns into java-11 2020-08-03 15:42:18 +00:00
b9f17824fa removing unwanted modifiers 2020-08-03 17:38:03 +02:00
3ae7466647 Typically command pattern is implemented using
interfaces and concrete classes. Refactor the
code to use the same
2020-08-03 16:51:30 +02:00
9ff5b9e7c0 Fix merge 2020-08-03 16:49:46 +03:00
4941e8ebc4 Merge pull request #1471 from iluwatar/all-contributors/add-charlesfinley
docs: add charlesfinley as a contributor
2020-08-03 16:35:28 +03:00
081d789749 Merge branch 'master' into all-contributors/add-charlesfinley 2020-08-03 16:34:41 +03:00
f84f7b973c docs: update .all-contributorsrc [skip ci] 2020-08-03 13:30:52 +00:00
83acaa82d4 docs: update README.md [skip ci] 2020-08-03 13:30:51 +00:00
b0ded54c66 Cleanup 2020-08-02 22:48:54 +03:00
689cc8b59b Update surefire and minor improvements 2020-08-02 11:55:13 +03:00
8c7dd72d5a Merge pull request #1470 from charlesfinley/master
Updated ${artifactId} to ${project.artifactId}
2020-08-02 11:51:14 +03:00
14487261d0 Use of ${artifactId} is deprecated and should be updated to ${project.artifactId} 2020-08-02 00:03:36 -04:00
a9b7111b39 work on Abstract Factory readme 2020-08-01 16:26:14 +03:00
b3bfd43bff #590 update Acyclic Visitor class diagram 2020-08-01 15:54:46 +03:00
6a8297598e #1047 remove module infos 2020-08-01 15:19:09 +03:00
7ac8eba434 #590 explanation for Acyclic Visitor 2020-08-01 15:18:32 +03:00
595086aa13 Merge pull request #1467 from iluwatar/all-contributors/add-raja-peeyush-kumar-singh
docs: add raja-peeyush-kumar-singh as a contributor
2020-08-01 12:49:06 +03:00
38791a6a66 docs: update .all-contributorsrc [skip ci] 2020-08-01 09:48:24 +00:00
27c40826de docs: update README.md [skip ci] 2020-08-01 09:48:23 +00:00
d1d67bcb6c Merge pull request #1466 from iluwatar/all-contributors/add-nishant
docs: add nishant as a contributor
2020-08-01 11:46:28 +03:00
d41077f355 docs: update .all-contributorsrc [skip ci] 2020-08-01 08:45:39 +00:00
e4473e5c88 docs: update README.md [skip ci] 2020-08-01 08:45:38 +00:00
7af544998d Merge pull request #1465 from iluwatar/all-contributors/add-MananS77
docs: add MananS77 as a contributor
2020-08-01 11:08:05 +03:00
0a2c87d49a docs: update .all-contributorsrc [skip ci] 2020-08-01 08:07:21 +00:00
15eb49e574 docs: update README.md [skip ci] 2020-08-01 08:07:20 +00:00
661f9e1373 Merge pull request #1464 from iluwatar/all-contributors/add-charlesfinley
docs: add charlesfinley as a contributor
2020-08-01 10:42:44 +03:00
7908d38604 docs: update .all-contributorsrc [skip ci] 2020-08-01 07:41:48 +00:00
41020982de docs: update README.md [skip ci] 2020-08-01 07:41:47 +00:00
43569ecd66 Merge pull request #1463 from charlesfinley/master
Fixes Issue #1462 - Unit Test assertEquals parameters are reversed
2020-08-01 10:39:20 +03:00
fb6507ceda Corrected assertEquals order for expected, actual. 2020-07-31 22:52:23 -04:00
29f799c815 Corrected assertEquals order for expected, actual. 2020-07-31 22:50:48 -04:00
55bb1f11e0 #590 fix typo 2020-07-30 21:57:07 +03:00
8364b289b4 #590 explanation for Abstract Document 2020-07-30 21:39:11 +03:00
417f21ed3d Code cleanup (#1461)
* Code cleanup

* Fix flux tests

* Fix checkstyle errors

* Fix compile error
2020-07-30 20:28:47 +03:00
5381387026 docs: add xiaod-dev as a contributor (#1460)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 21:03:29 +03:00
f95aadc8f5 docs: add hbothra15 as a contributor (#1459)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* fix merge

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 20:42:45 +03:00
402b753480 docs: add webpro as a contributor (#1458)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:24:01 +03:00
6a28d09a3c docs: add zd-zero as a contributor (#1457)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:22:29 +03:00
1e38edec15 docs: add rachelcarmena as a contributor (#1456)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:21:07 +03:00
ec7a2025f0 docs: add iamrichardjones as a contributor (#1455)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:19:47 +03:00
de79019ece docs: add Jahhein as a contributor (#1454)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:18:15 +03:00
f2ac53edca docs: add Bobo1239 as a contributor (#1453)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:16:54 +03:00
c9e30390d3 docs: add vertti as a contributor (#1452)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:14:42 +03:00
f49f9a15b6 docs: add d4gg4d as a contributor (#1451)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:13:24 +03:00
f878bf63aa docs: add sivasubramanim as a contributor (#1450)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:11:51 +03:00
51ef7176b1 docs: add grzesiekkedzior as a contributor (#1449)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:08:47 +03:00
46d4155328 docs: update .all-contributorsrc [skip ci] 2020-07-29 17:08:13 +00:00
a968dce586 docs: update README.md [skip ci] 2020-07-29 17:08:12 +00:00
047285aed7 docs: add PalAditya as a contributor (#1448)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:07:30 +03:00
4db3a1cfb2 docs: add varunu28 as a contributor (#1447)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:06:01 +03:00
075fbe7433 docs: add yorlov as a contributor (#1446)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 20:04:33 +03:00
1f0a24cefa docs: add trautonen as a contributor (#1445)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-07-29 19:59:40 +03:00
69341ff712 docs: add IAmPramod as a contributor (#1443)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:53:14 +03:00
a1b2ab129e docs: add Amarnath510 as a contributor (#1442)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:51:03 +03:00
87c2644842 docs: add Anurag870 as a contributor (#1441)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:49:20 +03:00
1d025b7019 docs: add Deathnerd as a contributor (#1440)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:47:29 +03:00
34a36cb519 docs: add Harshrajsinh as a contributor (#1439)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:45:07 +03:00
62ac59afda docs: add MaVdbussche as a contributor (#1438)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:43:26 +03:00
beffc87deb docs: add alexsomai as a contributor (#1437)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:41:47 +03:00
706c5092c1 docs: add amogozov as a contributor (#1436)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:40:00 +03:00
e222a69964 docs: add anthonycampbell as a contributor (#1435)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:38:23 +03:00
9483888b5e docs: add christophercolumbusdog as a contributor (#1434)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:36:36 +03:00
73d55afd58 docs: add dzmitryh as a contributor (#1433)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:34:58 +03:00
1f900d164d docs: add jjjimenez100 as a contributor (#1432)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:33:18 +03:00
5d21a03acd docs: add kaiwinter as a contributor (#1431)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:31:35 +03:00
6c9b912620 docs: add lbroman as a contributor (#1430)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:29:55 +03:00
7fdcd2ec5a docs: add pnowy as a contributor (#1429)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:28:18 +03:00
dafe495610 docs: add prafful1 as a contributor (#1428)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:26:38 +03:00
6f0035e7c2 docs: add sankypanhale as a contributor (#1427)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:25:03 +03:00
652a68b134 docs: add staillebois as a contributor (#1426)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:23:12 +03:00
b5fac5cf86 docs: add valdar-hu as a contributor (#1425)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:21:22 +03:00
ecb7b44f97 docs: add vanogrid as a contributor (#1424)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:19:24 +03:00
1841fba831 docs: add yosfik as a contributor (#1423)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:17:45 +03:00
325f0d93b2 docs: add 7agustibm as a contributor (#1422)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:16:02 +03:00
efd8c8156e docs: add Juaanma as a contributor (#1421)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:14:26 +03:00
ae57ec75f3 docs: add LuigiCortese as a contributor (#1420)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:12:46 +03:00
47acedaaf7 docs: add Rzeposlaw as a contributor (#1419)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 19:10:44 +03:00
65d627b2ed docs: add akrystian as a contributor (#1418)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:49:46 +03:00
b4e4cf9cfe docs: add baislsl as a contributor (#1417)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:48:09 +03:00
b67a019c48 docs: add besok as a contributor (#1416)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:45:53 +03:00
1bbae5fd5a docs: add dmitraver as a contributor (#1415)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:44:29 +03:00
d11b2f06ea docs: add fanofxiaofeng as a contributor (#1414)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:42:55 +03:00
2a66fec6fe docs: add hoangnam2261 as a contributor (#1413)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:41:17 +03:00
a475df845b docs: add jarpit96 as a contributor (#1412)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:38:07 +03:00
1bc77a80f2 docs: add joningiwork as a contributor (#1411)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:36:27 +03:00
9b5ae765fc docs: add kirill-vlasov as a contributor (#1410)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:34:45 +03:00
8e268cf261 docs: add mitchellirvin as a contributor (#1409)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:32:59 +03:00
fe2f8f74a1 docs: add ranjeet-floyd as a contributor (#1408)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:29:41 +03:00
e2a42b0051 docs: add Alwayswithme as a contributor (#1407)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:28:10 +03:00
54bb02f691 docs: add MSaifAsif as a contributor (#1406)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:26:34 +03:00
a70213f852 docs: add kanwarpreet25 as a contributor (#1405)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:25:03 +03:00
19929d9e72 docs: add leonmak as a contributor (#1404)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:23:23 +03:00
09880e3850 docs: add perwramdemark as a contributor (#1403)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:21:41 +03:00
96bfb8bd9f docs: add waisuan as a contributor (#1402)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:19:53 +03:00
a727a1d05b docs: add AnaghaSasikumar as a contributor (#1401)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:18:07 +03:00
46fdc5a54f docs: add christofferh as a contributor (#1400)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:16:12 +03:00
8137609e2f docs: add dgruntz as a contributor (#1399)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:14:30 +03:00
e924c9399a docs: add hannespernpeintner as a contributor (#1398)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:12:47 +03:00
d791c78501 docs: add leogtzr as a contributor (#1397)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:11:09 +03:00
ba485e2c3e docs: add npczwh as a contributor (#1396)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:09:00 +03:00
be54dc1c7e docs: add oconnelc as a contributor (#1395)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:07:15 +03:00
ec80402fe5 docs: add giorgosmav21 as a contributor (#1394)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:05:22 +03:00
d1de465780 docs: add hbothra15 as a contributor (#1393)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:02:13 +03:00
c2fb591749 docs: add igeligel as a contributor (#1392)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 18:00:07 +03:00
c5479cc882 docs: add llorllale as a contributor (#1391)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 17:58:00 +03:00
7968615ad4 docs: add mookkiah as a contributor (#1390)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 17:55:53 +03:00
c0d7c8922e docs: add Azureyjt as a contributor (#1388)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 17:53:30 +03:00
5a23fab795 docs: add vehpsr as a contributor (#1389)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 17:50:53 +03:00
8c21809dad docs: add ThatGuyWithTheHat as a contributor (#1387)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 17:49:00 +03:00
37bffb4a99 docs: add gopinath-langote as a contributor (#1386)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä <ilkka.seppala@gofore.com>
2020-07-29 17:47:06 +03:00
9b25d302b7 Fix broken logging in service layer 2020-07-26 21:57:15 +01:00
12d392931e #1321 Added UML diagram 2020-07-27 00:39:53 +05:30
4017c37b6f #1321 Fixed a test 2020-07-26 18:34:42 +05:30
9d191324ff #1321 2020-07-26 18:17:00 +05:30
75ab3b5245 #1321 Added Tests 2020-07-26 17:38:33 +05:30
e0fb2d014a #1321 Added comments and refactored code 2020-07-26 15:56:55 +05:30
c4b1b89f1f #1321 2020-07-19 22:20:15 +05:30
52e6ea2b68 #1321
Implemented DAO
2020-07-19 20:33:52 +05:30
112973482d #1321
Added basic structure and planned out the roadmap
2020-07-19 16:51:16 +05:30
58e3fbfc6a #1321
Added gitignore
2020-07-19 16:19:01 +05:30
bf01f3e68b #1321
Added Readme file
2020-07-19 15:35:53 +05:30
58b98c54e5 #1321
Initial folder setup
2020-07-19 15:30:30 +05:30
daf53225d8 Resolves CR comments 2020-05-01 08:04:45 +00:00
d733122e7a Java 11 migraiton: mutex 2020-04-12 23:00:49 +00:00
2fa938c02d Java 11 migraiton: mute-idiom 2020-04-12 22:58:50 +00:00
9b105d770d Java 11 migraiton: multiton 2020-04-12 22:51:37 +00:00
109d33c710 Java 11 migraiton: monostate 2020-04-12 22:49:00 +00:00
a142c06048 Java 11 migraiton: monad 2020-04-12 22:45:54 +00:00
f1b27ef5c7 Java 11 migraiton: module 2020-04-12 22:38:00 +00:00
99c70af16a Java 11 migraiton: model-view-presenter 2020-04-12 22:35:33 +00:00
edcb520d08 Java 11 migraiton: model-view-controller 2020-04-12 22:30:18 +00:00
a00622c656 Java 11 migraiton: memento 2020-04-12 22:21:48 +00:00
93e5570778 Java 11 migraiton: mediator pattern 2020-04-12 22:19:11 +00:00
59e050b20b Java 11 migraiton: master-worker-pattern 2020-04-12 22:05:13 +00:00
e6c74a5fb9 Java 11 migraiton: marker 2020-04-12 21:35:48 +00:00
905 changed files with 18634 additions and 6143 deletions

File diff suppressed because it is too large Load Diff

80
.github/workflows/maven-ci.yml vendored Normal file
View File

@ -0,0 +1,80 @@
#
# 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 CI
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Checkout Code
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:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v2
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven dependencies
uses: actions/cache@v2
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 -y xvfb
# 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
env:
# These two env variables are needed for sonar analysis
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@ -24,37 +24,41 @@
# 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 PR Builder
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
types: [ opened, reopened, synchronize, labeled, unlabeled ]
jobs:
build:
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Checkout Code
uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache Maven Dependecies
uses: actions/cache@v2
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
run: sudo apt-get install -y xvfb
# 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
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 }}

8
.gitignore vendored
View File

@ -4,7 +4,8 @@ target
.classpath
.project
*.class
# Package Files #
### Package Files ###
*.jar
*.war
*.ear
@ -13,7 +14,8 @@ target
*.swp
datanucleus.log
/bin/
/bin/
/bin/
*.log
event-sourcing/Journal.json
### Checkstyle ###
.checkstyle

263
README.md
View File

@ -6,12 +6,19 @@
![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-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-32-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-151-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<br/>
Read in different language : [![CN](/assets/flags/CN.png)**CN**](/zh/README.md),[![KR](/assets/flags/KR.png)**KR**](/ko/README.md),[![FR](/assets/flags/FR.png)**FR**](/fr/README.md),[![TR](/assets/flags/TR.png)**TR**](/tr/README.md),
<br/>
# Introduction
Design patterns are the best formalized practices a programmer can use to
@ -30,7 +37,7 @@ This site showcases Java Design Patterns. The solutions have been developed by
experienced programmers and architects from the open source community. The
patterns can be browsed by their high level descriptions or by looking at their
source code. The source code examples are well commented and can be thought as
programming tutorials how to implement a specific pattern. We use the most
programming tutorials on how to implement a specific pattern. We use the most
popular battle-proven open source Java technologies.
Before you dive into the material, you should be familiar with various
@ -69,71 +76,235 @@ This project is licensed under the terms of the MIT license.
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/iluwatar"><img src="https://avatars1.githubusercontent.com/u/582346?v=4" width="100px;" alt=""/><br /><sub><b>Ilkka Seppälä</b></sub></a><br /><a href="#projectManagement-iluwatar" title="Project Management">📆</a> <a href="#maintenance-iluwatar" title="Maintenance">🚧</a> <a href="#content-iluwatar" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/amit1307"><img src="https://avatars0.githubusercontent.com/u/23420222?v=4" width="100px;" alt=""/><br /><sub><b>amit1307</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit1307" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/npathai"><img src="https://avatars2.githubusercontent.com/u/1792515?v=4" width="100px;" alt=""/><br /><sub><b>Narendra Pathai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npathai" title="Code">💻</a> <a href="#ideas-npathai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Anpathai" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/fluxw42"><img src="https://avatars1.githubusercontent.com/u/1545460?v=4" width="100px;" alt=""/><br /><sub><b>Jeroen Meulemeester</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fluxw42" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/iluwatar"><img src="https://avatars1.githubusercontent.com/u/582346?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ilkka Seppälä</b></sub></a><br /><a href="#projectManagement-iluwatar" title="Project Management">📆</a> <a href="#maintenance-iluwatar" title="Maintenance">🚧</a> <a href="#content-iluwatar" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/amit1307"><img src="https://avatars0.githubusercontent.com/u/23420222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>amit1307</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit1307" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/npathai"><img src="https://avatars2.githubusercontent.com/u/1792515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Narendra Pathai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npathai" title="Code">💻</a> <a href="#ideas-npathai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Anpathai" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/fluxw42"><img src="https://avatars1.githubusercontent.com/u/1545460?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeroen Meulemeester</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fluxw42" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="http://www.joemccarthy.co.uk"><img src="https://avatars0.githubusercontent.com/u/4526195?v=4" width="100px;" alt=""/><br /><sub><b>Joseph McCarthy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mikulucky" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/thomasoss"><img src="https://avatars1.githubusercontent.com/u/22516154?v=4" width="100px;" alt=""/><br /><sub><b>Thomas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=thomasoss" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/anuragagarwal561994"><img src="https://avatars1.githubusercontent.com/u/6075379?v=4" width="100px;" alt=""/><br /><sub><b>Anurag Agarwal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anuragagarwal561994" title="Code">💻</a></td>
<td align="center"><a href="https://markusmo3.github.io"><img src="https://avatars1.githubusercontent.com/u/3317416?v=4" width="100px;" alt=""/><br /><sub><b>Markus Moser</b></sub></a><br /><a href="#design-markusmo3" title="Design">🎨</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=markusmo3" title="Code">💻</a> <a href="#ideas-markusmo3" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="http://www.joemccarthy.co.uk"><img src="https://avatars0.githubusercontent.com/u/4526195?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joseph McCarthy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mikulucky" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/thomasoss"><img src="https://avatars1.githubusercontent.com/u/22516154?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=thomasoss" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/anuragagarwal561994"><img src="https://avatars1.githubusercontent.com/u/6075379?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anurag Agarwal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anuragagarwal561994" title="Code">💻</a></td>
<td align="center"><a href="https://markusmo3.github.io"><img src="https://avatars1.githubusercontent.com/u/3317416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Markus Moser</b></sub></a><br /><a href="#design-markusmo3" title="Design">🎨</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=markusmo3" title="Code">💻</a> <a href="#ideas-markusmo3" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
<tr>
<td align="center"><a href="https://twitter.com/i_sabiq"><img src="https://avatars1.githubusercontent.com/u/19510920?v=4" width="100px;" alt=""/><br /><sub><b>Sabiq Ihab</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=isabiq" title="Code">💻</a></td>
<td align="center"><a href="http://inbravo.github.io"><img src="https://avatars3.githubusercontent.com/u/5253764?v=4" width="100px;" alt=""/><br /><sub><b>Amit Dixit</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=inbravo" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/piyushchaudhari04"><img src="https://avatars3.githubusercontent.com/u/10268029?v=4" width="100px;" alt=""/><br /><sub><b>Piyush Kailash Chaudhari</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=piyushchaudhari04" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/joshzambales"><img src="https://avatars1.githubusercontent.com/u/8704552?v=4" width="100px;" alt=""/><br /><sub><b>joshzambales</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joshzambales" title="Code">💻</a></td>
<td align="center"><a href="https://twitter.com/i_sabiq"><img src="https://avatars1.githubusercontent.com/u/19510920?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sabiq Ihab</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=isabiq" title="Code">💻</a></td>
<td align="center"><a href="http://inbravo.github.io"><img src="https://avatars3.githubusercontent.com/u/5253764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Dixit</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=inbravo" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/piyushchaudhari04"><img src="https://avatars3.githubusercontent.com/u/10268029?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piyush Kailash Chaudhari</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=piyushchaudhari04" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/joshzambales"><img src="https://avatars1.githubusercontent.com/u/8704552?v=4?s=100" width="100px;" alt=""/><br /><sub><b>joshzambales</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joshzambales" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/Crossy147"><img src="https://avatars2.githubusercontent.com/u/7272996?v=4" width="100px;" alt=""/><br /><sub><b>Kamil Pietruszka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Crossy147" title="Code">💻</a></td>
<td align="center"><a href="http://cs.joensuu.fi/~zkhayda"><img src="https://avatars2.githubusercontent.com/u/660742?v=4" width="100px;" alt=""/><br /><sub><b>Zafar Khaydarov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Documentation">📖</a></td>
<td align="center"><a href="https://kemitix.github.io/"><img src="https://avatars1.githubusercontent.com/u/1147749?v=4" width="100px;" alt=""/><br /><sub><b>Paul Campbell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kemitix" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Argyro-Sioziou"><img src="https://avatars0.githubusercontent.com/u/22822639?v=4" width="100px;" alt=""/><br /><sub><b>Argyro Sioziou</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Argyro-Sioziou" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Crossy147"><img src="https://avatars2.githubusercontent.com/u/7272996?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kamil Pietruszka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Crossy147" title="Code">💻</a></td>
<td align="center"><a href="http://cs.joensuu.fi/~zkhayda"><img src="https://avatars2.githubusercontent.com/u/660742?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zafar Khaydarov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Documentation">📖</a></td>
<td align="center"><a href="https://kemitix.github.io/"><img src="https://avatars1.githubusercontent.com/u/1147749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Campbell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kemitix" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Argyro-Sioziou"><img src="https://avatars0.githubusercontent.com/u/22822639?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Argyro Sioziou</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Argyro-Sioziou" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/TylerMcConville"><img src="https://avatars0.githubusercontent.com/u/4946449?v=4" width="100px;" alt=""/><br /><sub><b>TylerMcConville</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=TylerMcConville" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/saksham93"><img src="https://avatars1.githubusercontent.com/u/37399540?v=4" width="100px;" alt=""/><br /><sub><b>saksham93</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=saksham93" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nikhilbarar"><img src="https://avatars2.githubusercontent.com/u/37332144?v=4" width="100px;" alt=""/><br /><sub><b>nikhilbarar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nikhilbarar" title="Code">💻</a></td>
<td align="center"><a href="http://colinbut.com"><img src="https://avatars2.githubusercontent.com/u/10725674?v=4" width="100px;" alt=""/><br /><sub><b>Colin But</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=colinbut" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/TylerMcConville"><img src="https://avatars0.githubusercontent.com/u/4946449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>TylerMcConville</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=TylerMcConville" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/saksham93"><img src="https://avatars1.githubusercontent.com/u/37399540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>saksham93</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=saksham93" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nikhilbarar"><img src="https://avatars2.githubusercontent.com/u/37332144?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nikhilbarar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nikhilbarar" title="Code">💻</a></td>
<td align="center"><a href="http://colinbut.com"><img src="https://avatars2.githubusercontent.com/u/10725674?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Colin But</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=colinbut" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ruslanpa"><img src="https://avatars2.githubusercontent.com/u/1503411?v=4" width="100px;" alt=""/><br /><sub><b>Ruslan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruslanpa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4" width="100px;" alt=""/><br /><sub><b>Juho Kang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JuhoKang" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/dheeraj-mummareddy"><img src="https://avatars2.githubusercontent.com/u/7002230?v=4" width="100px;" alt=""/><br /><sub><b>Dheeraj Mummareddy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dheeraj-mummareddy" title="Code">💻</a></td>
<td align="center"><a href="https://www.bernardosulzbach.com"><img src="https://avatars0.githubusercontent.com/u/8271090?v=4" width="100px;" alt=""/><br /><sub><b>Bernardo Sulzbach</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=bernardosulzbach" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ruslanpa"><img src="https://avatars2.githubusercontent.com/u/1503411?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ruslan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruslanpa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juho Kang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JuhoKang" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/dheeraj-mummareddy"><img src="https://avatars2.githubusercontent.com/u/7002230?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dheeraj Mummareddy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dheeraj-mummareddy" title="Code">💻</a></td>
<td align="center"><a href="https://www.bernardosulzbach.com"><img src="https://avatars0.githubusercontent.com/u/8271090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bernardo Sulzbach</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=bernardosulzbach" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/4lexis"><img src="https://avatars0.githubusercontent.com/u/19871727?v=4" width="100px;" alt=""/><br /><sub><b>Aleksandar Dudukovic</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=4lexis" title="Code">💻</a></td>
<td align="center"><a href="https://www.yusufaytas.com"><img src="https://avatars2.githubusercontent.com/u/1049483?v=4" width="100px;" alt=""/><br /><sub><b>Yusuf Aytaş</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yusufaytas" title="Code">💻</a></td>
<td align="center"><a href="http://futurehomes.hu"><img src="https://avatars2.githubusercontent.com/u/1001491?v=4" width="100px;" alt=""/><br /><sub><b>Mihály Kuprivecz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qpi" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kapinuss"><img src="https://avatars0.githubusercontent.com/u/17639945?v=4" width="100px;" alt=""/><br /><sub><b>Stanislav Kapinus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kapinuss" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/4lexis"><img src="https://avatars0.githubusercontent.com/u/19871727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandar Dudukovic</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=4lexis" title="Code">💻</a></td>
<td align="center"><a href="https://www.yusufaytas.com"><img src="https://avatars2.githubusercontent.com/u/1049483?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yusuf Aytaş</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yusufaytas" title="Code">💻</a></td>
<td align="center"><a href="http://futurehomes.hu"><img src="https://avatars2.githubusercontent.com/u/1001491?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihály Kuprivecz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qpi" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kapinuss"><img src="https://avatars0.githubusercontent.com/u/17639945?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stanislav Kapinus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kapinuss" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/gvsharma"><img src="https://avatars1.githubusercontent.com/u/6648152?v=4" width="100px;" alt=""/><br /><sub><b>GVSharma</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gvsharma" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/SrdjanPaunovic"><img src="https://avatars1.githubusercontent.com/u/22815104?v=4" width="100px;" alt=""/><br /><sub><b>Srđan Paunović</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=SrdjanPaunovic" title="Code">💻</a></td>
<td align="center"><a href="https://sideris.xyz/"><img src="https://avatars3.githubusercontent.com/u/5484694?v=4" width="100px;" alt=""/><br /><sub><b>Petros G. Sideris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sideris" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/gopinathlangote/"><img src="https://avatars2.githubusercontent.com/u/10210778?v=4" width="100px;" alt=""/><br /><sub><b>Gopinath Langote</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gopinath-langote" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/gvsharma"><img src="https://avatars1.githubusercontent.com/u/6648152?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GVSharma</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gvsharma" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/SrdjanPaunovic"><img src="https://avatars1.githubusercontent.com/u/22815104?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Srđan Paunović</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=SrdjanPaunovic" title="Code">💻</a></td>
<td align="center"><a href="https://sideris.xyz/"><img src="https://avatars3.githubusercontent.com/u/5484694?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Petros G. Sideris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sideris" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/pramodgupta3/"><img src="https://avatars1.githubusercontent.com/u/2184241?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pramod Gupta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AIAmPramod" title="Reviewed Pull Requests">👀</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/qza"><img src="https://avatars3.githubusercontent.com/u/233149?v=4" width="100px;" alt=""/><br /><sub><b>qza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qza" title="Code">💻</a></td>
<td align="center"><a href="http://tschis.github.io"><img src="https://avatars1.githubusercontent.com/u/20662669?v=4" width="100px;" alt=""/><br /><sub><b>Rodolfo Forte</b></sub></a><br /><a href="#content-Tschis" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/ankurkaushal"><img src="https://avatars2.githubusercontent.com/u/2236616?v=4" width="100px;" alt=""/><br /><sub><b>Ankur Kaushal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ankurkaushal" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/ovidijus-okinskas/"><img src="https://avatars0.githubusercontent.com/u/20372387?v=4" width="100px;" alt=""/><br /><sub><b>Ovidijus Okinskas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=okinskas" title="Code">💻</a></td>
<td align="center"><a href="https://amarnath510.github.io/portfolio"><img src="https://avatars0.githubusercontent.com/u/4599623?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amarnath Chandana</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Amarnath510" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Anurag870"><img src="https://avatars1.githubusercontent.com/u/6295975?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anurag870</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Anurag870" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=Anurag870" title="Documentation">📖</a></td>
<td align="center"><a href="http://theerroris.me"><img src="https://avatars0.githubusercontent.com/u/1685953?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wes Gilleland</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Deathnerd" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Harshrajsinh"><img src="https://avatars2.githubusercontent.com/u/22811531?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harshraj Thakor</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Harshrajsinh" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://twitter.com/StPitsios"><img src="https://avatars1.githubusercontent.com/u/6773603?v=4" width="100px;" alt=""/><br /><sub><b>Stamatis Pitsios</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pitsios-s" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/robertt240"><img src="https://avatars1.githubusercontent.com/u/9137432?v=4" width="100px;" alt=""/><br /><sub><b>Robert Kasperczyk</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=robertt240" title="Code">💻</a></td>
<td align="center"><a href="https://t.me/paul_docker"><img src="https://avatars1.githubusercontent.com/u/2404785?v=4" width="100px;" alt=""/><br /><sub><b>田浩</b></sub></a><br /><a href="#content-llitfkitfk" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/gwildor28"><img src="https://avatars0.githubusercontent.com/u/16000365?v=4" width="100px;" alt=""/><br /><sub><b>gwildor28</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gwildor28" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/MaVdbussche"><img src="https://avatars1.githubusercontent.com/u/26136934?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martin Vandenbussche</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MaVdbussche" title="Code">💻</a></td>
<td align="center"><a href="https://alexsomai.com"><img src="https://avatars1.githubusercontent.com/u/5720977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandru Somai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=alexsomai" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/amogozov"><img src="https://avatars3.githubusercontent.com/u/7372215?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artur Mogozov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amogozov" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/anthonycampbell"><img src="https://avatars3.githubusercontent.com/u/10249255?v=4?s=100" width="100px;" alt=""/><br /><sub><b>anthony</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anthonycampbell" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/amit2103"><img src="https://avatars3.githubusercontent.com/u/7566692?v=4" width="100px;" alt=""/><br /><sub><b>Amit Pandey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit2103" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/hoswey"><img src="https://avatars3.githubusercontent.com/u/3689445?v=4" width="100px;" alt=""/><br /><sub><b>Hoswey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoswey" title="Code">💻</a></td>
<td align="center"><a href="http://ccygnus.com/"><img src="https://avatars1.githubusercontent.com/u/9342724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Cygnus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christophercolumbusdog" title="Code">💻</a></td>
<td align="center"><a href="https://about.me/dzmitryh"><img src="https://avatars2.githubusercontent.com/u/5390492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dima Gubin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dzmitryh" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jjjimenez100"><img src="https://avatars3.githubusercontent.com/u/22243493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joshua Jimenez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jjjimenez100" title="Code">💻</a></td>
<td align="center"><a href="http://about.me/kaiwinter"><img src="https://avatars0.githubusercontent.com/u/110982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Winter</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kaiwinter" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/lbroman"><img src="https://avatars1.githubusercontent.com/u/86007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lbroman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=lbroman" title="Code">💻</a></td>
<td align="center"><a href="https://przemeknowak.com"><img src="https://avatars1.githubusercontent.com/u/3254609?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Przemek</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pnowy" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/prafful1"><img src="https://avatars0.githubusercontent.com/u/14350274?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Prafful Agarwal</b></sub></a><br /><a href="#content-prafful1" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/sankypanhale"><img src="https://avatars1.githubusercontent.com/u/6478783?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sanket Panhale</b></sub></a><br /><a href="#content-sankypanhale" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/staillebois"><img src="https://avatars0.githubusercontent.com/u/23701200?v=4?s=100" width="100px;" alt=""/><br /><sub><b>staillebois</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=staillebois" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/valdar-hu"><img src="https://avatars3.githubusercontent.com/u/17962817?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krisztián Nagy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=valdar-hu" title="Code">💻</a></td>
<td align="center"><a href="https://www.vanogrid.com"><img src="https://avatars0.githubusercontent.com/u/4307918?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Ivanov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vanogrid" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/yosfik"><img src="https://avatars3.githubusercontent.com/u/4850270?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yosfik Alqadri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yosfik" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/7agustibm"><img src="https://avatars0.githubusercontent.com/u/8149332?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Agustí Becerra Milà</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=7agustibm" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Juaanma"><img src="https://avatars3.githubusercontent.com/u/7390500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Suárez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Juaanma" title="Code">💻</a></td>
<td align="center"><a href="http://www.devsedge.net/"><img src="https://avatars0.githubusercontent.com/u/9956006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luigi Cortese</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=LuigiCortese" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Rzeposlaw"><img src="https://avatars2.githubusercontent.com/u/18425745?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katarzyna Rzepecka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Rzeposlaw" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="http://adamski.pro"><img src="https://avatars1.githubusercontent.com/u/6537430?v=4?s=100" width="100px;" alt=""/><br /><sub><b>adamski.pro</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=akrystian" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/baislsl"><img src="https://avatars0.githubusercontent.com/u/17060584?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shengli Bai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=baislsl" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/besok"><img src="https://avatars2.githubusercontent.com/u/29834592?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=besok" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/dmitraver"><img src="https://avatars3.githubusercontent.com/u/1798156?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Avershin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dmitraver" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/fanofxiaofeng"><img src="https://avatars0.githubusercontent.com/u/3983683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>靳阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fanofxiaofeng" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/hoangnam2261"><img src="https://avatars2.githubusercontent.com/u/31692990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hoangnam2261</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoangnam2261" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jarpit96"><img src="https://avatars2.githubusercontent.com/u/10098713?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arpit Jain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jarpit96" title="Code">💻</a></td>
<td align="center"><a href="http://joningi.net"><img src="https://avatars2.githubusercontent.com/u/6115148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jón Ingi Sveinbjörnsson</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joningiwork" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/kirill-vlasov"><img src="https://avatars3.githubusercontent.com/u/16112495?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kirill Vlasov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kirill-vlasov" title="Code">💻</a></td>
<td align="center"><a href="http://mitchell-irvin.com"><img src="https://avatars0.githubusercontent.com/u/16233245?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mitchell Irvin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mitchellirvin" title="Code">💻</a></td>
<td align="center"><a href="https://ranjeet-floyd.github.io"><img src="https://avatars0.githubusercontent.com/u/1992972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ranjeet</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ranjeet-floyd" title="Code">💻</a></td>
<td align="center"><a href="https://alwayswithme.github.io"><img src="https://avatars3.githubusercontent.com/u/3234786?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PhoenixYip</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Alwayswithme" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/MSaifAsif"><img src="https://avatars1.githubusercontent.com/u/6280554?v=4?s=100" width="100px;" alt=""/><br /><sub><b>M Saif Asif</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MSaifAsif" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kanwarpreet25"><img src="https://avatars0.githubusercontent.com/u/39183641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kanwarpreet25</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kanwarpreet25" title="Code">💻</a></td>
<td align="center"><a href="http://leonmak.me"><img src="https://avatars3.githubusercontent.com/u/13071508?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leon Mak</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leonmak" title="Code">💻</a></td>
<td align="center"><a href="http://www.wramdemark.se"><img src="https://avatars2.githubusercontent.com/u/7052193?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Per Wramdemark</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=perwramdemark" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/waisuan"><img src="https://avatars2.githubusercontent.com/u/10975700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evan Sia Wai Suan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=waisuan" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/AnaghaSasikumar"><img src="https://avatars2.githubusercontent.com/u/42939261?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AnaghaSasikumar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AnaghaSasikumar" title="Code">💻</a></td>
<td align="center"><a href="https://christofferh.com"><img src="https://avatars1.githubusercontent.com/u/767643?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoffer Hamberg</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christofferh" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/dgruntz"><img src="https://avatars0.githubusercontent.com/u/1516800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dominik Gruntz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dgruntz" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://bitbucket.org/hannespernpeintner/"><img src="https://avatars3.githubusercontent.com/u/1679437?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hannes</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hannespernpeintner" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/leogtzr"><img src="https://avatars0.githubusercontent.com/u/1211969?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leo Gutiérrez Ramírez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leogtzr" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/npczwh"><img src="https://avatars0.githubusercontent.com/u/14066422?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zhang WH</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npczwh" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/oconnelc"><img src="https://avatars0.githubusercontent.com/u/1112973?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christopher O'Connell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=oconnelc" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/giorgosmav21"><img src="https://avatars2.githubusercontent.com/u/22855493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Mavroeidis</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=giorgosmav21" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/hbothra15"><img src="https://avatars1.githubusercontent.com/u/7418012?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hemant Bothra</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hbothra15" title="Code">💻</a> <a href="#design-hbothra15" title="Design">🎨</a></td>
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars1.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=igeligel" title="Code">💻</a></td>
<td align="center"><a href="https://llorllale.github.io/"><img src="https://avatars1.githubusercontent.com/u/2019896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Aristy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=llorllale" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/mookkiah"><img src="https://avatars1.githubusercontent.com/u/8975264?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mahendran Mookkiah</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mookkiah" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Azureyjt"><img src="https://avatars2.githubusercontent.com/u/18476317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Azureyjt</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Azureyjt" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vehpsr"><img src="https://avatars2.githubusercontent.com/u/3133265?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vehpsr" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ThatGuyWithTheHat"><img src="https://avatars0.githubusercontent.com/u/24470582?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt</b></sub></a><br /><a href="#content-ThatGuyWithTheHat" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.linkedin.com/in/gopinathlangote/"><img src="https://avatars2.githubusercontent.com/u/10210778?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gopinath Langote</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gopinath-langote" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/hoswey"><img src="https://avatars3.githubusercontent.com/u/3689445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hoswey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoswey" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/amit2103"><img src="https://avatars3.githubusercontent.com/u/7566692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Pandey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit2103" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/gwildor28"><img src="https://avatars0.githubusercontent.com/u/16000365?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gwildor28</b></sub></a><br /><a href="#content-gwildor28" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://t.me/paul_docker"><img src="https://avatars1.githubusercontent.com/u/2404785?v=4?s=100" width="100px;" alt=""/><br /><sub><b>田浩</b></sub></a><br /><a href="#content-llitfkitfk" title="Content">🖋</a></td>
<td align="center"><a href="https://twitter.com/StPitsios"><img src="https://avatars1.githubusercontent.com/u/6773603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stamatis Pitsios</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pitsios-s" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/qza"><img src="https://avatars3.githubusercontent.com/u/233149?v=4?s=100" width="100px;" alt=""/><br /><sub><b>qza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qza" title="Code">💻</a></td>
<td align="center"><a href="http://tschis.github.io"><img src="https://avatars1.githubusercontent.com/u/20662669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodolfo Forte</b></sub></a><br /><a href="#content-Tschis" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ankurkaushal"><img src="https://avatars2.githubusercontent.com/u/2236616?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ankur Kaushal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ankurkaushal" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/ovidijus-okinskas/"><img src="https://avatars0.githubusercontent.com/u/20372387?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ovidijus Okinskas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=okinskas" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/robertt240"><img src="https://avatars1.githubusercontent.com/u/9137432?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert Kasperczyk</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=robertt240" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/trautonen"><img src="https://avatars3.githubusercontent.com/u/1641063?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tapio Rautonen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=trautonen" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="http://vk.com/yuri.orlov"><img src="https://avatars0.githubusercontent.com/u/1595733?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yuri Orlov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yorlov" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/varunu28/"><img src="https://avatars0.githubusercontent.com/u/7676016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Varun Upadhyay</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=varunu28" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/PalAditya"><img src="https://avatars2.githubusercontent.com/u/25523604?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aditya Pal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=PalAditya" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/grzesiekkedzior"><img src="https://avatars3.githubusercontent.com/u/23739158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>grzesiekkedzior</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=grzesiekkedzior" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Agrzesiekkedzior" title="Reviewed Pull Requests">👀</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/sivasubramanim"><img src="https://avatars2.githubusercontent.com/u/51107434?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sivasubramani M</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sivasubramanim" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/d4gg4d"><img src="https://avatars2.githubusercontent.com/u/99457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sami Airaksinen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=d4gg4d" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vertti"><img src="https://avatars0.githubusercontent.com/u/557751?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Janne Sinivirta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vertti" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Bobo1239"><img src="https://avatars1.githubusercontent.com/u/2302947?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris-Chengbiao Zhou</b></sub></a><br /><a href="#content-Bobo1239" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://jahhein.github.io"><img src="https://avatars2.githubusercontent.com/u/10779515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob Hein</b></sub></a><br /><a href="#content-Jahhein" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/iamrichardjones"><img src="https://avatars3.githubusercontent.com/u/14842151?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richard Jones</b></sub></a><br /><a href="#content-iamrichardjones" title="Content">🖋</a></td>
<td align="center"><a href="https://rachelcarmena.github.io"><img src="https://avatars0.githubusercontent.com/u/22792183?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rachel M. Carmena</b></sub></a><br /><a href="#content-rachelcarmena" title="Content">🖋</a></td>
<td align="center"><a href="https://zd-zero.github.io"><img src="https://avatars0.githubusercontent.com/u/21978370?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zaerald Denze Lungos</b></sub></a><br /><a href="#content-zd-zero" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://webpro.nl"><img src="https://avatars1.githubusercontent.com/u/456426?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lars Kappert</b></sub></a><br /><a href="#content-webpro" title="Content">🖋</a></td>
<td align="center"><a href="https://xiaod.info"><img src="https://avatars2.githubusercontent.com/u/21277644?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Liu</b></sub></a><br /><a href="#translation-xiaod-dev" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/nishant"><img src="https://avatars2.githubusercontent.com/u/15331971?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nishant Arora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nishant" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/raja-peeyush-kumar-singh"><img src="https://avatars0.githubusercontent.com/u/5496024?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Peeyush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=raja-peeyush-kumar-singh" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aravening" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/vINCENT8888801"><img src="https://avatars0.githubusercontent.com/u/8037883?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wei Seng</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vINCENT8888801" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.linkedin.com/in/ashish-trivedi-218379135/"><img src="https://avatars3.githubusercontent.com/u/23194128?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashish Trivedi</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ashishtrivedi16" title="Code">💻</a></td>
<td align="center"><a href="https://rayyounghong.com"><img src="https://avatars1.githubusercontent.com/u/41055099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>洪月阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=RayYH" title="Code">💻</a></td>
<td align="center"><a href="https://xdvrx1.github.io/"><img src="https://avatars0.githubusercontent.com/u/47092464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xdvrx1</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Axdvrx1" title="Reviewed Pull Requests">👀</a> <a href="#ideas-xdvrx1" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="http://subho.xyz"><img src="https://avatars0.githubusercontent.com/u/13291222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Subhrodip Mohanta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ohbus" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aohbus" title="Reviewed Pull Requests">👀</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/nahteb"><img src="https://avatars3.githubusercontent.com/u/13121570?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bethan Palmer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nahteb" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ToxicDreamz"><img src="https://avatars0.githubusercontent.com/u/45225562?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Toxic Dreamz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ToxicDreamz" title="Code">💻</a></td>
<td align="center"><a href="http://www.edycutjong.com"><img src="https://avatars1.githubusercontent.com/u/1098102?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Edy Cu Tjong</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=edycutjong" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mkrzywanski"><img src="https://avatars0.githubusercontent.com/u/15279585?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michał Krzywański</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mkrzywanski" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.stefan-birkner.de"><img src="https://avatars1.githubusercontent.com/u/711349?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Birkner</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=stefanbirkner" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/fedorskvorcov"><img src="https://avatars3.githubusercontent.com/u/43882212?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fedor Skvorcov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fedorskvorcov" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/samilAyoub"><img src="https://avatars0.githubusercontent.com/u/61546990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>samilAyoub</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samilAyoub" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vdlald"><img src="https://avatars0.githubusercontent.com/u/29997701?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Golubinov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vdlald" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/swarajsaaj"><img src="https://avatars2.githubusercontent.com/u/6285049?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Swaraj</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=swarajsaaj" title="Code">💻</a></td>
<td align="center"><a href="http://christophflick.de"><img src="https://avatars0.githubusercontent.com/u/4465376?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoph Flick</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ChFlick" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Ascenio"><img src="https://avatars1.githubusercontent.com/u/7662016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ascênio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AAscenio" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://www.linkedin.com/in/domenico-sibilio/"><img src="https://avatars2.githubusercontent.com/u/24280982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Domenico Sibilio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dsibilio" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/akashchandwani"><img src="https://avatars2.githubusercontent.com/u/3483277?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akash Chandwani</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aakashchandwani" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="http://www.linkedin.com/in/manannikov"><img src="https://avatars2.githubusercontent.com/u/7019769?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pavlo Manannikov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=manannikov" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/eimanip"><img src="https://avatars0.githubusercontent.com/u/20307301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eiman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eimanip" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/OrangePants-R"><img src="https://avatars0.githubusercontent.com/u/42976136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rocky</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=OrangePants-R" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://ibrahimalii.github.io/"><img src="https://avatars2.githubusercontent.com/u/21141301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ibrahim ali abdelghany</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AibrahimAlii" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/gkulkarni2020"><img src="https://avatars3.githubusercontent.com/u/5161548?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Girish Kulkarni</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gkulkarni2020" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/omk13"><img src="https://avatars0.githubusercontent.com/u/59054172?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Omar Karazoun</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=omk13" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jeff303"><img src="https://avatars0.githubusercontent.com/u/3521562?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeff Evans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jeff303" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://viveksb007.github.io"><img src="https://avatars1.githubusercontent.com/u/12713808?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vivek Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=viveksb007" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/siavashsoleymani"><img src="https://avatars2.githubusercontent.com/u/18074419?v=4?s=100" width="100px;" alt=""/><br /><sub><b>siavash</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=siavashsoleymani" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ruchpeanuts"><img src="https://avatars0.githubusercontent.com/u/29301900?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ruchpeanuts</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruchpeanuts" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/warp125"><img src="https://avatars1.githubusercontent.com/u/48073115?v=4?s=100" width="100px;" alt=""/><br /><sub><b>warp125</b></sub></a><br /><a href="#translation-warp125" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="http://libkhadir.fr"><img src="https://avatars1.githubusercontent.com/u/45130488?v=4?s=100" width="100px;" alt=""/><br /><sub><b>KHADIR Tayeb</b></sub></a><br /><a href="#translation-tkhadir" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/ignite1771"><img src="https://avatars2.githubusercontent.com/u/59446563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ignite1771</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ignite1771" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/demirhalil"><img src="https://avatars1.githubusercontent.com/u/22895118?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Halil Demir</b></sub></a><br /><a href="#translation-demirhalil" title="Translation">🌍</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

View File

@ -9,21 +9,182 @@ tags:
---
## Intent
Achieve flexibility of untyped languages and keep the type-safety
Use dynamic properties and achieve flexibility of untyped languages while keeping type-safety.
## Explanation
The Abstract Document pattern enables handling additional, non-static properties. This pattern
uses concept of traits to enable type safety and separate properties of different classes into
set of interfaces.
Real world example
> Consider a car that consists of multiple parts. However we don't know if the specific car really has all the parts, or just some of them. Our cars are dynamic and extremely flexible.
In plain words
> Abstract Document pattern allows attaching properties to objects without them knowing about it.
Wikipedia says
> An object-oriented structural design pattern for organizing objects in loosely typed key-value stores and exposing
the data using typed views. The purpose of the pattern is to achieve a high degree of flexibility between components
in a strongly typed language where new properties can be added to the object-tree on the fly, without losing the
support of type-safety. The pattern makes use of traits to separate different properties of a class into different
interfaces.
**Programmatic Example**
Let's first define the base classes `Document` and `AbstractDocument`. They basically make the object hold a property
map and any amount of child objects.
```java
public interface Document {
Void put(String key, Object value);
Object get(String key);
<T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
}
public abstract class AbstractDocument implements Document {
private final Map<String, Object> properties;
protected AbstractDocument(Map<String, Object> properties) {
Objects.requireNonNull(properties, "properties map is required");
this.properties = properties;
}
@Override
public Void put(String key, Object value) {
properties.put(key, value);
return null;
}
@Override
public Object get(String key) {
return properties.get(key);
}
@Override
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
return Stream.ofNullable(get(key))
.filter(Objects::nonNull)
.map(el -> (List<Map<String, Object>>) el)
.findAny()
.stream()
.flatMap(Collection::stream)
.map(constructor);
}
...
}
```
Next we define an enum `Property` and a set of interfaces for type, price, model and parts. This allows us to create
static looking interface to our `Car` class.
```java
public enum Property {
PARTS, TYPE, PRICE, MODEL
}
public interface HasType extends Document {
default Optional<String> getType() {
return Optional.ofNullable((String) get(Property.TYPE.toString()));
}
}
public interface HasPrice extends Document {
default Optional<Number> getPrice() {
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
}
}
public interface HasModel extends Document {
default Optional<String> getModel() {
return Optional.ofNullable((String) get(Property.MODEL.toString()));
}
}
public interface HasParts extends Document {
default Stream<Part> getParts() {
return children(Property.PARTS.toString(), Part::new);
}
}
```
Now we are ready to introduce the `Car`.
```java
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
public Car(Map<String, Object> properties) {
super(properties);
}
}
```
And finally here's how we construct and use the `Car` in a full example.
```java
LOGGER.info("Constructing parts and car");
var wheelProperties = Map.of(
Property.TYPE.toString(), "wheel",
Property.MODEL.toString(), "15C",
Property.PRICE.toString(), 100L);
var doorProperties = Map.of(
Property.TYPE.toString(), "door",
Property.MODEL.toString(), "Lambo",
Property.PRICE.toString(), 300L);
var carProperties = Map.of(
Property.MODEL.toString(), "300SL",
Property.PRICE.toString(), 10000L,
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
var car = new Car(carProperties);
LOGGER.info("Here is our car:");
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
LOGGER.info("-> parts: ");
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
p.getType().orElse(null),
p.getModel().orElse(null),
p.getPrice().orElse(null))
);
// Constructing parts and car
// Here is our car:
// model: 300SL
// price: 10000
// parts:
// wheel/15C/100
// door/Lambo/300
```
## Class diagram
![alt text](./etc/abstract-document.png "Abstract Document Traits and Domain")
## Applicability
Use the Abstract Document Pattern when
* there is a need to add new properties on the fly
* you want a flexible way to organize domain in tree like structure
* you want more loosely coupled system
* There is a need to add new properties on the fly
* You want a flexible way to organize domain in tree like structure
* You want more loosely coupled system
## Credits
* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://www.amazon.com/gp/product/0470059028/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0470059028&linkId=e3aacaea7017258acf184f9f3283b492)

View File

@ -21,7 +21,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>abstract-document</artifactId>
<dependencies>

View File

@ -43,9 +43,11 @@ public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Executes the App.
* Program entry point.
*
* @param args command line args
*/
public App() {
public static void main(String[] args) {
LOGGER.info("Constructing parts and car");
var wheelProperties = Map.of(
@ -75,14 +77,4 @@ public class App {
p.getPrice().orElse(null))
);
}
/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {
new App();
}
}

View File

@ -32,7 +32,6 @@ import java.util.stream.Stream;
*/
public interface HasParts extends Document {
default Stream<Part> getParts() {
return children(Property.PARTS.toString(), Part::new);
}

View File

@ -32,7 +32,6 @@ import java.util.Optional;
*/
public interface HasPrice extends Document {
default Optional<Number> getPrice() {
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
}

View File

@ -32,7 +32,6 @@ import java.util.Optional;
*/
public interface HasType extends Document {
default Optional<String> getType() {
return Optional.ofNullable((String) get(Property.TYPE.toString()));
}

View File

@ -40,14 +40,14 @@ public class AbstractDocumentTest {
private static final String KEY = "key";
private static final String VALUE = "value";
private class DocumentImplementation extends AbstractDocument {
private static class DocumentImplementation extends AbstractDocument {
DocumentImplementation(Map<String, Object> properties) {
super(properties);
}
}
private DocumentImplementation document = new DocumentImplementation(new HashMap<>());
private final DocumentImplementation document = new DocumentImplementation(new HashMap<>());
@Test
public void shouldPutAndGetValue() {

View File

@ -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));
}
}

View File

@ -9,16 +9,19 @@ tags:
---
## Also known as
Kit
## Intent
Provide an interface for creating families of related or dependent
objects without specifying their concrete classes.
## Explanation
Real world example
> To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
> To create a kingdom we need objects with a common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
In plain words
@ -30,15 +33,18 @@ Wikipedia says
**Programmatic Example**
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the kingdom
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the
kingdom.
```java
public interface Castle {
String getDescription();
}
public interface King {
String getDescription();
}
public interface Army {
String getDescription();
}
@ -66,7 +72,7 @@ public class ElfArmy implements Army {
}
}
// Orcish implementations similarly...
// Orcish implementations similarly -> ...
```
@ -112,9 +118,17 @@ var castle = factory.createCastle();
var king = factory.createKing();
var army = factory.createArmy();
castle.getDescription(); // Output: This is the Elven castle!
king.getDescription(); // Output: This is the Elven king!
army.getDescription(); // Output: This is the Elven Army!
castle.getDescription();
king.getDescription();
army.getDescription();
```
Program output:
```java
This is the Elven castle!
This is the Elven king!
This is the Elven Army!
```
Now, we can design a factory for our different kingdom factories. In this example, we created FactoryMaker, responsible for returning an instance of either ElfKingdomFactory or OrcKingdomFactory.
@ -156,46 +170,52 @@ public static void main(String[] args) {
```
## Class diagram
![alt text](./etc/abstract-factory.urm.png "Abstract Factory class diagram")
## Applicability
Use the Abstract Factory pattern when
* a system should be independent of how its products are created, composed and represented
* a system should be configured with one of multiple families of products
* a family of related product objects is designed to be used together, and you need to enforce this constraint
* you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
* the lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
* you need a run-time value to construct a particular dependency
* you want to decide which product to call from a family at runtime.
* you need to supply one or more parameters only known at run-time before you can resolve a dependency.
* when you need consistency among products
* you dont want to change existing code when adding new products or families of products to the program.
* The system should be independent of how its products are created, composed and represented
* The system should be configured with one of multiple families of products
* The family of related product objects is designed to be used together, and you need to enforce this constraint
* You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
* You need a run-time value to construct a particular dependency
* You want to decide which product to call from a family at runtime.
* You need to supply one or more parameters only known at run-time before you can resolve a dependency.
* When you need consistency among products
* You dont want to change existing code when adding new products or families of products to the program.
## Use Cases:
Example use cases
* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
* Unit test case writing becomes much easier
* Selecting to call to the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
* Unit test case writing becomes much easier
* UI tools for different OS
## Consequences:
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
* While the pattern is great when creating predefined objects, adding the new ones might be challenging.
* The code may become more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
* The code becomes more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
## Tutorial
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
## Real world examples
## Known uses
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
## Related patterns
[Factory Method](https://java-design-patterns.com/patterns/factory-method/)
[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)

View File

@ -22,7 +22,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>abstract-factory</artifactId>
<dependencies>

View File

@ -23,7 +23,6 @@
package com.iluwatar.abstractfactory;
import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -41,84 +40,14 @@ import org.slf4j.LoggerFactory;
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
* both concrete implementations to create a king, a castle and an army.
*/
public class App {
public class App implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
private static Logger log = LoggerFactory.getLogger(App.class);
private King king;
private Castle castle;
private Army army;
private final Kingdom kingdom = new Kingdom();
/**
* Creates kingdom.
*/
public void createKingdom(final KingdomFactory factory) {
setKing(factory.createKing());
setCastle(factory.createCastle());
setArmy(factory.createArmy());
}
King getKing(final KingdomFactory factory) {
return factory.createKing();
}
public King getKing() {
return king;
}
private void setKing(final King king) {
this.king = king;
}
Castle getCastle(final KingdomFactory factory) {
return factory.createCastle();
}
public Castle getCastle() {
return castle;
}
private void setCastle(final Castle castle) {
this.castle = castle;
}
Army getArmy(final KingdomFactory factory) {
return factory.createArmy();
}
public Army getArmy() {
return army;
}
private void setArmy(final Army army) {
this.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.");
}
}
public Kingdom getKingdom() {
return kingdom;
}
/**
@ -127,19 +56,33 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
var app = new App();
app.run();
}
LOGGER.info("Elf Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
@Override
public void run() {
log.info("Elf Kingdom");
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
log.info(kingdom.getArmy().getDescription());
log.info(kingdom.getCastle().getDescription());
log.info(kingdom.getKing().getDescription());
LOGGER.info("Orc Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
log.info("Orc Kingdom");
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
log.info(kingdom.getArmy().getDescription());
log.info(kingdom.getCastle().getDescription());
log.info(kingdom.getKing().getDescription());
}
/**
* Creates kingdom.
* @param kingdomType type of Kingdom
*/
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());
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.abstractfactory;
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.
*/
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.");
}
}
}
}

View File

@ -23,65 +23,71 @@
package com.iluwatar.abstractfactory;
import org.junit.jupiter.api.Test;
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 org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* Test for abstract factory.
*/
public class AbstractFactoryTest {
private App app = new App();
private KingdomFactory elfFactory;
private KingdomFactory orcFactory;
@BeforeEach
public void setUp() {
elfFactory = FactoryMaker.makeFactory(KingdomType.ELF);
orcFactory = FactoryMaker.makeFactory(KingdomType.ORC);
}
private final App app = new App();
@Test
public void king() {
final var elfKing = app.getKing(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());
final var orcKing = app.getKing(orcFactory);
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
final var orcKing = kingdom.getKing();
assertTrue(orcKing instanceof OrcKing);
assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription());
}
@Test
public void castle() {
final var elfCastle = app.getCastle(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());
final var orcCastle = app.getCastle(orcFactory);
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
final var orcCastle = kingdom.getCastle();
assertTrue(orcCastle instanceof OrcCastle);
assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription());
}
@Test
public void army() {
final var elfArmy = app.getArmy(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());
final var orcArmy = app.getArmy(orcFactory);
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
final var orcArmy = kingdom.getArmy();
assertTrue(orcArmy instanceof OrcArmy);
assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription());
}
@Test
public void createElfKingdom() {
app.createKingdom(elfFactory);
final var king = app.getKing();
final var castle = app.getCastle();
final var army = app.getArmy();
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
final var kingdom = app.getKingdom();
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);
@ -92,10 +98,12 @@ 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();
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
final var kingdom = app.getKingdom();
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);

View File

@ -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[]{}));
}
}

View File

@ -9,12 +9,126 @@ tags:
---
## Intent
Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating the troublesome dependency cycles that are inherent to the GOF VISITOR Pattern.
Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating
the troublesome dependency cycles that are inherent to the GoF Visitor Pattern.
## Explanation
Real world example
> We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based
> on filtering criteria (is it Unix or DOS compatible modem).
In plain words
> Acyclic Visitor allows functions to be added to existing class hierarchies without modifying the hierarchies.
[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) says
> The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies without affecting those
> hierarchies, and without creating the dependency cycles that are inherent to the GangOfFour VisitorPattern.
**Programmatic Example**
Here's the `Modem` hierarchy.
```java
public abstract class Modem {
public abstract void accept(ModemVisitor modemVisitor);
}
public class Zoom extends Modem {
...
@Override
public void accept(ModemVisitor modemVisitor) {
if (modemVisitor instanceof ZoomVisitor) {
((ZoomVisitor) modemVisitor).visit(this);
} else {
LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem");
}
}
}
public class Hayes extends Modem {
...
@Override
public void accept(ModemVisitor modemVisitor) {
if (modemVisitor instanceof HayesVisitor) {
((HayesVisitor) modemVisitor).visit(this);
} else {
LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem");
}
}
}
```
Next we introduce the `ModemVisitor` hierarchy.
```java
public interface ModemVisitor {
}
public interface HayesVisitor extends ModemVisitor {
void visit(Hayes hayes);
}
public interface ZoomVisitor extends ModemVisitor {
void visit(Zoom zoom);
}
public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
}
public class ConfigureForDosVisitor implements AllModemVisitor {
...
@Override
public void visit(Hayes hayes) {
LOGGER.info(hayes + " used with Dos configurator.");
}
@Override
public void visit(Zoom zoom) {
LOGGER.info(zoom + " used with Dos configurator.");
}
}
public class ConfigureForUnixVisitor implements ZoomVisitor {
...
@Override
public void visit(Zoom zoom) {
LOGGER.info(zoom + " used with Unix configurator.");
}
}
```
Finally, here are the visitors in action.
```java
var conUnix = new ConfigureForUnixVisitor();
var conDos = new ConfigureForDosVisitor();
var zoom = new Zoom();
var hayes = new Hayes();
hayes.accept(conDos);
zoom.accept(conDos);
hayes.accept(conUnix);
zoom.accept(conUnix);
```
Program output:
```
// Hayes modem used with Dos configurator.
// Zoom modem used with Dos configurator.
// Only HayesVisitor is allowed to visit Hayes modem
// Zoom modem used with Unix configurator.
```
## Class diagram
![alt text](./etc/acyclic-visitor.png "Acyclic Visitor")
## Applicability
This pattern can be used:
* When you need to add a new function to an existing hierarchy without the need to alter or affect that hierarchy.
@ -24,6 +138,7 @@ This pattern can be used:
* When the recompilation, relinking, retesting or redistribution of the derivatives of Element is very expensive.
## Consequences
The good:
* No dependency cycles between class hierarchies.
@ -32,11 +147,14 @@ The good:
The bad:
* Violates the principle of least surprise or Liskov's Substitution principle by showing that it can accept all visitors but actually only being interested in particular visitors.
* Violates [Liskov's Substitution Principle](https://java-design-patterns.com/principles/#liskov-substitution-principle) by showing that it can accept all visitors but actually only being interested in particular visitors.
* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy.
## Related patterns
* [Visitor Pattern](../visitor/)
* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/)
## Credits
* [Acyclic Visitor](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor)

View File

@ -1,115 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
<interface id="1" language="java" name="com.iluwatar.acyclicvisitor.ModemVisitor" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="860" y="67"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="2" language="java" name="com.iluwatar.acyclicvisitor.Modem" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="327" y="77"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="124" width="196" x="647" y="225"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="com.iluwatar.acyclicvisitor.Zoom" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="203" y="305"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="5" language="java" name="com.iluwatar.acyclicvisitor.HayesVisitor" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="1019" y="468"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<interface id="6" language="java" name="com.iluwatar.acyclicvisitor.ZoomVisitor" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="758" y="467"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="7" language="java" name="com.iluwatar.acyclicvisitor.Hayes" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="479" y="307"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="8" language="java" name="com.iluwatar.acyclicvisitor.ConfigureForDosVisitor" project="acyclic-visitor"
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="142" width="192" x="883" y="225"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<generalization id="9">
<end type="SOURCE" refId="7"/>
<end type="TARGET" refId="2"/>
</generalization>
<realization id="10">
<end type="SOURCE" refId="8"/>
<end type="TARGET" refId="6"/>
</realization>
<realization id="11">
<end type="SOURCE" refId="8"/>
<end type="TARGET" refId="5"/>
</realization>
<realization id="12">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="6"/>
</realization>
<realization id="13">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="1"/>
</realization>
<realization id="14">
<end type="SOURCE" refId="8"/>
<end type="TARGET" refId="1"/>
</realization>
<generalization id="15">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="2"/>
</generalization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -21,7 +21,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>acyclic-visitor</artifactId>

View File

@ -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[]{}));
}
}

View File

@ -37,7 +37,7 @@ import uk.org.lidalia.slf4jtest.TestLoggerFactory;
*/
public class ConfigureForDosVisitorTest {
private TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
private final TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
@Test
public void testVisitForZoom() {

View File

@ -12,9 +12,8 @@ tags:
Wrapper
## Intent
Convert the interface of a class into another interface the clients
expect. Adapter lets classes work together that couldn't otherwise because of
incompatible interfaces.
Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that
couldn't otherwise because of incompatible interfaces.
## Explanation
@ -56,7 +55,7 @@ And captain expects an implementation of `RowingBoat` interface to be able to mo
```java
public class Captain {
private RowingBoat rowingBoat;
private final RowingBoat rowingBoat;
// default constructor and setter for rowingBoat
public Captain(RowingBoat rowingBoat) {
this.rowingBoat = rowingBoat;
@ -75,7 +74,7 @@ public class FishingBoatAdapter implements RowingBoat {
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
private FishingBoat boat;
private final FishingBoat boat;
public FishingBoatAdapter() {
boat = new FishingBoat();

View File

@ -22,7 +22,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>adapter</artifactId>
<dependencies>

View File

@ -29,7 +29,7 @@ package com.iluwatar.adapter;
*/
public class FishingBoatAdapter implements RowingBoat {
private FishingBoat boat;
private final FishingBoat boat;
public FishingBoatAdapter() {
boat = new FishingBoat();

View File

@ -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[]{}));
}
}

View File

@ -6,20 +6,97 @@ permalink: /patterns/aggregator-microservices/
categories: Architectural
tags:
- Cloud distributed
- Decoupling
- Microservices
---
## Intent
The user makes a single call to the Aggregator, and the aggregator then calls each relevant microservice and collects
the data, apply business logic to it, and further publish is as a REST Endpoint.
More variations of the aggregator are:
- Proxy Microservice Design Pattern: A different microservice is called upon the business need.
- Chained Microservice Design Pattern: In this case each microservice is dependent/ chained to a series
of other microservices.
The user makes a single call to the aggregator service, and the aggregator then calls each relevant microservice.
## Explanation
Real world example
> Our web marketplace needs information about products and their current inventory. It makes a call to an aggregator
> service which in turn calls the product information microservice and product inventory microservice returning the
> combined information.
In plain words
> Aggregator Microservice collects pieces of data from various microservices and returns an aggregate for processing.
Stack Overflow says
> Aggregator Microservice invokes multiple services to achieve the functionality required by the application.
**Programmatic Example**
Let's start from the data model. Here's our `Product`.
```java
public class Product {
private String title;
private int productInventories;
// getters and setters ->
...
}
```
Next we can introduce our `Aggregator` microservice. It contains clients `ProductInformationClient` and
`ProductInventoryClient` for calling respective microservices.
```java
@RestController
public class Aggregator {
@Resource
private ProductInformationClient informationClient;
@Resource
private ProductInventoryClient inventoryClient;
@RequestMapping(path = "/product", method = RequestMethod.GET)
public Product getProduct() {
var product = new Product();
var productTitle = informationClient.getProductTitle();
var productInventory = inventoryClient.getProductInventories();
//Fallback to error message
product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed"));
//Fallback to default error inventory
product.setProductInventories(requireNonNullElse(productInventory, -1));
return product;
}
}
```
Here's the essence of information microservice implementation. Inventory microservice is similar, it just returns
inventory counts.
```java
@RestController
public class InformationController {
@RequestMapping(value = "/information", method = RequestMethod.GET)
public String getProductTitle() {
return "The Product Title.";
}
}
```
Now calling our `Aggregator` REST API returns the product information.
```bash
curl http://localhost:50004/product
{"title":"The Product Title.","productInventories":5}
```
## Class diagram
![alt text](./etc/aggregator-microservice.png "Aggregator Microservice")
![alt text](./aggregator-service/etc/aggregator-service.png "Aggregator Microservice")
## Applicability
@ -28,3 +105,5 @@ Use the Aggregator Microservices pattern when you need a unified API for various
## Credits
* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/)
* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60)
* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4)

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -20,7 +20,7 @@
<parent>
<artifactId>aggregator-microservices</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>aggregator-service</artifactId>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View File

@ -20,7 +20,7 @@
<parent>
<artifactId>aggregator-microservices</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -20,7 +20,7 @@
<parent>
<artifactId>aggregator-microservices</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>inventory-microservice</artifactId>

View File

@ -29,7 +29,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>aggregator-microservices</artifactId>

View File

@ -10,28 +10,37 @@ tags:
---
## Intent
Provide a helper service instance on a client and offload common functionality away from a shared resource.
## Explanation
Real world example
> A remote service has many clients accessing a function it provides. The service is a legacy application and is impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request frequency should be implemented along with latency checks and client-side logging.
> A remote service has many clients accessing a function it provides. The service is a legacy application and is
> impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request
> frequency should be implemented along with latency checks and client-side logging.
In plain words
> Using the ambassador pattern, we can implement less-frequent polling from clients along with latency checks and logging.
> With the Ambassador pattern, we can implement less-frequent polling from clients along with latency checks and
> logging.
Microsoft documentation states
> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
> An ambassador service can be thought of as an out-of-process proxy which is co-located with the client. This pattern
> can be useful for offloading common client connectivity tasks such as monitoring, logging, routing,
> security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications,
> or other applications that are difficult to modify, in order to extend their networking capabilities. It can also
> enable a specialized team to implement those features.
**Programmatic Example**
With the above example in mind we will imitate the functionality in a simple manner. We have an interface implemented by the remote service as well as the ambassador service:
With the above introduction in mind we will imitate the functionality in this example. We have an interface implemented
by the remote service as well as the ambassador service:
```java
interface RemoteServiceInterface {
long doRemoteFunction(int value) throws Exception;
}
```
@ -136,7 +145,7 @@ public class Client {
}
```
And here are two clients using the service.
Here are two clients using the service.
```java
public class App {
@ -149,13 +158,29 @@ public class App {
}
```
Here's the output for running the example:
```java
Time taken (ms): 111
Service result: 120
Time taken (ms): 931
Failed to reach remote: (1)
Time taken (ms): 665
Failed to reach remote: (2)
Time taken (ms): 538
Failed to reach remote: (3)
Service result: -1
```
## Class diagram
![alt text](./etc/ambassador.urm.png "Ambassador class diagram")
## Applicability
Ambassador is applicable when working with a legacy remote service that cannot
be modified or would be extremely difficult to modify. Connectivity features can
be implemented on the client avoiding the need for changes on the remote service.
Ambassador is applicable when working with a legacy remote service which cannot be modified or would be extremely
difficult to modify. Connectivity features can be implemented on the client avoiding the need for changes on the remote
service.
* Ambassador provides a local interface for a remote service.
* Ambassador provides logging, circuit breaking, retries and security on the client.
@ -168,10 +193,14 @@ be implemented on the client avoiding the need for changes on the remote service
* Offload remote service tasks
* Facilitate network connection
## Real world examples
## Known uses
* [Kubernetes-native API gateway for microservices](https://github.com/datawire/ambassador)
## Related patterns
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
## Credits
* [Ambassador pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador)

View File

@ -20,7 +20,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ambassador</artifactId>

View File

@ -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,7 @@ 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();
}
}

View File

@ -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) throws Exception;
long doRemoteFunction(int value);
}

View File

@ -21,39 +21,28 @@
* THE SOFTWARE.
*/
package com.iluwatar.command;
package com.iluwatar.ambassador;
/**
* ShrinkSpell is a concrete command.
* Holds information regarding the status of the Remote Service.
*
* <p> 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. </p>
*/
public class ShrinkSpell extends Command {
private Size oldSize;
private Target target;
public enum RemoteServiceStatus {
FAILURE(-1)
;
@Override
public void execute(Target target) {
oldSize = target.getSize();
target.setSize(Size.SMALL);
this.target = target;
private final long remoteServiceStatusValue;
RemoteServiceStatus(long remoteServiceStatusValue) {
this.remoteServiceStatusValue = remoteServiceStatusValue;
}
@Override
public void undo() {
if (oldSize != null && target != null) {
var temp = target.getSize();
target.setSize(oldSize);
oldSize = temp;
}
}
@Override
public void redo() {
undo();
}
@Override
public String toString() {
return "Shrink spell";
public long getRemoteServiceStatusValue() {
return remoteServiceStatusValue;
}
}

View File

@ -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 {

View File

@ -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[]{}));
}
}

View File

@ -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());
}
}

View File

@ -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
@ -48,7 +48,7 @@ class RemoteServiceTest {
}
private static class StaticRandomProvider implements RandomProvider {
private double value;
private final double value;
StaticRandomProvider(double value) {
this.value = value;

View File

@ -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());
}
}

View File

@ -12,49 +12,53 @@ tags:
## Intent
Aggregate calls to microservices in a single location: the API Gateway. The user makes a single call to the API Gateway,
and the API Gateway then calls each relevant microservice.
Aggregate calls to microservices in a single location, the API Gateway. The user makes a single call
to the API Gateway, and the API Gateway then calls each relevant microservice.
## Explanation
With the Microservices pattern, a client may need data from multiple different microservices. If the client called each
microservice directly, that could contribute to longer load times, since the client would have to make a network request
for each microservice called. Moreover, having the client call each microservice directly ties the client to that
microservice - if the internal implementations of the microservices change (for example, if two microservices are
combined sometime in the future) or if the location (host and port) of a microservice changes, then every client that
With the Microservices pattern, a client may need data from multiple different microservices. If the
client called each microservice directly, that could contribute to longer load times, since the
client would have to make a network request for each microservice called. Moreover, having the
client call each microservice directly ties the client to that microservice - if the internal
implementations of the microservices change (for example, if two microservices are combined sometime
in the future) or if the location (host and port) of a microservice changes, then every client that
makes use of those microservices must be updated.
The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway pattern, an additional
entity (the API Gateway) is placed between the client and the microservices. The job of the API Gateway is to aggregate
the calls to the microservices. Rather than the client calling each microservice individually, the client calls the
API Gateway a single time. The API Gateway then calls each of the microservices that the client needs.
The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway
pattern, an additional entity (the API Gateway) is placed between the client and the microservices.
The job of the API Gateway is to aggregate the calls to the microservices. Rather than the client
calling each microservice individually, the client calls the API Gateway a single time. The API
Gateway then calls each of the microservices that the client needs.
Real world example
> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system the API Gateway makes
calls to the Image and Price microservices.
> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system
> the API Gateway makes calls to the Image and Price microservices.
In plain words
> For a system implemented using microservices architecture, API Gateway is the single entry point that aggregates the
calls to the individual microservices.
> For a system implemented using microservices architecture, API Gateway is the single entry point
> that aggregates the calls to the individual microservices.
Wikipedia says
> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling and security
policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often
includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also
provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to
support authentication, authorization, security, audit and regulatory compliance.
> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling
> and security policies, passes requests to the back-end service and then passes the response back
> to the requester. A gateway often includes a transformation engine to orchestrate and modify the
> requests and responses on the fly. A gateway can also provide functionality such as collecting
> analytics data and providing caching. The gateway can provide functionality to support
> authentication, authorization, security, audit and regulatory compliance.
**Programmatic Example**
This implementation shows what the API Gateway pattern could look like for an e-commerce site. The `ApiGateway` makes
calls to the Image and Price microservices using the `ImageClientImpl` and `PriceClientImpl` respectively. Customers
viewing the site on a desktop device can see both price information and an image of a product, so the `ApiGateway` calls
both of the microservices and aggregates the data in the `DesktopProduct` model. However, mobile users only see price
information; they do not see a product image. For mobile users, the `ApiGateway` only retrieves price information, which
it uses to populate the `MobileProduct`.
This implementation shows what the API Gateway pattern could look like for an e-commerce site. The
`ApiGateway` makes calls to the Image and Price microservices using the `ImageClientImpl` and
`PriceClientImpl` respectively. Customers viewing the site on a desktop device can see both price
information and an image of a product, so the `ApiGateway` calls both of the microservices and
aggregates the data in the `DesktopProduct` model. However, mobile users only see price information;
they do not see a product image. For mobile users, the `ApiGateway` only retrieves price
information, which it uses to populate the `MobileProduct`.
Here's the Image microservice implementation.
@ -64,7 +68,6 @@ public interface ImageClient {
}
public class ImageClientImpl implements ImageClient {
@Override
public String getImagePath() {
var httpClient = HttpClient.newHttpClient();
@ -114,7 +117,7 @@ public class PriceClientImpl implements PriceClient {
}
```
And here we can see how API Gateway maps the requests to the microservices.
Here we can see how API Gateway maps the requests to the microservices.
```java
public class ApiGateway {

View File

@ -29,7 +29,7 @@
<parent>
<artifactId>api-gateway</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway-service</artifactId>

View File

@ -23,11 +23,16 @@
package com.iluwatar.api.gateway;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
/**
@ -35,6 +40,8 @@ import org.springframework.stereotype.Component;
*/
@Component
public class ImageClientImpl implements ImageClient {
private static final Logger LOGGER = getLogger(ImageClientImpl.class);
/**
* Makes a simple HTTP Get request to the Image microservice.
*
@ -49,12 +56,26 @@ public class ImageClientImpl implements ImageClient {
.build();
try {
LOGGER.info("Sending request to fetch image path");
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
logResponse(httpResponse);
return httpResponse.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
LOGGER.error("Failure occurred while getting image path", e);
}
return null;
}
private void logResponse(HttpResponse<String> httpResponse) {
if (isSuccessResponse(httpResponse.statusCode())) {
LOGGER.info("Image path received successfully");
} else {
LOGGER.warn("Image path request failed");
}
}
private boolean isSuccessResponse(int responseCode) {
return responseCode >= 200 && responseCode <= 299;
}
}

View File

@ -23,18 +23,26 @@
package com.iluwatar.api.gateway;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
/**
* An adapter to communicate with the Price microservice.
*/
@Component
public class PriceClientImpl implements PriceClient {
private static final Logger LOGGER = getLogger(PriceClientImpl.class);
/**
* Makes a simple HTTP Get request to the Price microservice.
*
@ -49,12 +57,26 @@ public class PriceClientImpl implements PriceClient {
.build();
try {
LOGGER.info("Sending request to fetch price info");
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
logResponse(httpResponse);
return httpResponse.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
LOGGER.error("Failure occurred while getting price info", e);
}
return null;
}
private void logResponse(HttpResponse<String> httpResponse) {
if (isSuccessResponse(httpResponse.statusCode())) {
LOGGER.info("Price info received successfully");
} else {
LOGGER.warn("Price info request failed");
}
}
private boolean isSuccessResponse(int responseCode) {
return responseCode >= 200 && responseCode <= 299;
}
}

View File

@ -29,7 +29,7 @@
<parent>
<artifactId>api-gateway</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>image-microservice</artifactId>

View File

@ -23,15 +23,20 @@
package com.iluwatar.image.microservice;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Exposes the Image microservice's endpoints.
*/
@RestController
public class ImageController {
private static final Logger LOGGER = getLogger(ImageController.class);
/**
* An endpoint for a user to retrieve an image path.
@ -40,6 +45,7 @@ public class ImageController {
*/
@RequestMapping(value = "/image-path", method = RequestMethod.GET)
public String getImagePath() {
LOGGER.info("Successfully found image path");
return "/product-image.png";
}
}

View File

@ -29,7 +29,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway</artifactId>

View File

@ -29,7 +29,7 @@
<parent>
<artifactId>api-gateway</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -23,15 +23,20 @@
package com.iluwatar.price.microservice;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Exposes the Price microservice's endpoints.
*/
@RestController
public class PriceController {
private static final Logger LOGGER = getLogger(PriceController.class);
/**
* An endpoint for a user to retrieve a product's price.
@ -40,6 +45,7 @@ public class PriceController {
*/
@RequestMapping(value = "/price", method = RequestMethod.GET)
public String getPrice() {
LOGGER.info("Successfully found price info");
return "20";
}
}

View File

@ -9,22 +9,137 @@ tags:
---
## Also known as
Given/When/Then
## Intent
The Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
It breaks tests down into three clear and distinct steps:
1. Arrange: Perform the setup and initialization required for the test.
2. Act: Take action(s) required for the test.
3. Assert: Verify the outcome(s) of the test.
## Explanation
This pattern has several significant benefits. It creates a clear separation between a test's
setup, operations, and results. This structure makes the code easier to read and understand. If
you place the steps in order and format your code to separate them, you can scan a test and
quickly comprehend what it does.
It also enforces a certain degree of discipline when you write your tests. You have to think
clearly about the three steps your test will perform. It makes tests more natural to write at
the same time since you already have an outline.
Real world example
> We need to write comprehensive and clear unit test suite for a class.
In plain words
> Arrange/Act/Assert is a testing pattern that organizes tests into three clear steps for easy
> maintenance.
WikiWikiWeb says
> Arrange/Act/Assert is a pattern for arranging and formatting code in UnitTest methods.
**Programmatic Example**
Let's first introduce our `Cash` class to be unit tested.
```java
public class Cash {
private int amount;
Cash(int amount) {
this.amount = amount;
}
void plus(int addend) {
amount += addend;
}
boolean minus(int subtrahend) {
if (amount >= subtrahend) {
amount -= subtrahend;
return true;
} else {
return false;
}
}
int count() {
return amount;
}
}
```
Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the clearly
separated steps for each unit test.
```java
public class CashAAATest {
@Test
public void testPlus() {
//Arrange
var cash = new Cash(3);
//Act
cash.plus(4);
//Assert
assertEquals(7, cash.count());
}
@Test
public void testMinus() {
//Arrange
var cash = new Cash(8);
//Act
var result = cash.minus(5);
//Assert
assertTrue(result);
assertEquals(3, cash.count());
}
@Test
public void testInsufficientMinus() {
//Arrange
var cash = new Cash(1);
//Act
var result = cash.minus(6);
//Assert
assertFalse(result);
assertEquals(1, cash.count());
}
@Test
public void testUpdate() {
//Arrange
var cash = new Cash(5);
//Act
cash.plus(6);
var result = cash.minus(3);
//Assert
assertTrue(result);
assertEquals(8, cash.count());
}
}
```
## Applicability
Use Arrange/Act/Assert pattern when
* you need to structure your unit tests so they're easier to read, maintain, and enhance.
* You need to structure your unit tests so that they're easier to read, maintain, and enhance.
## Credits
* [Arrange, Act, Assert: What is AAA Testing?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx)
* [Bill Wake: 3A Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/)
* [Martin Fowler: GivenWhenThen](https://martinfowler.com/bliki/GivenWhenThen.html)
* [xUnit Test Patterns: Refactoring Test Code](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f7e8dd50d720c9b63dbf)
* [Unit Testing Principles, Practices, and Patterns](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cf22a63c3e4758ae08aa0a0cc35)
* [Test Driven Development: By Example](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b84ca5087472ef0e05)

View File

@ -29,7 +29,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -60,7 +60,7 @@ public class CashAAATest {
//Act
cash.plus(4);
//Assert
assertEquals(cash.count(), 7);
assertEquals(7, cash.count());
}
@Test
@ -71,7 +71,7 @@ public class CashAAATest {
var result = cash.minus(5);
//Assert
assertTrue(result);
assertEquals(cash.count(), 3);
assertEquals(3, cash.count());
}
@Test
@ -82,7 +82,7 @@ public class CashAAATest {
var result = cash.minus(6);
//Assert
assertFalse(result);
assertEquals(cash.count(), 1);
assertEquals(1, cash.count());
}
@Test
@ -94,6 +94,6 @@ public class CashAAATest {
var result = cash.minus(3);
//Assert
assertTrue(result);
assertEquals(cash.count(), 8);
assertEquals(8, cash.count());
}
}

View File

@ -44,16 +44,16 @@ public class CashAntiAAATest {
var cash = new Cash(3);
//test plus
cash.plus(4);
assertEquals(cash.count(), 7);
assertEquals(7, cash.count());
//test minus
cash = new Cash(8);
assertTrue(cash.minus(5));
assertEquals(cash.count(), 3);
assertEquals(3, cash.count());
assertFalse(cash.minus(6));
assertEquals(cash.count(), 3);
assertEquals(3, cash.count());
//test update
cash.plus(5);
assertTrue(cash.minus(5));
assertEquals(cash.count(), 3);
assertEquals(3, cash.count());
}
}

BIN
assets/flags/CN.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
assets/flags/FR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

BIN
assets/flags/KR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

BIN
assets/flags/TR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

View File

@ -22,7 +22,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>async-method-invocation</artifactId>
<dependencies>

View File

@ -100,7 +100,7 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
void setValue(T value) {
this.value = value;
this.state = COMPLETED;
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.<Exception>empty()));
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.empty()));
synchronized (lock) {
lock.notifyAll();
}

View File

@ -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[]{}));
}
}

View File

@ -20,7 +20,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -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);
}
}

View File

@ -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

View File

@ -22,7 +22,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>bridge</artifactId>
<dependencies>

View File

@ -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[]{}));
}
}

View File

@ -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

View File

@ -22,7 +22,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>builder</artifactId>
<dependencies>

View File

@ -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[]{}));
}
}

View File

@ -22,7 +22,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>business-delegate</artifactId>
<dependencies>

View File

@ -28,7 +28,7 @@ package com.iluwatar.business.delegate;
*/
public class Client {
private BusinessDelegate businessDelegate;
private final BusinessDelegate businessDelegate;
public Client(BusinessDelegate businessDelegate) {
this.businessDelegate = businessDelegate;

View File

@ -28,5 +28,5 @@ package com.iluwatar.business.delegate;
*/
public enum ServiceType {
EJB, JMS;
EJB, JMS
}

View File

@ -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[]{}));
}
}

View File

@ -20,7 +20,7 @@
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -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);

View File

@ -30,9 +30,9 @@ import java.util.Stack;
*/
public class VirtualMachine {
private Stack<Integer> stack = new Stack<>();
private final Stack<Integer> stack = new Stack<>();
private Wizard[] wizards = new Wizard[2];
private final Wizard[] wizards = new Wizard[2];
/**
* Constructor.

View File

@ -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[]{}));
}
}

View File

@ -104,7 +104,7 @@ public class VirtualMachineTest {
bytecode[2] = LITERAL.getIntValue();
bytecode[3] = 50; // health amount
bytecode[4] = SET_HEALTH.getIntValue();
bytecode[5] = LITERAL.getIntValue();;
bytecode[5] = LITERAL.getIntValue();
bytecode[6] = wizardNumber;
bytecode[7] = GET_HEALTH.getIntValue();

View File

@ -29,7 +29,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>caching</artifactId>
<dependencies>

View File

@ -29,7 +29,7 @@ package com.iluwatar.caching;
public enum CachingPolicy {
THROUGH("through"), AROUND("around"), BEHIND("behind"), ASIDE("aside");
private String policy;
private final String policy;
CachingPolicy(String policy) {
this.policy = policy;

View File

@ -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[]{}));
}
}

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -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()

View File

@ -29,7 +29,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>callback</artifactId>
<dependencies>

View File

@ -1,26 +0,0 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
module com.iluwatar.callback {
requires org.slf4j;
}

View File

@ -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[]{}));
}
}

View File

@ -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 {
@ -65,7 +70,7 @@ Then the request handler hierarchy
```java
public abstract class RequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
private RequestHandler next;
private final RequestHandler next;
public RequestHandler(RequestHandler next) {
this.next = next;
@ -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

View File

@ -29,7 +29,7 @@
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.23.0-SNAPSHOT</version>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>chain</artifactId>
<dependencies>

View File

@ -33,7 +33,7 @@ public abstract class RequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
private RequestHandler next;
private final RequestHandler next;
public RequestHandler(RequestHandler next) {
this.next = next;

View File

@ -1,26 +0,0 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
module com.iluwatar.chain {
requires org.slf4j;
}

View File

@ -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[]{}));
}
}

View File

@ -12,167 +12,304 @@ 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 services that are used for
> fetching data. These remote services may be either healthy and responsive at times, or may become
> slow and unresponsive at some point of time due to variety of reasons. So if one of the remote
> services is slow or not responding successfully, our application will try to fetch response from
> the remote service using multiple threads/processes, soon all of them will hang (also called
> [thread starvation](https://en.wikipedia.org/wiki/Starvation_(computer_science))) causing our entire web application to 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 remote service failure. Meanwhile, the other services that are working
> normally, should keep functioning unaffected by this 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 {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {
var obj = new MonitoringService();
var circuitBreaker = new CircuitBreaker(3000, 1, 2000 * 1000 * 1000);
var serverStartTime = System.nanoTime();
while (true) {
LOGGER.info(obj.localResourceResponse());
LOGGER.info(obj.remoteResourceResponse(circuitBreaker, serverStartTime));
LOGGER.info(circuitBreaker.getState());
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
LOGGER.error(e.getMessage());
}
var delayedService = new DelayedRemoteService(serverStartTime, 5);
var delayedServiceCircuitBreaker = new DefaultCircuitBreaker(delayedService, 3000, 2,
2000 * 1000 * 1000);
var quickService = new QuickRemoteService();
var quickServiceCircuitBreaker = new DefaultCircuitBreaker(quickService, 3000, 2,
2000 * 1000 * 1000);
//Create an object of monitoring service which makes both local and remote calls
var monitoringService = new MonitoringService(delayedServiceCircuitBreaker,
quickServiceCircuitBreaker);
//Fetch response from local resource
LOGGER.info(monitoringService.localResourceResponse());
//Fetch response from delayed service 2 times, to meet the failure threshold
LOGGER.info(monitoringService.delayedServiceResponse());
LOGGER.info(monitoringService.delayedServiceResponse());
//Fetch current state of delayed service circuit breaker after crossing failure threshold limit
//which is OPEN now
LOGGER.info(delayedServiceCircuitBreaker.getState());
//Meanwhile, the delayed service is down, fetch response from the healthy quick service
LOGGER.info(monitoringService.quickServiceResponse());
LOGGER.info(quickServiceCircuitBreaker.getState());
//Wait for the delayed service to become responsive
try {
LOGGER.info("Waiting for delayed service to become responsive");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Check the state of delayed circuit breaker, should be HALF_OPEN
LOGGER.info(delayedServiceCircuitBreaker.getState());
//Fetch response from delayed service, which should be healthy by now
LOGGER.info(monitoringService.delayedServiceResponse());
//As successful response is fetched, it should be CLOSED again.
LOGGER.info(delayedServiceCircuitBreaker.getState());
}
}
```
The monitoring service is:
The monitoring service:
``` java
```java
public class MonitoringService {
private final CircuitBreaker delayedService;
private final CircuitBreaker quickService;
public MonitoringService(CircuitBreaker delayedService, CircuitBreaker quickService) {
this.delayedService = delayedService;
this.quickService = quickService;
}
//Assumption: Local service won't fail, no need to wrap it in a circuit breaker logic
public String localResourceResponse() {
return "Local Service is working";
}
public String remoteResourceResponse(CircuitBreaker circuitBreaker, long serverStartTime) {
/**
* Fetch response from the delayed service (with some simulated startup time).
*
* @return response string
*/
public String delayedServiceResponse() {
try {
return circuitBreaker.call("delayedService", serverStartTime);
} catch (Exception e) {
return this.delayedService.attemptRequest();
} catch (RemoteServiceException e) {
return e.getMessage();
}
}
/**
* Fetches response from a healthy service without any failure.
*
* @return response string
*/
public String quickServiceResponse() {
try {
return this.quickService.attemptRequest();
} catch (RemoteServiceException e) {
return e.getMessage();
}
}
}
```
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 {
public class DefaultCircuitBreaker implements CircuitBreaker {
private final long timeout;
private final long retryTimePeriod;
private final RemoteService service;
long lastFailureTime;
private String lastFailureResponse;
int failureCount;
private final int failureThreshold;
private State state;
private final long futureTime = 1000 * 1000 * 1000 * 1000;
CircuitBreaker(long timeout, int failureThreshold, long retryTimePeriod) {
/**
* Constructor to create an instance of Circuit Breaker.
*
* @param timeout Timeout for the API request. Not necessary for this simple example
* @param failureThreshold Number of failures we receive from the depended service before changing
* state to 'OPEN'
* @param retryTimePeriod Time period after which a new request is made to remote service for
* status check.
*/
DefaultCircuitBreaker(RemoteService serviceToCall, long timeout, int failureThreshold,
long retryTimePeriod) {
this.service = serviceToCall;
// We start in a closed state hoping that everything is fine
this.state = State.CLOSED;
this.failureThreshold = failureThreshold;
// Timeout for the API request.
// Used to break the calls made to remote resource if it exceeds the limit
this.timeout = timeout;
this.retryTimePeriod = retryTimePeriod;
//An absurd amount of time in future which basically indicates the last failure never happened
this.lastFailureTime = System.nanoTime() + futureTime;
this.failureCount = 0;
}
private void reset() {
// Reset everything to defaults
@Override
public void recordSuccess() {
this.failureCount = 0;
this.lastFailureTime = System.nanoTime() + futureTime;
this.lastFailureTime = System.nanoTime() + futureTime;
this.state = State.CLOSED;
}
private void recordFailure() {
@Override
public void recordFailure(String response) {
failureCount = failureCount + 1;
this.lastFailureTime = System.nanoTime();
// Cache the failure response for returning on open state
this.lastFailureResponse = response;
}
protected void setState() {
if (failureCount > failureThreshold) {
// Evaluate the current state based on failureThreshold, failureCount and lastFailureTime.
protected void evaluateState() {
if (failureCount >= failureThreshold) { //Then something is wrong with remote service
if ((System.nanoTime() - lastFailureTime) > retryTimePeriod) {
//We have waited long enough and should try checking if service is up
state = State.HALF_OPEN;
} else {
//Service would still probably be down
state = State.OPEN;
}
} else {
//Everything is working fine
state = State.CLOSED;
}
}
@Override
public String getState() {
evaluateState();
return state.name();
}
public void setStateForBypass(State state) {
/**
* Break the circuit beforehand if it is known service is down Or connect the circuit manually if
* service comes online before expected.
*
* @param state State at which circuit is in
*/
@Override
public void setState(State state) {
this.state = state;
switch (state) {
case OPEN:
this.failureCount = failureThreshold;
this.lastFailureTime = System.nanoTime();
break;
case HALF_OPEN:
this.failureCount = failureThreshold;
this.lastFailureTime = System.nanoTime() - retryTimePeriod;
break;
default:
this.failureCount = 0;
}
}
public String call(String serviceToCall, long serverStartTime) throws Exception {
setState();
/**
* Executes service call.
*
* @return Value from the remote resource, stale response or a custom exception
*/
@Override
public String attemptRequest() throws RemoteServiceException {
evaluateState();
if (state == State.OPEN) {
return "This is stale response from API";
// return cached response if the circuit is in OPEN state
return this.lastFailureResponse;
} else {
if (serviceToCall.equals("delayedService")) {
var delayedService = new DelayedService(20);
var response = delayedService.response(serverStartTime);
if (response.split(" ")[3].equals("working")) {
reset();
return response;
} else {
recordFailure();
throw new Exception("Remote service not responding");
}
} else {
throw new Exception("Unknown Service Name");
// Make the API request if the circuit is not OPEN
try {
//In a real application, this would be run in a thread and the timeout
//parameter of the circuit breaker would be utilized to know if service
//is working. Here, we simulate that based on server response itself
var response = service.call();
// Yay!! the API responded fine. Let's reset everything.
recordSuccess();
return response;
} catch (RemoteServiceException ex) {
recordFailure(ex.getMessage());
throw ex;
}
}
}
}
```
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Some files were not shown because too many files have changed in this diff Show More