Compare commits
143 Commits
balking-ex
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
3b87565fb6 | ||
|
da9f26bbc0 | ||
|
dde31bfe34 | ||
|
1596e9048d | ||
|
a4aff05123 | ||
|
c87689b247 | ||
|
5ce0419b44 | ||
|
58ce3a2ab2 | ||
|
7652b11bca | ||
|
07ee94d671 | ||
|
c5492184b7 | ||
|
4f8007d674 | ||
|
2d2dec98e8 | ||
|
3cc9bc2dea | ||
|
11f20593b2 | ||
|
c66ca67201 | ||
|
2679f7aa6f | ||
|
8403fdacdd | ||
|
f670ae547b | ||
|
df73d80365 | ||
|
4588e09939 | ||
|
69883196d2 | ||
|
4dcc20b733 | ||
|
600227d2e4 | ||
|
fee898cd27 | ||
|
b1242629c8 | ||
|
5d78a77b97 | ||
|
9063336687 | ||
|
b22c8bc32f | ||
|
f7fc48d6b7 | ||
|
414e3263b1 | ||
|
2674cb9523 | ||
|
925755fa35 | ||
|
89b2072131 | ||
|
0a7b524bd1 | ||
|
36c6ce1df7 | ||
|
22ddd57146 | ||
|
72bb189dc0 | ||
|
bee1283371 | ||
|
785cbf42b7 | ||
|
c51eb66c89 | ||
|
1eb74203fc | ||
|
c6803f920d | ||
|
b80ac39e1f | ||
|
da6d20e997 | ||
|
5dbb176a33 | ||
|
e3c3b02efd | ||
|
988c478ad4 | ||
|
221daf5d74 | ||
|
90b1b922e1 | ||
|
bd71bc1311 | ||
|
54d19d4c87 | ||
|
464b166fa3 | ||
|
78abdb4e13 | ||
|
d1c26f9d84 | ||
|
ba51a49802 | ||
|
73eca64b9f | ||
|
8aac45ab69 | ||
|
2c93c81cf9 | ||
|
656b441e29 | ||
|
37d9ff3342 | ||
|
d9dae3ae6a | ||
|
1354bf0f55 | ||
|
dc7c99c32f | ||
|
c2786e5dc4 | ||
|
a1f3c6fe20 | ||
|
0ad44ced24 | ||
|
4c5c0fd63e | ||
|
5a644f1092 | ||
|
cab9048e06 | ||
|
d247b6ed69 | ||
|
0a73ead12d | ||
|
ddb9b14eed | ||
|
0255111b4e | ||
|
9513d2be58 | ||
|
119abf3ee4 | ||
|
87cc4df14b | ||
|
57f9c2e968 | ||
|
42eb7950ae | ||
|
be72a96cd6 | ||
|
be25c0b433 | ||
|
be59e50205 | ||
|
ec90320eda | ||
|
3126ad3106 | ||
|
e2ebb59fe7 | ||
|
d87e8cf10d | ||
|
c5a4068e84 | ||
|
d36efdbc7c | ||
|
3f654ab0c8 | ||
|
eac85678f0 | ||
|
eaeb6e717c | ||
|
28fc672a2f | ||
|
04bf566dc1 | ||
|
bbdff14a66 | ||
|
eade10a98d | ||
|
43e7ca515a | ||
|
f6d43975fa | ||
|
c0d36894c2 | ||
|
6cf025447a | ||
|
dafe02f1be | ||
|
784cdee819 | ||
|
5e434b783e | ||
|
f597fc1b07 | ||
|
1b880c1818 | ||
|
e498c25675 | ||
|
122e6edb38 | ||
|
ea3c9d955e | ||
|
f1feb3f6a0 | ||
|
1388e38744 | ||
|
1dd26289e5 | ||
|
241a7ad9a2 | ||
|
32b33480dd | ||
|
068fa0371e | ||
|
b5aaa94794 | ||
|
825b5a9a29 | ||
|
31890f67e6 | ||
|
41b1462eed | ||
|
276549d156 | ||
|
d67b625a74 | ||
|
1b14ebcbb1 | ||
|
a471ce25da | ||
|
74caa0c4e5 | ||
|
53a294fee5 | ||
|
a5062908c0 | ||
|
076310bb79 | ||
|
470d29e715 | ||
|
74802e83b5 | ||
|
09b577f634 | ||
|
2fce2e44e2 | ||
|
b3a1749bd0 | ||
|
af0ccdc6e1 | ||
|
323dd63e66 | ||
|
be3250bd0d | ||
|
1222f12b99 | ||
|
965d38f139 | ||
|
eb8f9db575 | ||
|
6d7084f18d | ||
|
74f5cfa670 | ||
|
b525d871b4 | ||
|
c413e0902e | ||
|
7ac468db20 | ||
|
794795acf5 | ||
|
2b7d181ac4 |
@ -16,6 +16,17 @@
|
|||||||
"content"
|
"content"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"login": "ohbus",
|
||||||
|
"name": "Subhrodip Mohanta",
|
||||||
|
"avatar_url": "https://avatars0.githubusercontent.com/u/13291222?v=4",
|
||||||
|
"profile": "http://subho.xyz",
|
||||||
|
"contributions": [
|
||||||
|
"code",
|
||||||
|
"review",
|
||||||
|
"maintenance"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"login": "amit1307",
|
"login": "amit1307",
|
||||||
"name": "amit1307",
|
"name": "amit1307",
|
||||||
@ -1125,16 +1136,6 @@
|
|||||||
"ideas"
|
"ideas"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"login": "ohbus",
|
|
||||||
"name": "Subhrodip Mohanta",
|
|
||||||
"avatar_url": "https://avatars0.githubusercontent.com/u/13291222?v=4",
|
|
||||||
"profile": "http://subho.xyz",
|
|
||||||
"contributions": [
|
|
||||||
"code",
|
|
||||||
"review"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"login": "nahteb",
|
"login": "nahteb",
|
||||||
"name": "Bethan Palmer",
|
"name": "Bethan Palmer",
|
||||||
@ -1440,9 +1441,372 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"doc"
|
"doc"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "jinishavora",
|
||||||
|
"name": "jinishavora",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/40777762?v=4",
|
||||||
|
"profile": "https://www.linkedin.com/in/jinisha-vora",
|
||||||
|
"contributions": [
|
||||||
|
"review",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "eas5",
|
||||||
|
"name": "Elvys Soares",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/50836521?v=4",
|
||||||
|
"profile": "https://github.com/eas5",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "zWeBrain",
|
||||||
|
"name": "zWeBrain",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/46642512?v=4",
|
||||||
|
"profile": "https://github.com/zWeBrain",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Al-assad",
|
||||||
|
"name": "余林颖",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/22493821?v=4",
|
||||||
|
"profile": "https://al-assad.github.io/notion/",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "STudio26",
|
||||||
|
"name": "Alain",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/6988911?v=4",
|
||||||
|
"profile": "https://github.com/STudio26",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "DEV-VRUPER",
|
||||||
|
"name": "VR",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/30525467?v=4",
|
||||||
|
"profile": "https://github.com/DEV-VRUPER",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "JackieNim",
|
||||||
|
"name": "JackieNim",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/4138836?v=4",
|
||||||
|
"profile": "https://github.com/JackieNim",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "EdisonE3",
|
||||||
|
"name": "EdisonE3",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/52118917?v=4",
|
||||||
|
"profile": "https://github.com/EdisonE3",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "tao-sun2",
|
||||||
|
"name": "Tao",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/66189688?v=4",
|
||||||
|
"profile": "https://github.com/tao-sun2",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "JuanManuelAbate",
|
||||||
|
"name": "Juan Manuel Abate",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/16357060?v=4",
|
||||||
|
"profile": "https://github.com/JuanManuelAbate",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Xenilo137",
|
||||||
|
"name": "Xenilo137",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/24865069?v=4",
|
||||||
|
"profile": "https://github.com/Xenilo137",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "samuelpsouza",
|
||||||
|
"name": "Samuel Souza",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/17254162?v=4",
|
||||||
|
"profile": "https://www.linkedin.com/in/souzasamuel/",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "marlo2222",
|
||||||
|
"name": "Marlo Henrique",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/40809563?v=4",
|
||||||
|
"profile": "https://github.com/marlo2222",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "AndriyPyzh",
|
||||||
|
"name": "AndriyPyzh",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/57706635?v=4",
|
||||||
|
"profile": "https://github.com/AndriyPyzh",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "karthikbhat13",
|
||||||
|
"name": "karthikbhat13",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/22431014?v=4",
|
||||||
|
"profile": "https://github.com/karthikbhat13",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "mortezaadi",
|
||||||
|
"name": "Morteza Adigozalpour",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1329687?v=4",
|
||||||
|
"profile": "https://github.com/mortezaadi",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "tan31989",
|
||||||
|
"name": "Nagaraj Tantri",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/3784194?v=4",
|
||||||
|
"profile": "https://stackoverflow.com/users/308565/nagaraj-tantri",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "frascu",
|
||||||
|
"name": "Francesco Scuccimarri",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/7107651?v=4",
|
||||||
|
"profile": "http://scuccimarri.it",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Conhan93",
|
||||||
|
"name": "Conny Hansson",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/71334757?v=4",
|
||||||
|
"profile": "https://github.com/Conhan93",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "muklasr",
|
||||||
|
"name": "Muklas Rahmanto",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/43443753?v=4",
|
||||||
|
"profile": "http://muklasr.medium.com",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "VxDxK",
|
||||||
|
"name": "Vadim",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/38704817?v=4",
|
||||||
|
"profile": "https://github.com/VxDxK",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "sims-keshri",
|
||||||
|
"name": "Simran Keshri",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/62168475?v=4",
|
||||||
|
"profile": "https://github.com/sims-keshri",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "JCarlosR",
|
||||||
|
"name": "JCarlos",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/3101238?v=4",
|
||||||
|
"profile": "https://programacionymas.com",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Dev-AliGhasemi",
|
||||||
|
"name": "Ali Ghasemi",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/60359433?v=4",
|
||||||
|
"profile": "https://www.mrmoshkel.ir",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "carldea",
|
||||||
|
"name": "Carl Dea",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1594624?v=4",
|
||||||
|
"profile": "http://carlfx.wordpress.com",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Mozartuss",
|
||||||
|
"name": "Mozartus",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/32893711?v=4",
|
||||||
|
"profile": "https://github.com/Mozartuss",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "ManviGoel26",
|
||||||
|
"name": "Manvi Goel",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/55682355?v=4",
|
||||||
|
"profile": "https://github.com/ManviGoel26",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "blueberry404",
|
||||||
|
"name": "Anum Amin",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/39243539?v=4",
|
||||||
|
"profile": "https://github.com/blueberry404",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "uh-zz",
|
||||||
|
"name": "Reo Uehara",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/47747828?v=4",
|
||||||
|
"profile": "https://uh-zz.github.io/blog/",
|
||||||
|
"contributions": [
|
||||||
|
"translation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Fiordy",
|
||||||
|
"name": "Fiordy",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/53420573?v=4",
|
||||||
|
"profile": "https://github.com/Fiordy",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "harshalkh",
|
||||||
|
"name": "Harshal",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/37841724?v=4",
|
||||||
|
"profile": "https://github.com/harshalkh",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "vashisthabhinav",
|
||||||
|
"name": "Abhinav Vashisth",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/89785800?v=4",
|
||||||
|
"profile": "https://www.linkedin.com/in/abhinav-vashisth-06613b208/",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Kevinyl3",
|
||||||
|
"name": "Kevin",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/47126749?v=4",
|
||||||
|
"profile": "http://no website",
|
||||||
|
"contributions": [
|
||||||
|
"review",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Shrirang97",
|
||||||
|
"name": "Shrirang",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/28738668?v=4",
|
||||||
|
"profile": "https://github.com/Shrirang97",
|
||||||
|
"contributions": [
|
||||||
|
"review",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "interactwithankush",
|
||||||
|
"name": "interactwithankush",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/18613127?v=4",
|
||||||
|
"profile": "https://github.com/interactwithankush",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "yuhangbin",
|
||||||
|
"name": "CharlieYu",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/17566866?v=4",
|
||||||
|
"profile": "https://github.com/yuhangbin",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Leisterbecker",
|
||||||
|
"name": "Leisterbecker",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/20650323?v=4",
|
||||||
|
"profile": "https://github.com/Leisterbecker",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "castleKing1997",
|
||||||
|
"name": "DragonDreamer",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/35420129?v=4",
|
||||||
|
"profile": "http://rosaecrucis.cn",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "ShivanshCharak",
|
||||||
|
"name": "ShivanshCharak",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/96943825?v=4",
|
||||||
|
"profile": "https://github.com/ShivanshCharak",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "HattoriHenzo",
|
||||||
|
"name": "HattoriHenzo",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/5141285?v=4",
|
||||||
|
"profile": "https://github.com/HattoriHenzo",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 4,
|
"contributorsPerLine": 7,
|
||||||
"projectName": "java-design-patterns",
|
"projectName": "java-design-patterns",
|
||||||
"projectOwner": "iluwatar",
|
"projectOwner": "iluwatar",
|
||||||
"repoType": "github",
|
"repoType": "github",
|
||||||
|
54
.github/workflows/maven-ci.yml
vendored
@ -24,6 +24,9 @@
|
|||||||
# This workflow will build a Java project with Maven
|
# 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
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||||
|
|
||||||
|
# We are using two jobs here for testing our code on the latest JDK 11 build as well as a more satble build version of 11.0.3
|
||||||
|
# You can see the full discussion here https://github.com/iluwatar/java-design-patterns/pull/1868#issue-1029459688
|
||||||
|
|
||||||
name: Java CI
|
name: Java CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@ -33,38 +36,34 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
# This Workflow Job will build this project and run Sonar analysis using JDK 11.0.3
|
||||||
|
build-and-analyze:
|
||||||
|
|
||||||
|
name: Build and Run Sonar analysis on JDK 11.0.3
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
# Disabling shallow clone for improving relevancy of SonarQube reporting
|
# Disabling shallow clone for improving relevancy of SonarQube reporting
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up JDK 11
|
- name: Set up JDK 11.0.3
|
||||||
uses: actions/setup-java@master
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11.0.3
|
||||||
|
distribution: 'zulu'
|
||||||
|
cache: 'maven'
|
||||||
|
|
||||||
|
# Cache Sonar packages which as used to run anaylysis and collect metrics
|
||||||
- name: Cache SonarCloud packages
|
- name: Cache SonarCloud packages
|
||||||
uses: actions/cache@master
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ~/.sonar/cache
|
path: ~/.sonar/cache
|
||||||
key: ${{ runner.os }}-sonar
|
key: ${{ runner.os }}-sonar
|
||||||
restore-keys: ${{ runner.os }}-sonar
|
restore-keys: ${{ runner.os }}-sonar
|
||||||
|
|
||||||
- name: Cache Maven dependencies
|
|
||||||
uses: actions/cache@master
|
|
||||||
with:
|
|
||||||
path: ~/.m2/repository
|
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-maven-
|
|
||||||
|
|
||||||
# Some tests need screen access
|
# Some tests need screen access
|
||||||
- name: Install xvfb
|
- name: Install xvfb
|
||||||
run: sudo apt-get install -y xvfb
|
run: sudo apt-get install -y xvfb
|
||||||
@ -75,3 +74,28 @@ jobs:
|
|||||||
# These two env variables are needed for sonar analysis
|
# These two env variables are needed for sonar analysis
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
|
||||||
|
|
||||||
|
# This Workflow Job is going to build the project on the latest stable JDK 11
|
||||||
|
build:
|
||||||
|
|
||||||
|
name: Build and Test on JDK 11
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up JDK 11 (Latest)
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
distribution: 'zulu'
|
||||||
|
cache: 'maven'
|
||||||
|
|
||||||
|
# Some tests need screen access
|
||||||
|
- name: Install xvfb
|
||||||
|
run: sudo apt-get install -y xvfb
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: xvfb-run ./mvnw clean verify
|
||||||
|
26
.github/workflows/maven-pr-builder.yml
vendored
@ -29,29 +29,27 @@ name: Java PR Builder
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
types: [ opened, reopened, synchronize, labeled, unlabeled ]
|
types: [ opened, reopened, synchronize ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
|
name: Build JDP
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
java-version: [ 11.0.3, 11 ]
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up JDK 11
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
uses: actions/setup-java@master
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: ${{ matrix.java-version }}
|
||||||
|
distribution: 'zulu'
|
||||||
- name: Cache Maven Dependecies
|
cache: 'maven'
|
||||||
uses: actions/cache@master
|
|
||||||
with:
|
|
||||||
path: ~/.m2/repository
|
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-maven-
|
|
||||||
|
|
||||||
# Some tests need screen access
|
# Some tests need screen access
|
||||||
- name: Install xvfb
|
- name: Install xvfb
|
||||||
|
1
.gitignore
vendored
@ -12,6 +12,7 @@ tmp/
|
|||||||
local.properties
|
local.properties
|
||||||
.loadpath
|
.loadpath
|
||||||
.recommenders
|
.recommenders
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
####### Java annotation processor (APT) ########
|
####### Java annotation processor (APT) ########
|
||||||
.factorypath
|
.factorypath
|
||||||
|
39
.mvn/wrapper/maven-wrapper.properties
vendored
@ -1,25 +1,18 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
#
|
#
|
||||||
# The MIT License
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
# Copyright © 2014-2021 Ilkka Seppälä
|
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Unless required by applicable law or agreed to in writing,
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# software distributed under the License is distributed on an
|
||||||
# in the Software without restriction, including without limitation the rights
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# KIND, either express or implied. See the License for the
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
# specific language governing permissions and limitations
|
||||||
# furnished to do so, subject to the following conditions:
|
# under the License.
|
||||||
#
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
|
||||||
# The above copyright notice and this permission notice shall be included in
|
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
|
||||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014-2021 Ilkka Seppälä
|
Copyright © 2014-2021 Ilkka Seppälä
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -19,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
Module Model-view-viewmodel is using ZK framework
|
||||||
|
ZK framework is licensed under LGPL and the license can be found at lgpl-3.0.txt
|
||||||
|
154
README.md
@ -10,18 +10,18 @@
|
|||||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
[](#contributors-)
|
[](#contributors-)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
Read in different language : [**CN**](/zh/README.md), [**KR**](/ko/README.md), [**FR**](/fr/README.md), [**TR**](/tr/README.md), [**AR**](/ar/README.md)
|
Read in different language : [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md)
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Design patterns are the best formalized practices a programmer can use to
|
Design patterns are the best, formalized practices a programmer can use to
|
||||||
solve common problems when designing an application or system.
|
solve common problems when designing an application or system.
|
||||||
|
|
||||||
Design patterns can speed up the development process by providing tested, proven
|
Design patterns can speed up the development process by providing tested, proven
|
||||||
@ -34,11 +34,11 @@ are familiar with the patterns.
|
|||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
This site showcases Java Design Patterns. The solutions have been developed by
|
This site showcases Java Design Patterns. The solutions have been developed by
|
||||||
experienced programmers and architects from the open source community. The
|
experienced programmers and architects from the open-source community. The
|
||||||
patterns can be browsed by their high level descriptions or by looking at their
|
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
|
source code. The source code examples are well commented and can be thought of as
|
||||||
programming tutorials on 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.
|
popular battle-proven open-source Java technologies.
|
||||||
|
|
||||||
Before you dive into the material, you should be familiar with various
|
Before you dive into the material, you should be familiar with various
|
||||||
[Software Design Principles](https://java-design-patterns.com/principles/).
|
[Software Design Principles](https://java-design-patterns.com/principles/).
|
||||||
@ -56,8 +56,8 @@ of the following approaches
|
|||||||
- Using tags such as `Performance`, `Gang of Four` or `Data access`.
|
- Using tags such as `Performance`, `Gang of Four` or `Data access`.
|
||||||
- Using pattern categories, `Creational`, `Behavioral`, and others.
|
- Using pattern categories, `Creational`, `Behavioral`, and others.
|
||||||
|
|
||||||
Hopefully you find the object oriented solutions presented on this site useful
|
Hopefully, you find the object-oriented solutions presented on this site useful
|
||||||
in your architectures and have as much fun learning them as we had developing them.
|
in your architectures and have as much fun learning them as we had while developing them.
|
||||||
|
|
||||||
# How to contribute
|
# How to contribute
|
||||||
|
|
||||||
@ -77,29 +77,26 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<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/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="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> <a href="#maintenance-ohbus" title="Maintenance">🚧</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/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/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>
|
<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?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="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/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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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="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="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/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>
|
<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>
|
||||||
|
<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>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<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="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://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>
|
<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?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/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/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="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>
|
||||||
@ -110,38 +107,32 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<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/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://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>
|
<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?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://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="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="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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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/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://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://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>
|
<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://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://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="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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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://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://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/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>
|
<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>
|
||||||
|
<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>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<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://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="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>
|
<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://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://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/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>
|
||||||
@ -152,38 +143,32 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<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://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://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>
|
<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/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="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="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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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="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/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/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>
|
<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/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/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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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="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="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://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>
|
<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>
|
||||||
|
<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>
|
||||||
</tr>
|
</tr>
|
||||||
<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="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://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>
|
<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/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://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://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>
|
||||||
@ -194,38 +179,32 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<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/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/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>
|
<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/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://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://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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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/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/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/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>
|
<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://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/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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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://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://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="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>
|
<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>
|
||||||
|
<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>
|
||||||
</tr>
|
</tr>
|
||||||
<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://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/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>
|
<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="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://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/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>
|
||||||
@ -236,50 +215,41 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<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/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/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>
|
<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://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://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://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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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://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://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/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>
|
<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/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/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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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://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://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="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/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="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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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://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/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/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>
|
<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>
|
||||||
|
<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>
|
||||||
</tr>
|
</tr>
|
||||||
<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="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://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>
|
<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="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="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/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>
|
||||||
@ -290,28 +260,76 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<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/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/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>
|
<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://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/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/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>
|
||||||
<tr>
|
<tr>
|
||||||
|
<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>
|
||||||
<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="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/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>
|
<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>
|
||||||
<td align="center"><a href="https://github.com/rohit10000"><img src="https://avatars.githubusercontent.com/u/20845565?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rohit Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=rohit10000" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/rohit10000"><img src="https://avatars.githubusercontent.com/u/20845565?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rohit Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=rohit10000" title="Code">💻</a></td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/byoungju94"><img src="https://avatars.githubusercontent.com/u/42516378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>byoungju94</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=byoungju94" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/byoungju94"><img src="https://avatars.githubusercontent.com/u/42516378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>byoungju94</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=byoungju94" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/moustafafarhat"><img src="https://avatars.githubusercontent.com/u/38836727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moustafa Farhat</b></sub></a><br /><a href="#translation-moustafafarhat" title="Translation">🌍</a></td>
|
<td align="center"><a href="https://github.com/moustafafarhat"><img src="https://avatars.githubusercontent.com/u/38836727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moustafa Farhat</b></sub></a><br /><a href="#translation-moustafafarhat" title="Translation">🌍</a></td>
|
||||||
<td align="center"><a href="https://github.com/richardmr36"><img src="https://avatars.githubusercontent.com/u/19147333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martel Richard</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=richardmr36" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/va1m"><img src="https://avatars.githubusercontent.com/u/17025445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>va1m</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=va1m" title="Code">💻</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/richardmr36"><img src="https://avatars.githubusercontent.com/u/19147333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martel Richard</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=richardmr36" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/va1m"><img src="https://avatars.githubusercontent.com/u/17025445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>va1m</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=va1m" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/noamgrinch"><img src="https://avatars.githubusercontent.com/u/31648669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Noam Greenshtain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=noamgrinch" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/noamgrinch"><img src="https://avatars.githubusercontent.com/u/31648669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Noam Greenshtain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=noamgrinch" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://xuyonghong.cn/"><img src="https://avatars.githubusercontent.com/u/14086462?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yonghong Xu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qfxl" title="Documentation">📖</a></td>
|
<td align="center"><a href="https://xuyonghong.cn/"><img src="https://avatars.githubusercontent.com/u/14086462?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yonghong Xu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qfxl" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/jinisha-vora"><img src="https://avatars.githubusercontent.com/u/40777762?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jinishavora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Ajinishavora" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=jinishavora" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/eas5"><img src="https://avatars.githubusercontent.com/u/50836521?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Elvys Soares</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eas5" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/zWeBrain"><img src="https://avatars.githubusercontent.com/u/46642512?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zWeBrain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zWeBrain" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://al-assad.github.io/notion/"><img src="https://avatars.githubusercontent.com/u/22493821?v=4?s=100" width="100px;" alt=""/><br /><sub><b>余林颖</b></sub></a><br /><a href="#translation-Al-assad" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/STudio26"><img src="https://avatars.githubusercontent.com/u/6988911?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alain</b></sub></a><br /><a href="#translation-STudio26" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/DEV-VRUPER"><img src="https://avatars.githubusercontent.com/u/30525467?v=4?s=100" width="100px;" alt=""/><br /><sub><b>VR</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=DEV-VRUPER" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/JackieNim"><img src="https://avatars.githubusercontent.com/u/4138836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JackieNim</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JackieNim" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/EdisonE3"><img src="https://avatars.githubusercontent.com/u/52118917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>EdisonE3</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=EdisonE3" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/tao-sun2"><img src="https://avatars.githubusercontent.com/u/66189688?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tao</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=tao-sun2" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/JuanManuelAbate"><img src="https://avatars.githubusercontent.com/u/16357060?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Abate</b></sub></a><br /><a href="#translation-JuanManuelAbate" title="Translation">🌍</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/Xenilo137"><img src="https://avatars.githubusercontent.com/u/24865069?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xenilo137</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Xenilo137" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/souzasamuel/"><img src="https://avatars.githubusercontent.com/u/17254162?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samuel Souza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samuelpsouza" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/marlo2222"><img src="https://avatars.githubusercontent.com/u/40809563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marlo Henrique</b></sub></a><br /><a href="#translation-marlo2222" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/AndriyPyzh"><img src="https://avatars.githubusercontent.com/u/57706635?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AndriyPyzh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AndriyPyzh" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/karthikbhat13"><img src="https://avatars.githubusercontent.com/u/22431014?v=4?s=100" width="100px;" alt=""/><br /><sub><b>karthikbhat13</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=karthikbhat13" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/mortezaadi"><img src="https://avatars.githubusercontent.com/u/1329687?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Morteza Adigozalpour</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mortezaadi" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://stackoverflow.com/users/308565/nagaraj-tantri"><img src="https://avatars.githubusercontent.com/u/3784194?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nagaraj Tantri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=tan31989" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="http://scuccimarri.it"><img src="https://avatars.githubusercontent.com/u/7107651?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Francesco Scuccimarri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=frascu" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Conhan93"><img src="https://avatars.githubusercontent.com/u/71334757?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Conny Hansson</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Conhan93" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="http://muklasr.medium.com"><img src="https://avatars.githubusercontent.com/u/43443753?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Muklas Rahmanto</b></sub></a><br /><a href="#translation-muklasr" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/VxDxK"><img src="https://avatars.githubusercontent.com/u/38704817?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vadim</b></sub></a><br /><a href="#translation-VxDxK" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/sims-keshri"><img src="https://avatars.githubusercontent.com/u/62168475?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Simran Keshri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sims-keshri" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://programacionymas.com"><img src="https://avatars.githubusercontent.com/u/3101238?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JCarlos</b></sub></a><br /><a href="#translation-JCarlosR" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://www.mrmoshkel.ir"><img src="https://avatars.githubusercontent.com/u/60359433?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ali Ghasemi</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Dev-AliGhasemi" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="http://carlfx.wordpress.com"><img src="https://avatars.githubusercontent.com/u/1594624?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Carl Dea</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=carldea" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Mozartuss"><img src="https://avatars.githubusercontent.com/u/32893711?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mozartus</b></sub></a><br /><a href="#translation-Mozartuss" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/ManviGoel26"><img src="https://avatars.githubusercontent.com/u/55682355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manvi Goel</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ManviGoel26" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/blueberry404"><img src="https://avatars.githubusercontent.com/u/39243539?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anum Amin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=blueberry404" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://uh-zz.github.io/blog/"><img src="https://avatars.githubusercontent.com/u/47747828?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Reo Uehara</b></sub></a><br /><a href="#translation-uh-zz" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Fiordy"><img src="https://avatars.githubusercontent.com/u/53420573?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fiordy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Fiordy" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/harshalkh"><img src="https://avatars.githubusercontent.com/u/37841724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harshal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=harshalkh" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/abhinav-vashisth-06613b208/"><img src="https://avatars.githubusercontent.com/u/89785800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Abhinav Vashisth</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vashisthabhinav" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="http://no website"><img src="https://avatars.githubusercontent.com/u/47126749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AKevinyl3" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=Kevinyl3" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Shrirang97"><img src="https://avatars.githubusercontent.com/u/28738668?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shrirang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AShrirang97" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=Shrirang97" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/interactwithankush"><img src="https://avatars.githubusercontent.com/u/18613127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>interactwithankush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=interactwithankush" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/yuhangbin"><img src="https://avatars.githubusercontent.com/u/17566866?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CharlieYu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yuhangbin" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Leisterbecker"><img src="https://avatars.githubusercontent.com/u/20650323?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leisterbecker</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Leisterbecker" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://rosaecrucis.cn"><img src="https://avatars.githubusercontent.com/u/35420129?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DragonDreamer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=castleKing1997" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/ShivanshCharak"><img src="https://avatars.githubusercontent.com/u/96943825?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ShivanshCharak</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ShivanshCharak" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/HattoriHenzo"><img src="https://avatars.githubusercontent.com/u/5141285?v=4?s=100" width="100px;" alt=""/><br /><sub><b>HattoriHenzo</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=HattoriHenzo" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ title: Abstract Document
|
|||||||
folder: abstract-document
|
folder: abstract-document
|
||||||
permalink: /patterns/abstract-document/
|
permalink: /patterns/abstract-document/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Extensibility
|
- Extensibility
|
||||||
---
|
---
|
||||||
|
@ -23,14 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>abstract-document</artifactId>
|
<artifactId>abstract-document</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -4,6 +4,7 @@ title: Abstract Factory
|
|||||||
folder: abstract-factory
|
folder: abstract-factory
|
||||||
permalink: /patterns/abstract-factory/
|
permalink: /patterns/abstract-factory/
|
||||||
categories: Creational
|
categories: Creational
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Gang of Four
|
- Gang of Four
|
||||||
---
|
---
|
||||||
@ -19,9 +20,9 @@ objects without specifying their concrete classes.
|
|||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Real world example
|
Real-world example
|
||||||
|
|
||||||
> 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.
|
> To create a kingdom we need objects with a common theme. The elven kingdom needs an elven king, elven castle, and elven army whereas the orcish kingdom needs an orcish king, orcish castle, and orcish army. There is a dependency between the objects in the kingdom.
|
||||||
|
|
||||||
In plain words
|
In plain words
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ Wikipedia says
|
|||||||
|
|
||||||
**Programmatic Example**
|
**Programmatic Example**
|
||||||
|
|
||||||
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the
|
Translating the kingdom example above. First of all, we have some interfaces and implementation for the objects in the
|
||||||
kingdom.
|
kingdom.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@ -51,21 +52,21 @@ public interface Army {
|
|||||||
|
|
||||||
// Elven implementations ->
|
// Elven implementations ->
|
||||||
public class ElfCastle implements Castle {
|
public class ElfCastle implements Castle {
|
||||||
static final String DESCRIPTION = "This is the Elven castle!";
|
static final String DESCRIPTION = "This is the elven castle!";
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return DESCRIPTION;
|
return DESCRIPTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class ElfKing implements King {
|
public class ElfKing implements King {
|
||||||
static final String DESCRIPTION = "This is the Elven king!";
|
static final String DESCRIPTION = "This is the elven king!";
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return DESCRIPTION;
|
return DESCRIPTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class ElfArmy implements Army {
|
public class ElfArmy implements Army {
|
||||||
static final String DESCRIPTION = "This is the Elven Army!";
|
static final String DESCRIPTION = "This is the elven Army!";
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return DESCRIPTION;
|
return DESCRIPTION;
|
||||||
@ -76,7 +77,7 @@ public class ElfArmy implements Army {
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then we have the abstraction and implementations for the kingdom factory
|
Then we have the abstraction and implementations for the kingdom factory.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface KingdomFactory {
|
public interface KingdomFactory {
|
||||||
@ -86,31 +87,43 @@ public interface KingdomFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class ElfKingdomFactory implements KingdomFactory {
|
public class ElfKingdomFactory implements KingdomFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
public Castle createCastle() {
|
public Castle createCastle() {
|
||||||
return new ElfCastle();
|
return new ElfCastle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public King createKing() {
|
public King createKing() {
|
||||||
return new ElfKing();
|
return new ElfKing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Army createArmy() {
|
public Army createArmy() {
|
||||||
return new ElfArmy();
|
return new ElfArmy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OrcKingdomFactory implements KingdomFactory {
|
public class OrcKingdomFactory implements KingdomFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
public Castle createCastle() {
|
public Castle createCastle() {
|
||||||
return new OrcCastle();
|
return new OrcCastle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public King createKing() {
|
public King createKing() {
|
||||||
return new OrcKing();
|
return new OrcKing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Army createArmy() {
|
public Army createArmy() {
|
||||||
return new OrcArmy();
|
return new OrcArmy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we have our abstract factory that lets us make family of related objects i.e. Elven kingdom factory creates Elven castle, king and army etc.
|
Now we have the abstract factory that lets us make a family of related objects i.e. elven kingdom factory creates elven castle, king and army, etc.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
var factory = new ElfKingdomFactory();
|
var factory = new ElfKingdomFactory();
|
||||||
@ -126,13 +139,13 @@ army.getDescription();
|
|||||||
Program output:
|
Program output:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
This is the Elven castle!
|
This is the elven castle!
|
||||||
This is the Elven king!
|
This is the elven king!
|
||||||
This is the Elven Army!
|
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.
|
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`.
|
||||||
The client can use FactoryMaker to create the desired concrete factory which, in turn, will produce different concrete objects (Army, King, Castle).
|
The client can use `FactoryMaker` to create the desired concrete factory which, in turn, will produce different concrete objects (derived from `Army`, `King`, `Castle`).
|
||||||
In this example, we also used an enum to parameterize which type of kingdom factory the client will ask for.
|
In this example, we also used an enum to parameterize which type of kingdom factory the client will ask for.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@ -178,8 +191,8 @@ public static void main(String[] args) {
|
|||||||
|
|
||||||
Use the Abstract Factory pattern when
|
Use the Abstract Factory pattern when
|
||||||
|
|
||||||
* The system should be independent of how its products are created, composed and represented
|
* 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 system should be configured with one of the multiple families of products
|
||||||
* The family of related product objects is designed to be used together, and you need to enforce this constraint
|
* 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
|
* 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.
|
* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
|
||||||
@ -195,13 +208,13 @@ Example use cases
|
|||||||
* Unit test case writing becomes much easier
|
* Unit test case writing becomes much easier
|
||||||
* UI tools for different OS
|
* UI tools for different OS
|
||||||
|
|
||||||
## Consequences:
|
## 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.
|
* While the pattern is great when creating predefined objects, adding the new ones might be challenging.
|
||||||
* The code becomes 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
|
## Tutorials
|
||||||
|
|
||||||
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>abstract-factory</artifactId>
|
<artifactId>abstract-factory</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -37,7 +37,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*
|
*
|
||||||
* <p>The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory})
|
* <p>The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory})
|
||||||
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
|
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
|
||||||
* both concrete implementations to create a king, a castle and an army.
|
* both concrete implementations to create a king, a castle, and an army.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class App implements Runnable {
|
public class App implements Runnable {
|
||||||
@ -60,13 +60,13 @@ public class App implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOGGER.info("Elf Kingdom");
|
LOGGER.info("elf kingdom");
|
||||||
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
LOGGER.info(kingdom.getArmy().getDescription());
|
LOGGER.info(kingdom.getArmy().getDescription());
|
||||||
LOGGER.info(kingdom.getCastle().getDescription());
|
LOGGER.info(kingdom.getCastle().getDescription());
|
||||||
LOGGER.info(kingdom.getKing().getDescription());
|
LOGGER.info(kingdom.getKing().getDescription());
|
||||||
|
|
||||||
LOGGER.info("Orc Kingdom");
|
LOGGER.info("orc kingdom");
|
||||||
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
LOGGER.info(kingdom.getArmy().getDescription());
|
LOGGER.info(kingdom.getArmy().getDescription());
|
||||||
LOGGER.info(kingdom.getCastle().getDescription());
|
LOGGER.info(kingdom.getCastle().getDescription());
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
|||||||
*/
|
*/
|
||||||
public class ElfArmy implements Army {
|
public class ElfArmy implements Army {
|
||||||
|
|
||||||
static final String DESCRIPTION = "This is the Elven Army!";
|
static final String DESCRIPTION = "This is the elven army!";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
|||||||
*/
|
*/
|
||||||
public class ElfCastle implements Castle {
|
public class ElfCastle implements Castle {
|
||||||
|
|
||||||
static final String DESCRIPTION = "This is the Elven castle!";
|
static final String DESCRIPTION = "This is the elven castle!";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
|||||||
*/
|
*/
|
||||||
public class ElfKing implements King {
|
public class ElfKing implements King {
|
||||||
|
|
||||||
static final String DESCRIPTION = "This is the Elven king!";
|
static final String DESCRIPTION = "This is the elven king!";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
|||||||
*/
|
*/
|
||||||
public class OrcArmy implements Army {
|
public class OrcArmy implements Army {
|
||||||
|
|
||||||
static final String DESCRIPTION = "This is the Orc Army!";
|
static final String DESCRIPTION = "This is the orc army!";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
|||||||
*/
|
*/
|
||||||
public class OrcCastle implements Castle {
|
public class OrcCastle implements Castle {
|
||||||
|
|
||||||
static final String DESCRIPTION = "This is the Orc castle!";
|
static final String DESCRIPTION = "This is the orc castle!";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
|||||||
*/
|
*/
|
||||||
public class OrcKing implements King {
|
public class OrcKing implements King {
|
||||||
|
|
||||||
static final String DESCRIPTION = "This is the Orc king!";
|
static final String DESCRIPTION = "This is the orc king!";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -29,14 +29,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for abstract factory.
|
* Tests for abstract factory.
|
||||||
*/
|
*/
|
||||||
class AbstractFactoryTest {
|
class AbstractFactoryTest {
|
||||||
|
|
||||||
private final App app = new App();
|
private final App app = new App();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void king() {
|
void verifyKingCreation() {
|
||||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
final var kingdom = app.getKingdom();
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class AbstractFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void castle() {
|
void verifyCastleCreation() {
|
||||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
final var kingdom = app.getKingdom();
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ class AbstractFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void army() {
|
void verifyArmyCreation() {
|
||||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
final var kingdom = app.getKingdom();
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class AbstractFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createElfKingdom() {
|
void verifyElfKingdomCreation() {
|
||||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
final var kingdom = app.getKingdom();
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ class AbstractFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createOrcKingdom() {
|
void verifyOrcKingdomCreation() {
|
||||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
final var kingdom = app.getKingdom();
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
|
@ -28,10 +28,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issue: Add at least one assertion to this test case.
|
* Check whether the execution of the main method in {@link App} throws an exception.
|
||||||
*
|
|
||||||
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
|
|
||||||
* throws an exception.
|
|
||||||
*/
|
*/
|
||||||
class AppTest {
|
class AppTest {
|
||||||
|
|
||||||
|
@ -4,13 +4,14 @@ title: Active Object
|
|||||||
folder: active-object
|
folder: active-object
|
||||||
permalink: /patterns/active-object/
|
permalink: /patterns/active-object/
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Performance
|
- Performance
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests.
|
The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation, and a scheduler for handling requests.
|
||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ public abstract class ActiveCreature{
|
|||||||
requests.put(new Runnable() {
|
requests.put(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.info("{} has started to roam and the wastelands.",name());
|
logger.info("{} has started to roam the wastelands.",name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -81,7 +82,7 @@ public abstract class ActiveCreature{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We can see that any class that will extend the ActiveCreature class will have its own thread of control to execute and invocate methods.
|
We can see that any class that will extend the ActiveCreature class will have its own thread of control to invoke and execute methods.
|
||||||
|
|
||||||
For example, the Orc class:
|
For example, the Orc class:
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ public class Orc extends ActiveCreature {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, we can create multiple creatures such as Orcs, tell them to eat and roam and they will execute it on their own thread of control:
|
Now, we can create multiple creatures such as Orcs, tell them to eat and roam, and they will execute it on their own thread of control:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -122,4 +123,8 @@ Now, we can create multiple creatures such as Orcs, tell them to eat and roam an
|
|||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
* [Android and Java Concurrency: The Active Object Pattern](https://www.youtube.com/watch?v=Cd8t2u5Qmvc)
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>active-object</artifactId>
|
<artifactId>active-object</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -82,7 +82,7 @@ public abstract class ActiveCreature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roam in the wastelands.
|
* Roam the wastelands.
|
||||||
* @throws InterruptedException due to firing a new Runnable.
|
* @throws InterruptedException due to firing a new Runnable.
|
||||||
*/
|
*/
|
||||||
public void roam() throws InterruptedException {
|
public void roam() throws InterruptedException {
|
||||||
|
@ -4,6 +4,7 @@ title: Acyclic Visitor
|
|||||||
folder: acyclic-visitor
|
folder: acyclic-visitor
|
||||||
permalink: /patterns/acyclic-visitor/
|
permalink: /patterns/acyclic-visitor/
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Extensibility
|
- Extensibility
|
||||||
---
|
---
|
||||||
@ -137,6 +138,10 @@ This pattern can be used:
|
|||||||
* When the visited class hierarchy will be frequently extended with new derivatives of the Element class.
|
* When the visited class hierarchy will be frequently extended with new derivatives of the Element class.
|
||||||
* When the recompilation, relinking, retesting or redistribution of the derivatives of Element is very expensive.
|
* When the recompilation, relinking, retesting or redistribution of the derivatives of Element is very expensive.
|
||||||
|
|
||||||
|
## Tutorial
|
||||||
|
|
||||||
|
* [Acyclic Visitor Pattern Example](https://codecrafter.blogspot.com/2012/12/the-acyclic-visitor-pattern.html)
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
The good:
|
The good:
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -22,25 +23,19 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>acyclic-visitor</artifactId>
|
<artifactId>acyclic-visitor</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
|
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -29,7 +29,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
* Hayes class implements its accept method.
|
* Hayes class implements its accept method.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Hayes extends Modem {
|
public class Hayes implements Modem {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts all visitors but honors only HayesVisitor.
|
* Accepts all visitors but honors only HayesVisitor.
|
||||||
|
@ -24,8 +24,9 @@
|
|||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modem abstract class.
|
* //Modem abstract class.
|
||||||
|
* converted to an interface
|
||||||
*/
|
*/
|
||||||
public abstract class Modem {
|
public interface Modem {
|
||||||
public abstract void accept(ModemVisitor modemVisitor);
|
void accept(ModemVisitor modemVisitor);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
* Zoom class implements its accept method.
|
* Zoom class implements its accept method.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Zoom extends Modem {
|
public class Zoom implements Modem {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts all visitors but honors only ZoomVisitor.
|
* Accepts all visitors but honors only ZoomVisitor.
|
||||||
|
@ -4,6 +4,7 @@ title: Adapter
|
|||||||
folder: adapter
|
folder: adapter
|
||||||
permalink: /patterns/adapter/
|
permalink: /patterns/adapter/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Gang of Four
|
- Gang of Four
|
||||||
---
|
---
|
||||||
@ -17,10 +18,10 @@ couldn't otherwise because of incompatible interfaces.
|
|||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Real world example
|
Real-world example
|
||||||
|
|
||||||
> Consider that you have some pictures in your memory card and you need to transfer them to your computer. In order to transfer them you need some kind of adapter that is compatible with your computer ports so that you can attach memory card to your computer. In this case card reader is an adapter.
|
> Consider that you have some pictures on your memory card and you need to transfer them to your computer. To transfer them, you need some kind of adapter that is compatible with your computer ports so that you can attach a memory card to your computer. In this case card reader is an adapter.
|
||||||
> Another example would be the famous power adapter; a three legged plug can't be connected to a two pronged outlet, it needs to use a power adapter that makes it compatible with the two pronged outlet.
|
> Another example would be the famous power adapter; a three-legged plug can't be connected to a two-pronged outlet, it needs to use a power adapter that makes it compatible with the two-pronged outlets.
|
||||||
> Yet another example would be a translator translating words spoken by one person to another
|
> Yet another example would be a translator translating words spoken by one person to another
|
||||||
|
|
||||||
In plain words
|
In plain words
|
||||||
@ -35,7 +36,7 @@ Wikipedia says
|
|||||||
|
|
||||||
Consider a captain that can only use rowing boats and cannot sail at all.
|
Consider a captain that can only use rowing boats and cannot sail at all.
|
||||||
|
|
||||||
First we have interfaces `RowingBoat` and `FishingBoat`
|
First, we have interfaces `RowingBoat` and `FishingBoat`
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface RowingBoat {
|
public interface RowingBoat {
|
||||||
@ -67,7 +68,7 @@ public class Captain {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now let's say the pirates are coming and our captain needs to escape but there is only fishing boat available. We need to create an adapter that allows the captain to operate the fishing boat with his rowing boat skills.
|
Now let's say the pirates are coming and our captain needs to escape but there is only a fishing boat available. We need to create an adapter that allows the captain to operate the fishing boat with his rowing boat skills.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -99,25 +100,31 @@ captain.row();
|
|||||||
## Applicability
|
## Applicability
|
||||||
Use the Adapter pattern when
|
Use the Adapter pattern when
|
||||||
|
|
||||||
* you want to use an existing class, and its interface does not match the one you need
|
* You want to use an existing class, and its interface does not match the one you need
|
||||||
* you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces
|
* You want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces
|
||||||
* you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
|
* You need to use several existing subclasses, but it's impractical to adapt their interface by subclassing everyone. An object adapter can adapt the interface of its parent class.
|
||||||
* most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
|
* Most of the applications using third-party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
|
||||||
|
|
||||||
## Consequences:
|
## Tutorials
|
||||||
|
|
||||||
|
* [Dzone](https://dzone.com/articles/adapter-design-pattern-in-java)
|
||||||
|
* [Refactoring Guru](https://refactoring.guru/design-patterns/adapter/java/example)
|
||||||
|
* [Baeldung](https://www.baeldung.com/java-adapter-pattern)
|
||||||
|
|
||||||
|
## Consequences
|
||||||
Class and object adapters have different trade-offs. A class adapter
|
Class and object adapters have different trade-offs. A class adapter
|
||||||
|
|
||||||
* adapts Adaptee to Target by committing to a concrete Adaptee class. As a consequence, a class adapter won’t work when we want to adapt a class and all its subclasses.
|
* Adapts Adaptee to Target by committing to a concrete Adaptee class. As a consequence, a class adapter won’t work when we want to adapt a class and all its subclasses.
|
||||||
* let’s Adapter override some of Adaptee’s behavior, since Adapter is a subclass of Adaptee.
|
* Let’s Adapter override some of Adaptee’s behavior since Adapter is a subclass of Adaptee.
|
||||||
* introduces only one object, and no additional pointer indirection is needed to get to the adaptee.
|
* Introduces only one object, and no additional pointer indirection is needed to get to the adaptee.
|
||||||
|
|
||||||
An object adapter
|
An object adapter
|
||||||
|
|
||||||
* let’s a single Adapter work with many Adaptees—that is, the Adaptee itself and all of its subclasses (if any). The Adapter can also add functionality to all Adaptees at once.
|
* Lets a single Adapter work with many Adaptees—that is, the Adaptee itself and all of its subclasses (if any). The Adapter can also add functionality to all Adaptees at once.
|
||||||
* makes it harder to override Adaptee behavior. It will require subclassing Adaptee and making Adapter refer to the subclass rather than the Adaptee itself.
|
* Makes it harder to override Adaptee behavior. It will require subclassing Adaptee and making the Adapter refer to the subclass rather than the Adaptee itself.
|
||||||
|
|
||||||
|
|
||||||
## Real world examples
|
## Real-world examples
|
||||||
|
|
||||||
* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
|
* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
|
||||||
* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
|
* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>adapter</artifactId>
|
<artifactId>adapter</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -33,7 +33,7 @@ import static org.mockito.Mockito.spy;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class
|
* Tests for the adapter pattern.
|
||||||
*/
|
*/
|
||||||
class AdapterPatternTest {
|
class AdapterPatternTest {
|
||||||
|
|
||||||
|
@ -33,9 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|||||||
class AppTest {
|
class AppTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issue: Add at least one assertion to this test case.
|
* Check whether the execution of the main method in {@link App}
|
||||||
*
|
|
||||||
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
|
|
||||||
* throws an exception.
|
* throws an exception.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ title: Aggregator Microservices
|
|||||||
folder: aggregator-microservices
|
folder: aggregator-microservices
|
||||||
permalink: /patterns/aggregator-microservices/
|
permalink: /patterns/aggregator-microservices/
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Cloud distributed
|
- Cloud distributed
|
||||||
- Decoupling
|
- Decoupling
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>aggregator-service</artifactId>
|
<artifactId>aggregator-service</artifactId>
|
||||||
@ -54,7 +52,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -48,7 +48,7 @@ class AggregatorTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,19 +23,15 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>information-microservice</artifactId>
|
<artifactId>information-microservice</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
@ -51,7 +47,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -23,17 +23,14 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>inventory-microservice</artifactId>
|
<artifactId>inventory-microservice</artifactId>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -50,7 +47,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
|
@ -4,6 +4,7 @@ title: Ambassador
|
|||||||
folder: ambassador
|
folder: ambassador
|
||||||
permalink: /patterns/ambassador/
|
permalink: /patterns/ambassador/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
- Cloud distributed
|
- Cloud distributed
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>ambassador</artifactId>
|
<artifactId>ambassador</artifactId>
|
||||||
|
@ -4,6 +4,7 @@ title: API Gateway
|
|||||||
folder: api-gateway
|
folder: api-gateway
|
||||||
permalink: /patterns/api-gateway/
|
permalink: /patterns/api-gateway/
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Cloud distributed
|
- Cloud distributed
|
||||||
- Decoupling
|
- Decoupling
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>api-gateway-service</artifactId>
|
<artifactId>api-gateway-service</artifactId>
|
||||||
@ -54,7 +52,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -48,7 +48,7 @@ class ApiGatewayTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>image-microservice</artifactId>
|
<artifactId>image-microservice</artifactId>
|
||||||
@ -49,7 +47,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
|
@ -23,19 +23,15 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>price-microservice</artifactId>
|
<artifactId>price-microservice</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
@ -51,7 +47,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -4,6 +4,7 @@ title: Arrange/Act/Assert
|
|||||||
folder: arrange-act-assert
|
folder: arrange-act-assert
|
||||||
permalink: /patterns/arrange-act-assert/
|
permalink: /patterns/arrange-act-assert/
|
||||||
categories: Idiom
|
categories: Idiom
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Testing
|
- Testing
|
||||||
---
|
---
|
||||||
|
@ -23,16 +23,13 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>arrange-act-assert</artifactId>
|
<artifactId>arrange-act-assert</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
Before Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 100 B |
Before Width: | Height: | Size: 413 B |
Before Width: | Height: | Size: 802 B |
@ -4,6 +4,7 @@ title: Async Method Invocation
|
|||||||
folder: async-method-invocation
|
folder: async-method-invocation
|
||||||
permalink: /patterns/async-method-invocation/
|
permalink: /patterns/async-method-invocation/
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Reactive
|
- Reactive
|
||||||
---
|
---
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>async-method-invocation</artifactId>
|
<artifactId>async-method-invocation</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -59,9 +59,12 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
|
private static final String ROCKET_LAUNCH_LOG_PATTERN = "Space rocket <%s> launched successfully";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point.
|
* Program entry point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// construct a new executor that will run async tasks
|
// construct a new executor that will run async tasks
|
||||||
var executor = new ThreadAsyncExecutor();
|
var executor = new ThreadAsyncExecutor();
|
||||||
@ -87,9 +90,9 @@ public class App {
|
|||||||
asyncResult5.await();
|
asyncResult5.await();
|
||||||
|
|
||||||
// log the results of the tasks, callbacks log immediately when complete
|
// log the results of the tasks, callbacks log immediately when complete
|
||||||
log("Space rocket <" + result1 + "> launch complete");
|
log(String.format(ROCKET_LAUNCH_LOG_PATTERN, result1));
|
||||||
log("Space rocket <" + result2 + "> launch complete");
|
log(String.format(ROCKET_LAUNCH_LOG_PATTERN, result2));
|
||||||
log("Space rocket <" + result3 + "> launch complete");
|
log(String.format(ROCKET_LAUNCH_LOG_PATTERN, result3));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +105,7 @@ public class App {
|
|||||||
private static <T> Callable<T> lazyval(T value, long delayMillis) {
|
private static <T> Callable<T> lazyval(T value, long delayMillis) {
|
||||||
return () -> {
|
return () -> {
|
||||||
Thread.sleep(delayMillis);
|
Thread.sleep(delayMillis);
|
||||||
log("Space rocket <" + value + "> launched successfully");
|
log(String.format(ROCKET_LAUNCH_LOG_PATTERN, value));
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,24 +4,137 @@ title: Balking
|
|||||||
folder: balking
|
folder: balking
|
||||||
permalink: /patterns/balking/
|
permalink: /patterns/balking/
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Balking Pattern is used to prevent an object from executing certain code if it is an
|
|
||||||
incomplete or inappropriate state
|
Balking Pattern is used to prevent an object from executing a certain code if it is in an incomplete
|
||||||
|
or inappropriate state.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> There's a start-button in a washing machine to initiate the laundry washing. When the washing
|
||||||
|
> machine is inactive the button works as expected, but if it's already washing the button does
|
||||||
|
> nothing.
|
||||||
|
|
||||||
|
In plain words
|
||||||
|
|
||||||
|
> Using the balking pattern, a certain code executes only if the object is in particular state.
|
||||||
|
|
||||||
|
Wikipedia says
|
||||||
|
|
||||||
|
> The balking pattern is a software design pattern that only executes an action on an object when
|
||||||
|
> the object is in a particular state. For example, if an object reads ZIP files and a calling
|
||||||
|
> method invokes a get method on the object when the ZIP file is not open, the object would "balk"
|
||||||
|
> at the request.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
In this example implementation, `WashingMachine` is an object that has two states in which it can
|
||||||
|
be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING using a thread-safe
|
||||||
|
method. On the other hand, if it already has been washing and any other thread executes `wash()`
|
||||||
|
it won't do that and returns without doing anything.
|
||||||
|
|
||||||
|
Here are the relevant parts of the `WashingMachine` class.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public class WashingMachine {
|
||||||
|
|
||||||
|
private final DelayProvider delayProvider;
|
||||||
|
private WashingMachineState washingMachineState;
|
||||||
|
|
||||||
|
public WashingMachine(DelayProvider delayProvider) {
|
||||||
|
this.delayProvider = delayProvider;
|
||||||
|
this.washingMachineState = WashingMachineState.ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WashingMachineState getWashingMachineState() {
|
||||||
|
return washingMachineState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void wash() {
|
||||||
|
synchronized (this) {
|
||||||
|
var machineState = getWashingMachineState();
|
||||||
|
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
|
||||||
|
if (this.washingMachineState == WashingMachineState.WASHING) {
|
||||||
|
LOGGER.error("Cannot wash if the machine has been already washing!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.washingMachineState = WashingMachineState.WASHING;
|
||||||
|
}
|
||||||
|
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
|
||||||
|
this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void endOfWashing() {
|
||||||
|
washingMachineState = WashingMachineState.ENABLED;
|
||||||
|
LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here's the simple `DelayProvider` interface used by the `WashingMachine`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface DelayProvider {
|
||||||
|
void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we introduce the application using the `WashingMachine`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static void main(String... args) {
|
||||||
|
final var washingMachine = new WashingMachine();
|
||||||
|
var executorService = Executors.newFixedThreadPool(3);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
executorService.execute(washingMachine::wash);
|
||||||
|
}
|
||||||
|
executorService.shutdown();
|
||||||
|
try {
|
||||||
|
executorService.awaitTermination(10, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
LOGGER.error("ERROR: Waiting on executor service shutdown!");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is the console output of the program.
|
||||||
|
|
||||||
|
```
|
||||||
|
14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
|
||||||
|
14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing
|
||||||
|
14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING
|
||||||
|
14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
|
||||||
|
14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING
|
||||||
|
14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
|
||||||
|
14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed.
|
||||||
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Balking pattern when
|
Use the Balking pattern when
|
||||||
|
|
||||||
* you want to invoke an action on an object only when it is in a particular state
|
* You want to invoke an action on an object only when it is in a particular state
|
||||||
* objects are generally only in a state that is prone to balking temporarily
|
* Objects are generally only in a state that is prone to balking temporarily but for an unknown
|
||||||
but for an unknown amount of time
|
amount of time
|
||||||
|
|
||||||
## Related patterns
|
## Related patterns
|
||||||
* Guarded Suspension Pattern
|
|
||||||
* Double Checked Locking Pattern
|
* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/)
|
||||||
|
* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99)
|
||||||
|
@ -23,16 +23,13 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>balking</artifactId>
|
<artifactId>balking</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -32,11 +32,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
* then the method will return without doing anything. Objects that use this pattern are generally
|
* then the method will return without doing anything. Objects that use this pattern are generally
|
||||||
* only in a state that is prone to balking temporarily but for an unknown amount of time
|
* only in a state that is prone to balking temporarily but for an unknown amount of time
|
||||||
*
|
*
|
||||||
* <p>In this example implementation WashingMachine is an object that has two states in which it
|
* <p>In this example implementation, {@link WashingMachine} is an object that has two states in
|
||||||
* can be: ENABLED and WASHING. If the machine is ENABLED the state is changed into WASHING that any
|
* which it can be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING
|
||||||
* other thread can't invoke this action on this and then do the job. On the other hand if it have
|
* using a thread-safe method. On the other hand, if it already has been washing and any other
|
||||||
* been already washing and any other thread execute wash() it can't do that once again and returns
|
* thread executes {@link WashingMachine#wash()} it won't do that and returns without doing
|
||||||
* doing nothing.
|
* anything.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class App {
|
public class App {
|
||||||
@ -54,11 +54,12 @@ public class App {
|
|||||||
}
|
}
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
try {
|
try {
|
||||||
executorService.awaitTermination(10, TimeUnit.SECONDS);
|
if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
|
||||||
|
executorService.shutdownNow();
|
||||||
|
}
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
LOGGER.error("ERROR: Waiting on executor service shutdown!");
|
LOGGER.error("ERROR: Waiting on executor service shutdown!");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ title: Bridge
|
|||||||
folder: bridge
|
folder: bridge
|
||||||
permalink: /patterns/bridge/
|
permalink: /patterns/bridge/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Gang of Four
|
- Gang of Four
|
||||||
---
|
---
|
||||||
@ -18,7 +19,7 @@ Decouple an abstraction from its implementation so that the two can vary indepen
|
|||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Real world example
|
Real-world example
|
||||||
|
|
||||||
> Consider you have a weapon with different enchantments, and you are supposed to allow mixing
|
> 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
|
> different weapons with different enchantments. What would you do? Create multiple copies of each
|
||||||
@ -160,27 +161,36 @@ public class SoulEatingEnchantment implements Enchantment {
|
|||||||
Here are both hierarchies in action:
|
Here are both hierarchies in action:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
LOGGER.info("The knight receives an enchanted sword.");
|
||||||
var enchantedSword = new Sword(new SoulEatingEnchantment());
|
var enchantedSword = new Sword(new SoulEatingEnchantment());
|
||||||
enchantedSword.wield();
|
enchantedSword.wield();
|
||||||
enchantedSword.swing();
|
enchantedSword.swing();
|
||||||
enchantedSword.unwield();
|
enchantedSword.unwield();
|
||||||
// The sword is wielded.
|
|
||||||
// The item spreads bloodlust.
|
|
||||||
// The sword is swinged.
|
|
||||||
// The item eats the soul of enemies.
|
|
||||||
// The sword is unwielded.
|
|
||||||
// Bloodlust slowly disappears.
|
|
||||||
|
|
||||||
|
LOGGER.info("The valkyrie receives an enchanted hammer.");
|
||||||
var hammer = new Hammer(new FlyingEnchantment());
|
var hammer = new Hammer(new FlyingEnchantment());
|
||||||
hammer.wield();
|
hammer.wield();
|
||||||
hammer.swing();
|
hammer.swing();
|
||||||
hammer.unwield();
|
hammer.unwield();
|
||||||
// The hammer is wielded.
|
```
|
||||||
// The item begins to glow faintly.
|
|
||||||
// The hammer is swinged.
|
Here's the console output.
|
||||||
// The item flies and strikes the enemies finally returning to owner's hand.
|
|
||||||
// The hammer is unwielded.
|
```
|
||||||
// The item's glow fades.
|
The knight receives an enchanted sword.
|
||||||
|
The sword is wielded.
|
||||||
|
The item spreads bloodlust.
|
||||||
|
The sword is swung.
|
||||||
|
The item eats the soul of enemies.
|
||||||
|
The sword is unwielded.
|
||||||
|
Bloodlust slowly disappears.
|
||||||
|
The valkyrie receives an enchanted hammer.
|
||||||
|
The hammer is wielded.
|
||||||
|
The item begins to glow faintly.
|
||||||
|
The hammer is swung.
|
||||||
|
The item flies and strikes the enemies finally returning to owner's hand.
|
||||||
|
The hammer is unwielded.
|
||||||
|
The item's glow fades.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bridge</artifactId>
|
<artifactId>bridge</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -43,7 +43,7 @@ public class Hammer implements Weapon {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void swing() {
|
public void swing() {
|
||||||
LOGGER.info("The hammer is swinged.");
|
LOGGER.info("The hammer is swung.");
|
||||||
enchantment.apply();
|
enchantment.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class Sword implements Weapon {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void swing() {
|
public void swing() {
|
||||||
LOGGER.info("The sword is swinged.");
|
LOGGER.info("The sword is swung.");
|
||||||
enchantment.apply();
|
enchantment.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ title: Builder
|
|||||||
folder: builder
|
folder: builder
|
||||||
permalink: /patterns/builder/
|
permalink: /patterns/builder/
|
||||||
categories: Creational
|
categories: Creational
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Gang of Four
|
- Gang of Four
|
||||||
---
|
---
|
||||||
@ -15,11 +16,11 @@ process can create different representations.
|
|||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Real world example
|
Real-world example
|
||||||
|
|
||||||
> Imagine a character generator for a role-playing game. The easiest option is to let the computer
|
> 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
|
> 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
|
> profession, gender, hair color, etc. the character generation becomes a step-by-step process that
|
||||||
> completes when all the selections are ready.
|
> completes when all the selections are ready.
|
||||||
|
|
||||||
In plain words
|
In plain words
|
||||||
@ -48,7 +49,7 @@ anti-pattern.
|
|||||||
|
|
||||||
**Programmatic Example**
|
**Programmatic Example**
|
||||||
|
|
||||||
The sane alternative is to use the Builder pattern. First of all we have our hero that we want to
|
The sane alternative is to use the Builder pattern. First of all, we have our hero that we want to
|
||||||
create:
|
create:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@ -133,7 +134,13 @@ 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 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 construction process must allow different representations for the object that's constructed
|
||||||
|
|
||||||
## Real world examples
|
## Tutorials
|
||||||
|
|
||||||
|
* [Refactoring Guru](https://refactoring.guru/design-patterns/builder)
|
||||||
|
* [Oracle Blog](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java)
|
||||||
|
* [Journal Dev](https://www.journaldev.com/1425/builder-design-pattern-in-java)
|
||||||
|
|
||||||
|
## Known uses
|
||||||
|
|
||||||
* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
|
* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
|
||||||
* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) as well as similar buffers such as FloatBuffer, IntBuffer and so on.
|
* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) as well as similar buffers such as FloatBuffer, IntBuffer and so on.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>builder</artifactId>
|
<artifactId>builder</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -4,26 +4,162 @@ title: Business Delegate
|
|||||||
folder: business-delegate
|
folder: business-delegate
|
||||||
permalink: /patterns/business-delegate/
|
permalink: /patterns/business-delegate/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
The Business Delegate pattern adds an abstraction layer between
|
The Business Delegate pattern adds an abstraction layer between
|
||||||
presentation and business tiers. By using the pattern we gain loose coupling
|
presentation and business tiers. By using the pattern we gain loose coupling
|
||||||
between the tiers and encapsulate knowledge about how to locate, connect to,
|
between the tiers and encapsulate knowledge about how to locate, connect to,
|
||||||
and interact with the business objects that make up the application.
|
and interact with the business objects that make up the application.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> A mobile phone application promises to stream any movie in existence to your phone. It captures
|
||||||
|
> the user's search string and passes this on to the business delegate. The business delegate
|
||||||
|
> selects the most suitable video streaming service and plays the video from there.
|
||||||
|
|
||||||
|
In Plain Words
|
||||||
|
|
||||||
|
> Business delegate adds an abstraction layer between the presentation and business tiers.
|
||||||
|
|
||||||
|
Wikipedia says
|
||||||
|
|
||||||
|
> Business delegate is a Java EE design pattern. This pattern is directing to reduce the coupling
|
||||||
|
> in between business services and the connected presentation tier, and to hide the implementation
|
||||||
|
> details of services (including lookup and accessibility of EJB architecture). Business delegates
|
||||||
|
> acts as an adaptor to invoke business objects from the presentation tier.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
First, we have an abstraction for video streaming services and a couple of implementations.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface VideoStreamingService {
|
||||||
|
void doProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class NetflixService implements VideoStreamingService {
|
||||||
|
@Override
|
||||||
|
public void doProcessing() {
|
||||||
|
LOGGER.info("NetflixService is now processing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class YouTubeService implements VideoStreamingService {
|
||||||
|
@Override
|
||||||
|
public void doProcessing() {
|
||||||
|
LOGGER.info("YouTubeService is now processing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then we have a lookup service that decides which video streaming service is used.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Setter
|
||||||
|
public class BusinessLookup {
|
||||||
|
|
||||||
|
private NetflixService netflixService;
|
||||||
|
private YouTubeService youTubeService;
|
||||||
|
|
||||||
|
public VideoStreamingService getBusinessService(String movie) {
|
||||||
|
if (movie.toLowerCase(Locale.ROOT).contains("die hard")) {
|
||||||
|
return netflixService;
|
||||||
|
} else {
|
||||||
|
return youTubeService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The business delegate uses a business lookup to route movie playback requests to a suitable
|
||||||
|
video streaming service.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Setter
|
||||||
|
public class BusinessDelegate {
|
||||||
|
|
||||||
|
private BusinessLookup lookupService;
|
||||||
|
|
||||||
|
public void playbackMovie(String movie) {
|
||||||
|
VideoStreamingService videoStreamingService = lookupService.getBusinessService(movie);
|
||||||
|
videoStreamingService.doProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The mobile client utilizes business delegate to call the business tier.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class MobileClient {
|
||||||
|
|
||||||
|
private final BusinessDelegate businessDelegate;
|
||||||
|
|
||||||
|
public MobileClient(BusinessDelegate businessDelegate) {
|
||||||
|
this.businessDelegate = businessDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playbackMovie(String movie) {
|
||||||
|
businessDelegate.playbackMovie(movie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, we can show the full example in action.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// prepare the objects
|
||||||
|
var businessDelegate = new BusinessDelegate();
|
||||||
|
var businessLookup = new BusinessLookup();
|
||||||
|
businessLookup.setNetflixService(new NetflixService());
|
||||||
|
businessLookup.setYouTubeService(new YouTubeService());
|
||||||
|
businessDelegate.setLookupService(businessLookup);
|
||||||
|
|
||||||
|
// create the client and use the business delegate
|
||||||
|
var client = new MobileClient(businessDelegate);
|
||||||
|
client.playbackMovie("Die Hard 2");
|
||||||
|
client.playbackMovie("Maradona: The Greatest Ever");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is the console output.
|
||||||
|
|
||||||
|
```
|
||||||
|
21:15:33.790 [main] INFO com.iluwatar.business.delegate.NetflixService - NetflixService is now processing
|
||||||
|
21:15:33.794 [main] INFO com.iluwatar.business.delegate.YouTubeService - YouTubeService is now processing
|
||||||
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
|
## Related patterns
|
||||||
|
|
||||||
|
* [Service locator pattern](https://java-design-patterns.com/patterns/service-locator/)
|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Business Delegate pattern when
|
Use the Business Delegate pattern when
|
||||||
|
|
||||||
* you want loose coupling between presentation and business tiers
|
* You want loose coupling between presentation and business tiers
|
||||||
* you want to orchestrate calls to multiple business services
|
* You want to orchestrate calls to multiple business services
|
||||||
* you want to encapsulate service lookups and service calls
|
* You want to encapsulate service lookups and service calls
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
* [Business Delegate Pattern at TutorialsPoint](https://www.tutorialspoint.com/design_pattern/business_delegate_pattern.htm)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
||||||
|
* [Core J2EE Patterns: Best Practices and Design Strategies](https://www.amazon.com/gp/product/0130648841/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0130648841&linkId=a0100de2b28c71ede8db1757fb2b5947)
|
||||||
|
Before Width: | Height: | Size: 24 KiB |
@ -1,136 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
|
||||||
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
|
|
||||||
<class id="1" language="java" name="com.iluwatar.business.delegate.BusinessDelegate" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="272" y="219"/>
|
|
||||||
<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="2" language="java" name="com.iluwatar.business.delegate.Client" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="272" y="64"/>
|
|
||||||
<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>
|
|
||||||
<enumeration id="3" language="java" name="com.iluwatar.business.delegate.ServiceType" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="89" y="383"/>
|
|
||||||
<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>
|
|
||||||
</enumeration>
|
|
||||||
<interface id="4" language="java" name="com.iluwatar.business.delegate.BusinessService" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="630" y="365"/>
|
|
||||||
<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="5" language="java" name="com.iluwatar.business.delegate.JmsService" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="489" y="210"/>
|
|
||||||
<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="6" language="java" name="com.iluwatar.business.delegate.BusinessLookup" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="360" y="399"/>
|
|
||||||
<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="7" language="java" name="com.iluwatar.business.delegate.EjbService" project="business-delegate"
|
|
||||||
file="/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="668" y="210"/>
|
|
||||||
<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>
|
|
||||||
<realization id="8">
|
|
||||||
<end type="SOURCE" refId="7"/>
|
|
||||||
<end type="TARGET" refId="4"/>
|
|
||||||
</realization>
|
|
||||||
<association id="9">
|
|
||||||
<end type="SOURCE" refId="1" navigable="false">
|
|
||||||
<attribute id="10" name="lookupService">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</attribute>
|
|
||||||
<multiplicity id="11" minimum="0" maximum="1">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</multiplicity>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="6" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<association id="12">
|
|
||||||
<end type="SOURCE" refId="1" navigable="false">
|
|
||||||
<attribute id="13" name="serviceType">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</attribute>
|
|
||||||
<multiplicity id="14" minimum="0" maximum="1">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</multiplicity>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="3" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<realization id="15">
|
|
||||||
<end type="SOURCE" refId="5"/>
|
|
||||||
<end type="TARGET" refId="4"/>
|
|
||||||
</realization>
|
|
||||||
<association id="16">
|
|
||||||
<end type="SOURCE" refId="2" navigable="false">
|
|
||||||
<attribute id="17" name="businessDelegate">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</attribute>
|
|
||||||
<multiplicity id="18" minimum="0" maximum="1">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</multiplicity>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="1" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<association id="19">
|
|
||||||
<end type="SOURCE" refId="1" navigable="false">
|
|
||||||
<attribute id="20" name="businessService">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</attribute>
|
|
||||||
<multiplicity id="21" minimum="0" maximum="1">
|
|
||||||
<position height="0" width="0" x="0" y="0"/>
|
|
||||||
</multiplicity>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="4" navigable="true"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<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>
|
|
BIN
business-delegate/etc/business-delegate.urm.png
Normal file
After Width: | Height: | Size: 49 KiB |
@ -5,53 +5,42 @@ package com.iluwatar.business.delegate {
|
|||||||
+ main(args : String[]) {static}
|
+ main(args : String[]) {static}
|
||||||
}
|
}
|
||||||
class BusinessDelegate {
|
class BusinessDelegate {
|
||||||
- businessService : BusinessService
|
|
||||||
- lookupService : BusinessLookup
|
- lookupService : BusinessLookup
|
||||||
- serviceType : ServiceType
|
|
||||||
+ BusinessDelegate()
|
+ BusinessDelegate()
|
||||||
+ doTask()
|
+ playbackMovie(movie : String)
|
||||||
+ setLookupService(businessLookup : BusinessLookup)
|
+ setLookupService(lookupService : BusinessLookup)
|
||||||
+ setServiceType(serviceType : ServiceType)
|
|
||||||
}
|
}
|
||||||
class BusinessLookup {
|
class BusinessLookup {
|
||||||
- ejbService : EjbService
|
- netflixService : NetflixService
|
||||||
- jmsService : JmsService
|
- youTubeService : YouTubeService
|
||||||
+ BusinessLookup()
|
+ BusinessLookup()
|
||||||
+ getBusinessService(serviceType : ServiceType) : BusinessService
|
+ getBusinessService(movie : String) : VideoStreamingService
|
||||||
+ setEjbService(ejbService : EjbService)
|
+ setNetflixService(netflixService : NetflixService)
|
||||||
+ setJmsService(jmsService : JmsService)
|
+ setYouTubeService(youTubeService : YouTubeService)
|
||||||
}
|
}
|
||||||
interface BusinessService {
|
class MobileClient {
|
||||||
|
- businessDelegate : BusinessDelegate
|
||||||
|
+ MobileClient(businessDelegate : BusinessDelegate)
|
||||||
|
+ playbackMovie(movie : String)
|
||||||
|
}
|
||||||
|
class NetflixService {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ NetflixService()
|
||||||
|
+ doProcessing()
|
||||||
|
}
|
||||||
|
interface VideoStreamingService {
|
||||||
+ doProcessing() {abstract}
|
+ doProcessing() {abstract}
|
||||||
}
|
}
|
||||||
class Client {
|
class YouTubeService {
|
||||||
- businessDelegate : BusinessDelegate
|
|
||||||
+ Client(businessDelegate : BusinessDelegate)
|
|
||||||
+ doTask()
|
|
||||||
}
|
|
||||||
class EjbService {
|
|
||||||
- LOGGER : Logger {static}
|
- LOGGER : Logger {static}
|
||||||
+ EjbService()
|
+ YouTubeService()
|
||||||
+ doProcessing()
|
+ doProcessing()
|
||||||
}
|
}
|
||||||
class JmsService {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ JmsService()
|
|
||||||
+ doProcessing()
|
|
||||||
}
|
}
|
||||||
enum ServiceType {
|
BusinessLookup --> "-netflixService" NetflixService
|
||||||
+ EJB {static}
|
BusinessLookup --> "-youTubeService" YouTubeService
|
||||||
+ JMS {static}
|
MobileClient --> "-businessDelegate" BusinessDelegate
|
||||||
+ valueOf(name : String) : ServiceType {static}
|
|
||||||
+ values() : ServiceType[] {static}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BusinessLookup --> "-ejbService" EjbService
|
|
||||||
BusinessDelegate --> "-serviceType" ServiceType
|
|
||||||
Client --> "-businessDelegate" BusinessDelegate
|
|
||||||
BusinessDelegate --> "-businessService" BusinessService
|
|
||||||
BusinessDelegate --> "-lookupService" BusinessLookup
|
BusinessDelegate --> "-lookupService" BusinessLookup
|
||||||
BusinessLookup --> "-jmsService" JmsService
|
NetflixService ..|> VideoStreamingService
|
||||||
EjbService ..|> BusinessService
|
YouTubeService ..|> VideoStreamingService
|
||||||
JmsService ..|> BusinessService
|
|
||||||
@enduml
|
@enduml
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,15 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>business-delegate</artifactId>
|
<artifactId>business-delegate</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -33,9 +33,9 @@ package com.iluwatar.business.delegate;
|
|||||||
* retrieved through service lookups. The Business Delegate itself may contain business logic too
|
* retrieved through service lookups. The Business Delegate itself may contain business logic too
|
||||||
* potentially tying together multiple service calls, exception handling, retrying etc.
|
* potentially tying together multiple service calls, exception handling, retrying etc.
|
||||||
*
|
*
|
||||||
* <p>In this example the client ({@link Client}) utilizes a business delegate (
|
* <p>In this example the client ({@link MobileClient}) utilizes a business delegate (
|
||||||
* {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
|
* {@link BusinessDelegate}) to search for movies in video streaming services. The Business Delegate
|
||||||
* service and makes the service call.
|
* then selects the appropriate service and makes the service call.
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
@ -46,18 +46,16 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// prepare the objects
|
||||||
var businessDelegate = new BusinessDelegate();
|
var businessDelegate = new BusinessDelegate();
|
||||||
var businessLookup = new BusinessLookup();
|
var businessLookup = new BusinessLookup();
|
||||||
businessLookup.setEjbService(new EjbService());
|
businessLookup.setNetflixService(new NetflixService());
|
||||||
businessLookup.setJmsService(new JmsService());
|
businessLookup.setYouTubeService(new YouTubeService());
|
||||||
|
|
||||||
businessDelegate.setLookupService(businessLookup);
|
businessDelegate.setLookupService(businessLookup);
|
||||||
businessDelegate.setServiceType(ServiceType.EJB);
|
|
||||||
|
|
||||||
var client = new Client(businessDelegate);
|
// create the client and use the business delegate
|
||||||
client.doTask();
|
var client = new MobileClient(businessDelegate);
|
||||||
|
client.playbackMovie("Die Hard 2");
|
||||||
businessDelegate.setServiceType(ServiceType.JMS);
|
client.playbackMovie("Maradona: The Greatest Ever");
|
||||||
client.doTask();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,24 +23,18 @@
|
|||||||
|
|
||||||
package com.iluwatar.business.delegate;
|
package com.iluwatar.business.delegate;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BusinessDelegate separates the presentation and business tiers.
|
* BusinessDelegate separates the presentation and business tiers.
|
||||||
*/
|
*/
|
||||||
|
@Setter
|
||||||
public class BusinessDelegate {
|
public class BusinessDelegate {
|
||||||
|
|
||||||
private BusinessLookup lookupService;
|
private BusinessLookup lookupService;
|
||||||
private ServiceType serviceType;
|
|
||||||
|
|
||||||
public void setLookupService(BusinessLookup businessLookup) {
|
public void playbackMovie(String movie) {
|
||||||
this.lookupService = businessLookup;
|
VideoStreamingService videoStreamingService = lookupService.getBusinessService(movie);
|
||||||
}
|
videoStreamingService.doProcessing();
|
||||||
|
|
||||||
public void setServiceType(ServiceType serviceType) {
|
|
||||||
this.serviceType = serviceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doTask() {
|
|
||||||
BusinessService businessService = lookupService.getBusinessService(serviceType);
|
|
||||||
businessService.doProcessing();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
package com.iluwatar.business.delegate;
|
package com.iluwatar.business.delegate;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,21 +32,21 @@ import lombok.Setter;
|
|||||||
@Setter
|
@Setter
|
||||||
public class BusinessLookup {
|
public class BusinessLookup {
|
||||||
|
|
||||||
private EjbService ejbService;
|
private NetflixService netflixService;
|
||||||
|
|
||||||
private JmsService jmsService;
|
private YouTubeService youTubeService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets service instance based on service type.
|
* Gets service instance based on given movie search string.
|
||||||
*
|
*
|
||||||
* @param serviceType Type of service instance to be returned.
|
* @param movie Search string for the movie.
|
||||||
* @return Service instance.
|
* @return Service instance.
|
||||||
*/
|
*/
|
||||||
public BusinessService getBusinessService(ServiceType serviceType) {
|
public VideoStreamingService getBusinessService(String movie) {
|
||||||
if (serviceType.equals(ServiceType.EJB)) {
|
if (movie.toLowerCase(Locale.ROOT).contains("die hard")) {
|
||||||
return ejbService;
|
return netflixService;
|
||||||
} else {
|
} else {
|
||||||
return jmsService;
|
return youTubeService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,17 +24,17 @@
|
|||||||
package com.iluwatar.business.delegate;
|
package com.iluwatar.business.delegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client utilizes BusinessDelegate to call the business tier.
|
* MobileClient utilizes BusinessDelegate to call the business tier.
|
||||||
*/
|
*/
|
||||||
public class Client {
|
public class MobileClient {
|
||||||
|
|
||||||
private final BusinessDelegate businessDelegate;
|
private final BusinessDelegate businessDelegate;
|
||||||
|
|
||||||
public Client(BusinessDelegate businessDelegate) {
|
public MobileClient(BusinessDelegate businessDelegate) {
|
||||||
this.businessDelegate = businessDelegate;
|
this.businessDelegate = businessDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doTask() {
|
public void playbackMovie(String movie) {
|
||||||
businessDelegate.doTask();
|
businessDelegate.playbackMovie(movie);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,13 +26,13 @@ package com.iluwatar.business.delegate;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service EJB implementation.
|
* NetflixService implementation.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class EjbService implements BusinessService {
|
public class NetflixService implements VideoStreamingService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doProcessing() {
|
public void doProcessing() {
|
||||||
LOGGER.info("EjbService is now processing");
|
LOGGER.info("NetflixService is now processing");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,9 +24,9 @@
|
|||||||
package com.iluwatar.business.delegate;
|
package com.iluwatar.business.delegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for service implementations.
|
* Interface for video streaming service implementations.
|
||||||
*/
|
*/
|
||||||
public interface BusinessService {
|
public interface VideoStreamingService {
|
||||||
|
|
||||||
void doProcessing();
|
void doProcessing();
|
||||||
}
|
}
|
@ -26,13 +26,13 @@ package com.iluwatar.business.delegate;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service JMS implementation.
|
* YouTubeService implementation.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JmsService implements BusinessService {
|
public class YouTubeService implements VideoStreamingService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doProcessing() {
|
public void doProcessing() {
|
||||||
LOGGER.info("JmsService is now processing");
|
LOGGER.info("YouTubeService is now processing");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,25 +26,20 @@ package com.iluwatar.business.delegate;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Business Delegate pattern adds an abstraction layer between the presentation and business
|
* Tests for the {@link BusinessDelegate}
|
||||||
* tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
|
|
||||||
* encapsulates knowledge about how to locate, connect to, and interact with the business objects
|
|
||||||
* that make up the application.
|
|
||||||
*
|
|
||||||
* <p>Some of the services the Business Delegate uses are instantiated directly, and some can be
|
|
||||||
* retrieved through service lookups. The Business Delegate itself may contain business logic too
|
|
||||||
* potentially tying together multiple service calls, exception handling, retrying etc.
|
|
||||||
*/
|
*/
|
||||||
class BusinessDelegateTest {
|
class BusinessDelegateTest {
|
||||||
|
|
||||||
private EjbService ejbService;
|
private NetflixService netflixService;
|
||||||
|
|
||||||
private JmsService jmsService;
|
private YouTubeService youTubeService;
|
||||||
|
|
||||||
private BusinessDelegate businessDelegate;
|
private BusinessDelegate businessDelegate;
|
||||||
|
|
||||||
@ -54,19 +49,19 @@ class BusinessDelegateTest {
|
|||||||
*/
|
*/
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
ejbService = spy(new EjbService());
|
netflixService = spy(new NetflixService());
|
||||||
jmsService = spy(new JmsService());
|
youTubeService = spy(new YouTubeService());
|
||||||
|
|
||||||
BusinessLookup businessLookup = spy(new BusinessLookup());
|
BusinessLookup businessLookup = spy(new BusinessLookup());
|
||||||
businessLookup.setEjbService(ejbService);
|
businessLookup.setNetflixService(netflixService);
|
||||||
businessLookup.setJmsService(jmsService);
|
businessLookup.setYouTubeService(youTubeService);
|
||||||
|
|
||||||
businessDelegate = spy(new BusinessDelegate());
|
businessDelegate = spy(new BusinessDelegate());
|
||||||
businessDelegate.setLookupService(businessLookup);
|
businessDelegate.setLookupService(businessLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this example the client ({@link Client}) utilizes a business delegate (
|
* In this example the client ({@link MobileClient}) utilizes a business delegate (
|
||||||
* {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
|
* {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
|
||||||
* service and makes the service call.
|
* service and makes the service call.
|
||||||
*/
|
*/
|
||||||
@ -74,26 +69,20 @@ class BusinessDelegateTest {
|
|||||||
void testBusinessDelegate() {
|
void testBusinessDelegate() {
|
||||||
|
|
||||||
// setup a client object
|
// setup a client object
|
||||||
var client = new Client(businessDelegate);
|
var client = new MobileClient(businessDelegate);
|
||||||
|
|
||||||
// set the service type
|
|
||||||
businessDelegate.setServiceType(ServiceType.EJB);
|
|
||||||
|
|
||||||
// action
|
// action
|
||||||
client.doTask();
|
client.playbackMovie("Die hard");
|
||||||
|
|
||||||
// verifying that the businessDelegate was used by client during doTask() method.
|
// verifying that the businessDelegate was used by client during playbackMovie() method.
|
||||||
verify(businessDelegate).doTask();
|
verify(businessDelegate).playbackMovie(anyString());
|
||||||
verify(ejbService).doProcessing();
|
verify(netflixService).doProcessing();
|
||||||
|
|
||||||
// set the service type
|
|
||||||
businessDelegate.setServiceType(ServiceType.JMS);
|
|
||||||
|
|
||||||
// action
|
// action
|
||||||
client.doTask();
|
client.playbackMovie("Maradona");
|
||||||
|
|
||||||
// verifying that the businessDelegate was used by client during doTask() method.
|
// verifying that the businessDelegate was used by client during doTask() method.
|
||||||
verify(businessDelegate, times(2)).doTask();
|
verify(businessDelegate, times(2)).playbackMovie(anyString());
|
||||||
verify(jmsService).doProcessing();
|
verify(youTubeService).doProcessing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,23 +4,240 @@ title: Bytecode
|
|||||||
folder: bytecode
|
folder: bytecode
|
||||||
permalink: /patterns/bytecode/
|
permalink: /patterns/bytecode/
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Game programming
|
- Game programming
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Allows to encode behaviour as instructions for virtual machine.
|
|
||||||
|
Allows encoding behavior as instructions for a virtual machine.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> A team is working on a new game where wizards battle against each other. The wizard behavior
|
||||||
|
> needs to be carefully adjusted and iterated hundreds of times through playtesting. It's not
|
||||||
|
> optimal to ask the programmer to make changes each time the game designer wants to vary the
|
||||||
|
> behavior, so the wizard behavior is implemented as a data-driven virtual machine.
|
||||||
|
|
||||||
|
In plain words
|
||||||
|
|
||||||
|
> Bytecode pattern enables behavior driven by data instead of code.
|
||||||
|
|
||||||
|
[Gameprogrammingpatterns.com](https://gameprogrammingpatterns.com/bytecode.html) documentation
|
||||||
|
states:
|
||||||
|
|
||||||
|
> An instruction set defines the low-level operations that can be performed. A series of
|
||||||
|
> instructions is encoded as a sequence of bytes. A virtual machine executes these instructions one
|
||||||
|
> at a time, using a stack for intermediate values. By combining instructions, complex high-level
|
||||||
|
> behavior can be defined.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
One of the most important game objects is the `Wizard` class.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Slf4j
|
||||||
|
public class Wizard {
|
||||||
|
|
||||||
|
private int health;
|
||||||
|
private int agility;
|
||||||
|
private int wisdom;
|
||||||
|
private int numberOfPlayedSounds;
|
||||||
|
private int numberOfSpawnedParticles;
|
||||||
|
|
||||||
|
public void playSound() {
|
||||||
|
LOGGER.info("Playing sound");
|
||||||
|
numberOfPlayedSounds++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnParticles() {
|
||||||
|
LOGGER.info("Spawning particles");
|
||||||
|
numberOfSpawnedParticles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, we show the available instructions for our virtual machine. Each of the instructions has its
|
||||||
|
own semantics on how it operates with the stack data. For example, the ADD instruction takes the top
|
||||||
|
two items from the stack, adds them together and pushes the result to the stack.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum Instruction {
|
||||||
|
|
||||||
|
LITERAL(1), // e.g. "LITERAL 0", push 0 to stack
|
||||||
|
SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health
|
||||||
|
SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
|
||||||
|
SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
|
||||||
|
PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
|
||||||
|
SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
|
||||||
|
GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
|
||||||
|
GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
|
||||||
|
GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
|
||||||
|
ADD(10), // e.g. "ADD", pop 2 values, push their sum
|
||||||
|
DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
At the heart of our example is the `VirtualMachine` class. It takes instructions as input and
|
||||||
|
executes them to provide the game object behavior.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Getter
|
||||||
|
@Slf4j
|
||||||
|
public class VirtualMachine {
|
||||||
|
|
||||||
|
private final Stack<Integer> stack = new Stack<>();
|
||||||
|
|
||||||
|
private final Wizard[] wizards = new Wizard[2];
|
||||||
|
|
||||||
|
public VirtualMachine() {
|
||||||
|
wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||||
|
0, 0);
|
||||||
|
wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualMachine(Wizard wizard1, Wizard wizard2) {
|
||||||
|
wizards[0] = wizard1;
|
||||||
|
wizards[1] = wizard2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(int[] bytecode) {
|
||||||
|
for (var i = 0; i < bytecode.length; i++) {
|
||||||
|
Instruction instruction = Instruction.getInstruction(bytecode[i]);
|
||||||
|
switch (instruction) {
|
||||||
|
case LITERAL:
|
||||||
|
// Read the next byte from the bytecode.
|
||||||
|
int value = bytecode[++i];
|
||||||
|
// Push the next value to stack
|
||||||
|
stack.push(value);
|
||||||
|
break;
|
||||||
|
case SET_AGILITY:
|
||||||
|
var amount = stack.pop();
|
||||||
|
var wizard = stack.pop();
|
||||||
|
setAgility(wizard, amount);
|
||||||
|
break;
|
||||||
|
case SET_WISDOM:
|
||||||
|
amount = stack.pop();
|
||||||
|
wizard = stack.pop();
|
||||||
|
setWisdom(wizard, amount);
|
||||||
|
break;
|
||||||
|
case SET_HEALTH:
|
||||||
|
amount = stack.pop();
|
||||||
|
wizard = stack.pop();
|
||||||
|
setHealth(wizard, amount);
|
||||||
|
break;
|
||||||
|
case GET_HEALTH:
|
||||||
|
wizard = stack.pop();
|
||||||
|
stack.push(getHealth(wizard));
|
||||||
|
break;
|
||||||
|
case GET_AGILITY:
|
||||||
|
wizard = stack.pop();
|
||||||
|
stack.push(getAgility(wizard));
|
||||||
|
break;
|
||||||
|
case GET_WISDOM:
|
||||||
|
wizard = stack.pop();
|
||||||
|
stack.push(getWisdom(wizard));
|
||||||
|
break;
|
||||||
|
case ADD:
|
||||||
|
var a = stack.pop();
|
||||||
|
var b = stack.pop();
|
||||||
|
stack.push(a + b);
|
||||||
|
break;
|
||||||
|
case DIVIDE:
|
||||||
|
a = stack.pop();
|
||||||
|
b = stack.pop();
|
||||||
|
stack.push(b / a);
|
||||||
|
break;
|
||||||
|
case PLAY_SOUND:
|
||||||
|
wizard = stack.pop();
|
||||||
|
getWizards()[wizard].playSound();
|
||||||
|
break;
|
||||||
|
case SPAWN_PARTICLES:
|
||||||
|
wizard = stack.pop();
|
||||||
|
getWizards()[wizard].spawnParticles();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid instruction value");
|
||||||
|
}
|
||||||
|
LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHealth(int wizard, int amount) {
|
||||||
|
wizards[wizard].setHealth(amount);
|
||||||
|
}
|
||||||
|
// other setters ->
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can show the full example utilizing the virtual machine.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
var vm = new VirtualMachine(
|
||||||
|
new Wizard(45, 7, 11, 0, 0),
|
||||||
|
new Wizard(36, 18, 8, 0, 0));
|
||||||
|
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH"));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is the console output.
|
||||||
|
|
||||||
|
```
|
||||||
|
16:20:10.193 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0]
|
||||||
|
16:20:10.196 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 0]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_HEALTH, Stack contains [0, 45]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 0]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_AGILITY, Stack contains [0, 45, 7]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 7, 0]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_WISDOM, Stack contains [0, 45, 7, 11]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 45, 18]
|
||||||
|
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 18, 2]
|
||||||
|
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed DIVIDE, Stack contains [0, 45, 9]
|
||||||
|
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 54]
|
||||||
|
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed SET_HEALTH, Stack contains []
|
||||||
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Bytecode pattern when you have a lot of behavior you need to define and your
|
Use the Bytecode pattern when you have a lot of behavior you need to define and your
|
||||||
game’s implementation language isn’t a good fit because:
|
game’s implementation language isn’t a good fit because:
|
||||||
|
|
||||||
* it’s too low-level, making it tedious or error-prone to program in.
|
* It’s too low-level, making it tedious or error-prone to program in.
|
||||||
* iterating on it takes too long due to slow compile times or other tooling issues.
|
* Iterating on it takes too long due to slow compile times or other tooling issues.
|
||||||
* it has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase.
|
* It has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase.
|
||||||
|
|
||||||
|
## Related patterns
|
||||||
|
|
||||||
|
* [Interpreter](https://java-design-patterns.com/patterns/interpreter/)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 19 KiB |
@ -1,49 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<class-diagram version="1.2.3" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
|
||||||
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
|
||||||
<class id="1" language="java" name="com.iluwatar.bytecode.VirtualMachine" project="bytecode"
|
|
||||||
file="/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="455" y="173"/>
|
|
||||||
<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="2" language="java" name="com.iluwatar.bytecode.App" project="bytecode"
|
|
||||||
file="/bytecode/src/main/java/com/iluwatar/bytecode/App.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="148" y="110"/>
|
|
||||||
<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.bytecode.Wizard" project="bytecode"
|
|
||||||
file="/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="148" y="416"/>
|
|
||||||
<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>
|
|
||||||
<association id="4">
|
|
||||||
<end type="SOURCE" refId="1" navigable="false" variant="ASSOCIATION">
|
|
||||||
<attribute id="5" name="wizards">
|
|
||||||
<position height="18" width="48" x="296" y="291"/>
|
|
||||||
</attribute>
|
|
||||||
<multiplicity id="6" minimum="0" maximum="2147483647">
|
|
||||||
<position height="0" width="0" x="-327" y="-27"/>
|
|
||||||
</multiplicity>
|
|
||||||
</end>
|
|
||||||
<end type="TARGET" refId="3" navigable="true" variant="ASSOCIATION"/>
|
|
||||||
<display labels="true" multiplicity="true"/>
|
|
||||||
</association>
|
|
||||||
<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>
|
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 84 KiB |
@ -3,7 +3,6 @@ package com.iluwatar.bytecode {
|
|||||||
class App {
|
class App {
|
||||||
- LOGGER : Logger {static}
|
- LOGGER : Logger {static}
|
||||||
+ App()
|
+ App()
|
||||||
- interpretInstruction(instruction : String, vm : VirtualMachine) {static}
|
|
||||||
+ main(args : String[]) {static}
|
+ main(args : String[]) {static}
|
||||||
}
|
}
|
||||||
enum Instruction {
|
enum Instruction {
|
||||||
@ -18,22 +17,25 @@ package com.iluwatar.bytecode {
|
|||||||
+ SET_HEALTH {static}
|
+ SET_HEALTH {static}
|
||||||
+ SET_WISDOM {static}
|
+ SET_WISDOM {static}
|
||||||
+ SPAWN_PARTICLES {static}
|
+ SPAWN_PARTICLES {static}
|
||||||
- value : int
|
- intValue : int
|
||||||
+ getInstruction(value : int) : Instruction {static}
|
+ getInstruction(value : int) : Instruction {static}
|
||||||
+ getIntValue() : int
|
+ getIntValue() : int
|
||||||
+ valueOf(name : String) : Instruction {static}
|
+ valueOf(name : String) : Instruction {static}
|
||||||
+ values() : Instruction[] {static}
|
+ values() : Instruction[] {static}
|
||||||
}
|
}
|
||||||
class VirtualMachine {
|
class VirtualMachine {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
- stack : Stack<Integer>
|
- stack : Stack<Integer>
|
||||||
- wizards : Wizard[]
|
- wizards : Wizard[]
|
||||||
+ VirtualMachine()
|
+ VirtualMachine()
|
||||||
|
+ VirtualMachine(wizard1 : Wizard, wizard2 : Wizard)
|
||||||
+ execute(bytecode : int[])
|
+ execute(bytecode : int[])
|
||||||
+ getAgility(wizard : int) : int
|
+ getAgility(wizard : int) : int
|
||||||
+ getHealth(wizard : int) : int
|
+ getHealth(wizard : int) : int
|
||||||
+ getStack() : Stack<Integer>
|
+ getStack() : Stack<Integer>
|
||||||
+ getWisdom(wizard : int) : int
|
+ getWisdom(wizard : int) : int
|
||||||
+ getWizards() : Wizard[]
|
+ getWizards() : Wizard[]
|
||||||
|
- randomInt(min : int, max : int) : int
|
||||||
+ setAgility(wizard : int, amount : int)
|
+ setAgility(wizard : int, amount : int)
|
||||||
+ setHealth(wizard : int, amount : int)
|
+ setHealth(wizard : int, amount : int)
|
||||||
+ setWisdom(wizard : int, amount : int)
|
+ setWisdom(wizard : int, amount : int)
|
||||||
@ -45,7 +47,7 @@ package com.iluwatar.bytecode {
|
|||||||
- numberOfPlayedSounds : int
|
- numberOfPlayedSounds : int
|
||||||
- numberOfSpawnedParticles : int
|
- numberOfSpawnedParticles : int
|
||||||
- wisdom : int
|
- wisdom : int
|
||||||
+ Wizard()
|
+ Wizard(health : int, agility : int, wisdom : int, numberOfPlayedSounds : int, numberOfSpawnedParticles : int)
|
||||||
+ getAgility() : int
|
+ getAgility() : int
|
||||||
+ getHealth() : int
|
+ getHealth() : int
|
||||||
+ getNumberOfPlayedSounds() : int
|
+ getNumberOfPlayedSounds() : int
|
||||||
@ -54,6 +56,8 @@ package com.iluwatar.bytecode {
|
|||||||
+ playSound()
|
+ playSound()
|
||||||
+ setAgility(agility : int)
|
+ setAgility(agility : int)
|
||||||
+ setHealth(health : int)
|
+ setHealth(health : int)
|
||||||
|
+ setNumberOfPlayedSounds(numberOfPlayedSounds : int)
|
||||||
|
+ setNumberOfSpawnedParticles(numberOfSpawnedParticles : int)
|
||||||
+ setWisdom(wisdom : int)
|
+ setWisdom(wisdom : int)
|
||||||
+ spawnParticles()
|
+ spawnParticles()
|
||||||
}
|
}
|
||||||
|
@ -23,16 +23,13 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>bytecode</artifactId>
|
<artifactId>bytecode</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -41,7 +38,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@ -61,5 +57,4 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -42,6 +42,14 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
|
private static final String LITERAL_0 = "LITERAL 0";
|
||||||
|
private static final String HEALTH_PATTERN = "%s_HEALTH";
|
||||||
|
private static final String GET_AGILITY = "GET_AGILITY";
|
||||||
|
private static final String GET_WISDOM = "GET_WISDOM";
|
||||||
|
private static final String ADD = "ADD";
|
||||||
|
private static final String LITERAL_2 = "LITERAL 2";
|
||||||
|
private static final String DIVIDE = "DIVIDE";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main app method.
|
* Main app method.
|
||||||
*
|
*
|
||||||
@ -49,33 +57,21 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
var wizard = new Wizard();
|
var vm = new VirtualMachine(
|
||||||
wizard.setHealth(45);
|
new Wizard(45, 7, 11, 0, 0),
|
||||||
wizard.setAgility(7);
|
new Wizard(36, 18, 8, 0, 0));
|
||||||
wizard.setWisdom(11);
|
|
||||||
|
|
||||||
var vm = new VirtualMachine();
|
vm.execute(InstructionConverterUtil.convertToByteCode(LITERAL_0));
|
||||||
vm.getWizards()[0] = wizard;
|
vm.execute(InstructionConverterUtil.convertToByteCode(LITERAL_0));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode(String.format(HEALTH_PATTERN, "GET")));
|
||||||
String literal = "LITERAL 0";
|
vm.execute(InstructionConverterUtil.convertToByteCode(LITERAL_0));
|
||||||
|
vm.execute(InstructionConverterUtil.convertToByteCode(GET_AGILITY));
|
||||||
interpretInstruction(literal, vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(LITERAL_0));
|
||||||
interpretInstruction(literal, vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(GET_WISDOM));
|
||||||
interpretInstruction("GET_HEALTH", vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(ADD));
|
||||||
interpretInstruction(literal, vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(LITERAL_2));
|
||||||
interpretInstruction("GET_AGILITY", vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(DIVIDE));
|
||||||
interpretInstruction(literal, vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(ADD));
|
||||||
interpretInstruction("GET_WISDOM ", vm);
|
vm.execute(InstructionConverterUtil.convertToByteCode(String.format(HEALTH_PATTERN, "SET")));
|
||||||
interpretInstruction("ADD", vm);
|
|
||||||
interpretInstruction("LITERAL 2", vm);
|
|
||||||
interpretInstruction("DIVIDE", vm);
|
|
||||||
interpretInstruction("ADD", vm);
|
|
||||||
interpretInstruction("SET_HEALTH", vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void interpretInstruction(String instruction, VirtualMachine vm) {
|
|
||||||
vm.execute(InstructionConverterUtil.convertToByteCode(instruction));
|
|
||||||
var stack = vm.getStack();
|
|
||||||
LOGGER.info(instruction + String.format("%" + (12 - instruction.length()) + "s", "") + stack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,17 +33,17 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
public enum Instruction {
|
public enum Instruction {
|
||||||
|
|
||||||
LITERAL(1),
|
LITERAL(1), // e.g. "LITERAL 0", push 0 to stack
|
||||||
SET_HEALTH(2),
|
SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health
|
||||||
SET_WISDOM(3),
|
SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
|
||||||
SET_AGILITY(4),
|
SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
|
||||||
PLAY_SOUND(5),
|
PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
|
||||||
SPAWN_PARTICLES(6),
|
SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
|
||||||
GET_HEALTH(7),
|
GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
|
||||||
GET_AGILITY(8),
|
GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
|
||||||
GET_WISDOM(9),
|
GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
|
||||||
ADD(10),
|
ADD(10), // e.g. "ADD", pop 2 values, push their sum
|
||||||
DIVIDE(11);
|
DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division
|
||||||
|
|
||||||
private final int intValue;
|
private final int intValue;
|
||||||
|
|
||||||
|
@ -24,12 +24,15 @@
|
|||||||
package com.iluwatar.bytecode;
|
package com.iluwatar.bytecode;
|
||||||
|
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of virtual machine.
|
* Implementation of virtual machine.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
@Slf4j
|
||||||
public class VirtualMachine {
|
public class VirtualMachine {
|
||||||
|
|
||||||
private final Stack<Integer> stack = new Stack<>();
|
private final Stack<Integer> stack = new Stack<>();
|
||||||
@ -37,12 +40,21 @@ public class VirtualMachine {
|
|||||||
private final Wizard[] wizards = new Wizard[2];
|
private final Wizard[] wizards = new Wizard[2];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* No-args constructor.
|
||||||
*/
|
*/
|
||||||
public VirtualMachine() {
|
public VirtualMachine() {
|
||||||
for (var i = 0; i < wizards.length; i++) {
|
wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||||
wizards[i] = new Wizard();
|
0, 0);
|
||||||
|
wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||||
|
0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor taking the wizards as arguments.
|
||||||
|
*/
|
||||||
|
public VirtualMachine(Wizard wizard1, Wizard wizard2) {
|
||||||
|
wizards[0] = wizard1;
|
||||||
|
wizards[1] = wizard2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +69,7 @@ public class VirtualMachine {
|
|||||||
case LITERAL:
|
case LITERAL:
|
||||||
// Read the next byte from the bytecode.
|
// Read the next byte from the bytecode.
|
||||||
int value = bytecode[++i];
|
int value = bytecode[++i];
|
||||||
|
// Push the next value to stack
|
||||||
stack.push(value);
|
stack.push(value);
|
||||||
break;
|
break;
|
||||||
case SET_AGILITY:
|
case SET_AGILITY:
|
||||||
@ -107,6 +120,7 @@ public class VirtualMachine {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid instruction value");
|
throw new IllegalArgumentException("Invalid instruction value");
|
||||||
}
|
}
|
||||||
|
LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,4 +147,8 @@ public class VirtualMachine {
|
|||||||
public int getAgility(int wizard) {
|
public int getAgility(int wizard) {
|
||||||
return wizards[wizard].getAgility();
|
return wizards[wizard].getAgility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int randomInt(int min, int max) {
|
||||||
|
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
package com.iluwatar.bytecode;
|
package com.iluwatar.bytecode;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -31,16 +32,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
* This class represent game objects which properties can be changed by instructions interpreted by
|
* This class represent game objects which properties can be changed by instructions interpreted by
|
||||||
* virtual machine.
|
* virtual machine.
|
||||||
*/
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Wizard {
|
public class Wizard {
|
||||||
|
|
||||||
private int health;
|
private int health;
|
||||||
|
|
||||||
private int agility;
|
private int agility;
|
||||||
private int wisdom;
|
private int wisdom;
|
||||||
|
|
||||||
private int numberOfPlayedSounds;
|
private int numberOfPlayedSounds;
|
||||||
private int numberOfSpawnedParticles;
|
private int numberOfSpawnedParticles;
|
||||||
|
|
||||||
@ -53,5 +53,4 @@ public class Wizard {
|
|||||||
LOGGER.info("Spawning particles");
|
LOGGER.info("Spawning particles");
|
||||||
numberOfSpawnedParticles++;
|
numberOfSpawnedParticles++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,4 @@ public class InstructionConverterUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,26 +4,342 @@ title: Caching
|
|||||||
folder: caching
|
folder: caching
|
||||||
permalink: /patterns/caching/
|
permalink: /patterns/caching/
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Performance
|
- Performance
|
||||||
- Cloud distributed
|
- Cloud distributed
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
To avoid expensive re-acquisition of resources by not releasing
|
|
||||||
the resources immediately after their use. The resources retain their identity, are kept in some
|
The caching pattern avoids expensive re-acquisition of resources by not releasing them immediately
|
||||||
fast-access storage, and are re-used to avoid having to acquire them again.
|
after use. The resources retain their identity, are kept in some fast-access storage, and are
|
||||||
|
re-used to avoid having to acquire them again.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> A team is working on a website that provides new homes for abandoned cats. People can post their
|
||||||
|
> cats on the website after registering, but all the new posts require approval from one of the
|
||||||
|
> site moderators. The user accounts of the site moderators contain a specific flag and the data
|
||||||
|
> is stored in a MongoDB database. Checking for the moderator flag each time a post is viewed
|
||||||
|
> becomes expensive and it's a good idea to utilize caching here.
|
||||||
|
|
||||||
|
In plain words
|
||||||
|
|
||||||
|
> Caching pattern keeps frequently needed data in fast-access storage to improve performance.
|
||||||
|
|
||||||
|
Wikipedia says:
|
||||||
|
|
||||||
|
> In computing, a cache is a hardware or software component that stores data so that future
|
||||||
|
> requests for that data can be served faster; the data stored in a cache might be the result of
|
||||||
|
> an earlier computation or a copy of data stored elsewhere. A cache hit occurs when the requested
|
||||||
|
> data can be found in a cache, while a cache miss occurs when it cannot. Cache hits are served by
|
||||||
|
> reading data from the cache, which is faster than recomputing a result or reading from a slower
|
||||||
|
> data store; thus, the more requests that can be served from the cache, the faster the system
|
||||||
|
> performs.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
Let's first look at the data layer of our application. The interesting classes are `UserAccount`
|
||||||
|
which is a simple Java object containing the user account details, and `DbManager` interface which handles
|
||||||
|
reading and writing of these objects to/from database.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class UserAccount {
|
||||||
|
private String userId;
|
||||||
|
private String userName;
|
||||||
|
private String additionalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface DbManager {
|
||||||
|
|
||||||
|
void connect();
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
UserAccount readFromDb(String userId);
|
||||||
|
UserAccount writeToDb(UserAccount userAccount);
|
||||||
|
UserAccount updateDb(UserAccount userAccount);
|
||||||
|
UserAccount upsertDb(UserAccount userAccount);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example, we are demonstrating various different caching policies
|
||||||
|
|
||||||
|
* Write-through writes data to the cache and DB in a single transaction
|
||||||
|
* Write-around writes data immediately into the DB instead of the cache
|
||||||
|
* Write-behind writes data into the cache initially whilst the data is only written into the DB
|
||||||
|
when the cache is full
|
||||||
|
* Cache-aside pushes the responsibility of keeping the data synchronized in both data sources to
|
||||||
|
the application itself
|
||||||
|
* Read-through strategy is also included in the aforementioned strategies and it returns data from
|
||||||
|
the cache to the caller if it exists, otherwise queries from DB and stores it into the cache for
|
||||||
|
future use.
|
||||||
|
|
||||||
|
The cache implementation in `LruCache` is a hash table accompanied by a doubly
|
||||||
|
linked-list. The linked-list helps in capturing and maintaining the LRU data in the cache. When
|
||||||
|
data is queried (from the cache), added (to the cache), or updated, the data is moved to the front
|
||||||
|
of the list to depict itself as the most-recently-used data. The LRU data is always at the end of
|
||||||
|
the list.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public class LruCache {
|
||||||
|
|
||||||
|
static class Node {
|
||||||
|
String userId;
|
||||||
|
UserAccount userAccount;
|
||||||
|
Node previous;
|
||||||
|
Node next;
|
||||||
|
|
||||||
|
public Node(String userId, UserAccount userAccount) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.userAccount = userAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... omitted details ... */
|
||||||
|
|
||||||
|
public LruCache(int capacity) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount get(String userId) {
|
||||||
|
if (cache.containsKey(userId)) {
|
||||||
|
var node = cache.get(userId);
|
||||||
|
remove(node);
|
||||||
|
setHead(node);
|
||||||
|
return node.userAccount;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(String userId, UserAccount userAccount) {
|
||||||
|
if (cache.containsKey(userId)) {
|
||||||
|
var old = cache.get(userId);
|
||||||
|
old.userAccount = userAccount;
|
||||||
|
remove(old);
|
||||||
|
setHead(old);
|
||||||
|
} else {
|
||||||
|
var newNode = new Node(userId, userAccount);
|
||||||
|
if (cache.size() >= capacity) {
|
||||||
|
LOGGER.info("# Cache is FULL! Removing {} from cache...", end.userId);
|
||||||
|
cache.remove(end.userId); // remove LRU data from cache.
|
||||||
|
remove(end);
|
||||||
|
setHead(newNode);
|
||||||
|
} else {
|
||||||
|
setHead(newNode);
|
||||||
|
}
|
||||||
|
cache.put(userId, newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(String userId) {
|
||||||
|
return cache.containsKey(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Node node) { /* ... */ }
|
||||||
|
public void setHead(Node node) { /* ... */ }
|
||||||
|
public void invalidate(String userId) { /* ... */ }
|
||||||
|
public boolean isFull() { /* ... */ }
|
||||||
|
public UserAccount getLruData() { /* ... */ }
|
||||||
|
public void clear() { /* ... */ }
|
||||||
|
public List<UserAccount> getCacheDataInListForm() { /* ... */ }
|
||||||
|
public void setCapacity(int newCapacity) { /* ... */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The next layer we are going to look at is `CacheStore` which implements the different caching
|
||||||
|
strategies.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public class CacheStore {
|
||||||
|
|
||||||
|
private static final int CAPACITY = 3;
|
||||||
|
private static LruCache cache;
|
||||||
|
private final DbManager dbManager;
|
||||||
|
|
||||||
|
/* ... details omitted ... */
|
||||||
|
|
||||||
|
public UserAccount readThrough(final String userId) {
|
||||||
|
if (cache.contains(userId)) {
|
||||||
|
LOGGER.info("# Found in Cache!");
|
||||||
|
return cache.get(userId);
|
||||||
|
}
|
||||||
|
LOGGER.info("# Not found in cache! Go to DB!!");
|
||||||
|
UserAccount userAccount = dbManager.readFromDb(userId);
|
||||||
|
cache.set(userId, userAccount);
|
||||||
|
return userAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeThrough(final UserAccount userAccount) {
|
||||||
|
if (cache.contains(userAccount.getUserId())) {
|
||||||
|
dbManager.updateDb(userAccount);
|
||||||
|
} else {
|
||||||
|
dbManager.writeToDb(userAccount);
|
||||||
|
}
|
||||||
|
cache.set(userAccount.getUserId(), userAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAround(final UserAccount userAccount) {
|
||||||
|
if (cache.contains(userAccount.getUserId())) {
|
||||||
|
dbManager.updateDb(userAccount);
|
||||||
|
// Cache data has been updated -- remove older
|
||||||
|
cache.invalidate(userAccount.getUserId());
|
||||||
|
// version from cache.
|
||||||
|
} else {
|
||||||
|
dbManager.writeToDb(userAccount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearCache() {
|
||||||
|
if (cache != null) {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void flushCache() {
|
||||||
|
LOGGER.info("# flushCache...");
|
||||||
|
Optional.ofNullable(cache)
|
||||||
|
.map(LruCache::getCacheDataInListForm)
|
||||||
|
.orElse(List.of())
|
||||||
|
.forEach(DbManager::updateDb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... omitted the implementation of other caching strategies ... */
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`AppManager` helps to bridge the gap in communication between the main class and the application's
|
||||||
|
back-end. DB connection is initialized through this class. The chosen caching strategy/policy is
|
||||||
|
also initialized here. Before the cache can be used, the size of the cache has to be set. Depending
|
||||||
|
on the chosen caching policy, `AppManager` will call the appropriate function in the `CacheStore`
|
||||||
|
class.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public final class AppManager {
|
||||||
|
|
||||||
|
private static CachingPolicy cachingPolicy;
|
||||||
|
private final DbManager dbManager;
|
||||||
|
private final CacheStore cacheStore;
|
||||||
|
|
||||||
|
private AppManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initDb() { /* ... */ }
|
||||||
|
|
||||||
|
public static void initCachingPolicy(CachingPolicy policy) { /* ... */ }
|
||||||
|
|
||||||
|
public static void initCacheCapacity(int capacity) { /* ... */ }
|
||||||
|
|
||||||
|
public UserAccount find(final String userId) {
|
||||||
|
LOGGER.info("Trying to find {} in cache", userId);
|
||||||
|
if (cachingPolicy == CachingPolicy.THROUGH
|
||||||
|
|| cachingPolicy == CachingPolicy.AROUND) {
|
||||||
|
return cacheStore.readThrough(userId);
|
||||||
|
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
|
return cacheStore.readThroughWithWriteBackPolicy(userId);
|
||||||
|
} else if (cachingPolicy == CachingPolicy.ASIDE) {
|
||||||
|
return findAside(userId);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(final UserAccount userAccount) {
|
||||||
|
LOGGER.info("Save record!");
|
||||||
|
if (cachingPolicy == CachingPolicy.THROUGH) {
|
||||||
|
cacheStore.writeThrough(userAccount);
|
||||||
|
} else if (cachingPolicy == CachingPolicy.AROUND) {
|
||||||
|
cacheStore.writeAround(userAccount);
|
||||||
|
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
|
cacheStore.writeBehind(userAccount);
|
||||||
|
} else if (cachingPolicy == CachingPolicy.ASIDE) {
|
||||||
|
saveAside(userAccount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String printCacheContent() {
|
||||||
|
return CacheStore.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... details omitted ... */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is what we do in the main class of the application.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public class App {
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
boolean isDbMongo = isDbMongo(args);
|
||||||
|
if(isDbMongo){
|
||||||
|
LOGGER.info("Using the Mongo database engine to run the application.");
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Using the 'in Memory' database to run the application.");
|
||||||
|
}
|
||||||
|
App app = new App(isDbMongo);
|
||||||
|
app.useReadAndWriteThroughStrategy();
|
||||||
|
String splitLine = "==============================================";
|
||||||
|
LOGGER.info(splitLine);
|
||||||
|
app.useReadThroughAndWriteAroundStrategy();
|
||||||
|
LOGGER.info(splitLine);
|
||||||
|
app.useReadThroughAndWriteBehindStrategy();
|
||||||
|
LOGGER.info(splitLine);
|
||||||
|
app.useCacheAsideStategy();
|
||||||
|
LOGGER.info(splitLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useReadAndWriteThroughStrategy() {
|
||||||
|
LOGGER.info("# CachingPolicy.THROUGH");
|
||||||
|
appManager.initCachingPolicy(CachingPolicy.THROUGH);
|
||||||
|
|
||||||
|
var userAccount1 = new UserAccount("001", "John", "He is a boy.");
|
||||||
|
|
||||||
|
appManager.save(userAccount1);
|
||||||
|
LOGGER.info(appManager.printCacheContent());
|
||||||
|
appManager.find("001");
|
||||||
|
appManager.find("001");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useReadThroughAndWriteAroundStrategy() { /* ... */ }
|
||||||
|
|
||||||
|
public void useReadThroughAndWriteBehindStrategy() { /* ... */ }
|
||||||
|
|
||||||
|
public void useCacheAsideStategy() { /* ... */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Caching pattern(s) when
|
Use the Caching pattern(s) when
|
||||||
|
|
||||||
* Repetitious acquisition, initialization, and release of the same resource causes unnecessary performance overhead.
|
* Repetitious acquisition, initialization, and release of the same resource cause unnecessary
|
||||||
|
performance overhead.
|
||||||
|
|
||||||
|
## Related patterns
|
||||||
|
|
||||||
|
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
|
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
|
||||||
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
|
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
|
||||||
* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
|
* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
|
||||||
|
* [Java EE 8 High Performance: Master techniques such as memory optimization, caching, concurrency, and multithreading to achieve maximum performance from your enterprise applications](https://www.amazon.com/gp/product/178847306X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=178847306X&linkId=e948720055599f248cdac47da9125ff4)
|
||||||
|
* [Java Performance: In-Depth Advice for Tuning and Programming Java 8, 11, and Beyond](https://www.amazon.com/gp/product/1492056111/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1492056111&linkId=7e553581559b9ec04221259e52004b08)
|
||||||
|
* [Effective Java](https://www.amazon.com/gp/product/B078H61SCH/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B078H61SCH&linkId=f06607a0b48c76541ef19c5b8b9e7882)
|
||||||
|
* [Java Performance: The Definitive Guide: Getting the Most Out of Your Code](https://www.amazon.com/gp/product/1449358454/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1449358454&linkId=475c18363e350630cc0b39ab681b2687)
|
||||||
|
11
caching/docker-compose.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: '3.7'
|
||||||
|
services:
|
||||||
|
mongodb_container:
|
||||||
|
image: mongo:latest
|
||||||
|
environment:
|
||||||
|
MONGO_INITDB_ROOT_USERNAME: root
|
||||||
|
MONGO_INITDB_ROOT_PASSWORD: rootpassword
|
||||||
|
ports:
|
||||||
|
- 27017:27017
|
||||||
|
volumes:
|
||||||
|
- ./mongo-data/:/data/db
|
Before Width: | Height: | Size: 112 KiB |
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
@ -23,13 +23,12 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.24.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>caching</artifactId>
|
<artifactId>caching</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -39,19 +38,14 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mongodb-driver</artifactId>
|
<artifactId>mockito-all</artifactId>
|
||||||
<version>3.12.1</version>
|
<version>1.10.19</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongodb-driver-core</artifactId>
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
<version>3.0.4</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mongodb</groupId>
|
|
||||||
<artifactId>bson</artifactId>
|
|
||||||
<version>3.0.4</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<!--
|
<!--
|
||||||
|
@ -1,58 +1,62 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
* Copyright © 2014-2021 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.caching;
|
package com.iluwatar.caching;
|
||||||
|
|
||||||
|
import com.iluwatar.caching.database.DbManager;
|
||||||
|
import com.iluwatar.caching.database.DbManagerFactory;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing
|
* The Caching pattern describes how to avoid expensive re-acquisition of
|
||||||
* the resources immediately after their use. The resources retain their identity, are kept in some
|
* resources by not releasing the resources immediately after their use.
|
||||||
* fast-access storage, and are re-used to avoid having to acquire them again. There are four main
|
* The resources retain their identity, are kept in some fast-access storage,
|
||||||
* caching strategies/techniques in this pattern; each with their own pros and cons. They are;
|
* and are re-used to avoid having to acquire them again. There are four main
|
||||||
* <code>write-through</code> which writes data to the cache and DB in a single transaction,
|
* caching strategies/techniques in this pattern; each with their own pros and
|
||||||
* <code>write-around</code> which writes data immediately into the DB instead of the cache,
|
* cons. They are <code>write-through</code> which writes data to the cache and
|
||||||
* <code>write-behind</code> which writes data into the cache initially whilst the data is only
|
* DB in a single transaction, <code>write-around</code> which writes data
|
||||||
* written into the DB when the cache is full, and <code>cache-aside</code> which pushes the
|
* immediately into the DB instead of the cache, <code>write-behind</code>
|
||||||
* responsibility of keeping the data synchronized in both data sources to the application itself.
|
* which writes data into the cache initially whilst the data is only
|
||||||
* The <code>read-through</code> strategy is also included in the mentioned four strategies --
|
* written into the DB when the cache is full, and <code>cache-aside</code>
|
||||||
* returns data from the cache to the caller <b>if</b> it exists <b>else</b> queries from DB and
|
* which pushes the responsibility of keeping the data synchronized in both
|
||||||
* stores it into the cache for future use. These strategies determine when the data in the cache
|
* data sources to the application itself. The <code>read-through</code>
|
||||||
* should be written back to the backing store (i.e. Database) and help keep both data sources
|
* strategy is also included in the mentioned four strategies --
|
||||||
* synchronized/up-to-date. This pattern can improve performance and also helps to maintain
|
* returns data from the cache to the caller <b>if</b> it exists <b>else</b>
|
||||||
* consistency between data held in the cache and the data in the underlying data store.
|
* queries from DB and stores it into the cache for future use. These strategies
|
||||||
|
* determine when the data in the cache should be written back to the backing
|
||||||
|
* store (i.e. Database) and help keep both data sources
|
||||||
|
* synchronized/up-to-date. This pattern can improve performance and also helps
|
||||||
|
* to maintainconsistency between data held in the cache and the data in
|
||||||
|
* the underlying data store.
|
||||||
*
|
*
|
||||||
* <p>In this example, the user account ({@link UserAccount}) entity is used as the underlying
|
* <p>In this example, the user account ({@link UserAccount}) entity is used
|
||||||
* application data. The cache itself is implemented as an internal (Java) data structure. It adopts
|
* as the underlying application data. The cache itself is implemented as an
|
||||||
* a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The four
|
* internal (Java) data structure. It adopts a Least-Recently-Used (LRU)
|
||||||
* strategies are individually tested. The testing of the cache is restricted towards saving and
|
* strategy for evicting data from itself when its full. The four
|
||||||
* querying of user accounts from the underlying data store ( {@link DbManager}). The main class (
|
* strategies are individually tested. The testing of the cache is restricted
|
||||||
* {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and
|
* towards saving and querying of user accounts from the
|
||||||
* whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager
|
* underlying data store( {@link DbManager}). The main class ( {@link App}
|
||||||
* ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
|
* is not aware of the underlying mechanics of the application
|
||||||
* (depending on the preferred caching policy/strategy).
|
* (i.e. save and query) and whether the data is coming from the cache or the
|
||||||
|
* DB (i.e. separation of concern). The AppManager ({@link AppManager}) handles
|
||||||
|
* the transaction of data to-and-from the underlying data store (depending on
|
||||||
|
* the preferred caching policy/strategy).
|
||||||
* <p>
|
* <p>
|
||||||
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager} </i>
|
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy -->
|
||||||
|
* DBManager} </i>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* There are 2 ways to launch the application.
|
||||||
|
* - to use "in Memory" database.
|
||||||
|
* - to use the MongoDb as a database
|
||||||
|
*
|
||||||
|
* To run the application with "in Memory" database, just launch it without parameters
|
||||||
|
* Example: 'java -jar app.jar'
|
||||||
|
*
|
||||||
|
* To run the application with MongoDb you need to be installed the MongoDb
|
||||||
|
* in your system, or to launch it in the docker container.
|
||||||
|
* You may launch docker container from the root of current module with command:
|
||||||
|
* 'docker-compose up'
|
||||||
|
* Then you can start the application with parameter --mongo
|
||||||
|
* Example: 'java -jar app.jar --mongo'
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see CacheStore
|
* @see CacheStore
|
||||||
@ -61,23 +65,67 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class App {
|
public class App {
|
||||||
|
/**
|
||||||
|
* Constant parameter name to use mongoDB.
|
||||||
|
*/
|
||||||
|
private static final String USE_MONGO_DB = "--mongo";
|
||||||
|
/**
|
||||||
|
* Application manager.
|
||||||
|
*/
|
||||||
|
private final AppManager appManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of current App.
|
||||||
|
*
|
||||||
|
* @param isMongo boolean
|
||||||
|
*/
|
||||||
|
public App(final boolean isMongo) {
|
||||||
|
DbManager dbManager = DbManagerFactory.initDb(isMongo);
|
||||||
|
appManager = new AppManager(dbManager);
|
||||||
|
appManager.initDb();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point.
|
* Program entry point.
|
||||||
*
|
*
|
||||||
* @param args command line args
|
* @param args command line args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(final String[] args) {
|
||||||
AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
// VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
||||||
// and the App class to avoid Maven compilation errors. Set flag to
|
// and the App class to avoid Maven compilation errors. Set flag to
|
||||||
// true to run the tests with MongoDB (provided that MongoDB is
|
// true to run the tests with MongoDB (provided that MongoDB is
|
||||||
// installed and socket connection is open).
|
// installed and socket connection is open).
|
||||||
AppManager.initCacheCapacity(3);
|
boolean isDbMongo = isDbMongo(args);
|
||||||
var app = new App();
|
if (isDbMongo) {
|
||||||
|
LOGGER.info("Using the Mongo database engine to run the application.");
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Using the 'in Memory' database to run the application.");
|
||||||
|
}
|
||||||
|
App app = new App(isDbMongo);
|
||||||
app.useReadAndWriteThroughStrategy();
|
app.useReadAndWriteThroughStrategy();
|
||||||
|
String splitLine = "==============================================";
|
||||||
|
LOGGER.info(splitLine);
|
||||||
app.useReadThroughAndWriteAroundStrategy();
|
app.useReadThroughAndWriteAroundStrategy();
|
||||||
|
LOGGER.info(splitLine);
|
||||||
app.useReadThroughAndWriteBehindStrategy();
|
app.useReadThroughAndWriteBehindStrategy();
|
||||||
|
LOGGER.info(splitLine);
|
||||||
app.useCacheAsideStategy();
|
app.useCacheAsideStategy();
|
||||||
|
LOGGER.info(splitLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the input parameters. if
|
||||||
|
*
|
||||||
|
* @param args input params
|
||||||
|
* @return true if there is "--mongo" parameter in arguments
|
||||||
|
*/
|
||||||
|
private static boolean isDbMongo(final String[] args) {
|
||||||
|
for (String arg : args) {
|
||||||
|
if (arg.equals(USE_MONGO_DB)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,14 +133,14 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public void useReadAndWriteThroughStrategy() {
|
public void useReadAndWriteThroughStrategy() {
|
||||||
LOGGER.info("# CachingPolicy.THROUGH");
|
LOGGER.info("# CachingPolicy.THROUGH");
|
||||||
AppManager.initCachingPolicy(CachingPolicy.THROUGH);
|
appManager.initCachingPolicy(CachingPolicy.THROUGH);
|
||||||
|
|
||||||
var userAccount1 = new UserAccount("001", "John", "He is a boy.");
|
var userAccount1 = new UserAccount("001", "John", "He is a boy.");
|
||||||
|
|
||||||
AppManager.save(userAccount1);
|
appManager.save(userAccount1);
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("001");
|
appManager.find("001");
|
||||||
AppManager.find("001");
|
appManager.find("001");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,21 +148,21 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public void useReadThroughAndWriteAroundStrategy() {
|
public void useReadThroughAndWriteAroundStrategy() {
|
||||||
LOGGER.info("# CachingPolicy.AROUND");
|
LOGGER.info("# CachingPolicy.AROUND");
|
||||||
AppManager.initCachingPolicy(CachingPolicy.AROUND);
|
appManager.initCachingPolicy(CachingPolicy.AROUND);
|
||||||
|
|
||||||
var userAccount2 = new UserAccount("002", "Jane", "She is a girl.");
|
var userAccount2 = new UserAccount("002", "Jane", "She is a girl.");
|
||||||
|
|
||||||
AppManager.save(userAccount2);
|
appManager.save(userAccount2);
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("002");
|
appManager.find("002");
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
userAccount2 = AppManager.find("002");
|
userAccount2 = appManager.find("002");
|
||||||
userAccount2.setUserName("Jane G.");
|
userAccount2.setUserName("Jane G.");
|
||||||
AppManager.save(userAccount2);
|
appManager.save(userAccount2);
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("002");
|
appManager.find("002");
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("002");
|
appManager.find("002");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,23 +170,31 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public void useReadThroughAndWriteBehindStrategy() {
|
public void useReadThroughAndWriteBehindStrategy() {
|
||||||
LOGGER.info("# CachingPolicy.BEHIND");
|
LOGGER.info("# CachingPolicy.BEHIND");
|
||||||
AppManager.initCachingPolicy(CachingPolicy.BEHIND);
|
appManager.initCachingPolicy(CachingPolicy.BEHIND);
|
||||||
|
|
||||||
var userAccount3 = new UserAccount("003", "Adam", "He likes food.");
|
var userAccount3 = new UserAccount("003",
|
||||||
var userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
|
"Adam",
|
||||||
var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
|
"He likes food.");
|
||||||
|
var userAccount4 = new UserAccount("004",
|
||||||
|
"Rita",
|
||||||
|
"She hates cats.");
|
||||||
|
var userAccount5 = new UserAccount("005",
|
||||||
|
"Isaac",
|
||||||
|
"He is allergic to mustard.");
|
||||||
|
|
||||||
AppManager.save(userAccount3);
|
appManager.save(userAccount3);
|
||||||
AppManager.save(userAccount4);
|
appManager.save(userAccount4);
|
||||||
AppManager.save(userAccount5);
|
appManager.save(userAccount5);
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("003");
|
appManager.find("003");
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child.");
|
UserAccount userAccount6 = new UserAccount("006",
|
||||||
AppManager.save(userAccount6);
|
"Yasha",
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
"She is an only child.");
|
||||||
AppManager.find("004");
|
appManager.save(userAccount6);
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
|
appManager.find("004");
|
||||||
|
LOGGER.info(appManager.printCacheContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,20 +202,26 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public void useCacheAsideStategy() {
|
public void useCacheAsideStategy() {
|
||||||
LOGGER.info("# CachingPolicy.ASIDE");
|
LOGGER.info("# CachingPolicy.ASIDE");
|
||||||
AppManager.initCachingPolicy(CachingPolicy.ASIDE);
|
appManager.initCachingPolicy(CachingPolicy.ASIDE);
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
|
|
||||||
var userAccount3 = new UserAccount("003", "Adam", "He likes food.");
|
var userAccount3 = new UserAccount("003",
|
||||||
var userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
|
"Adam",
|
||||||
var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
|
"He likes food.");
|
||||||
AppManager.save(userAccount3);
|
var userAccount4 = new UserAccount("004",
|
||||||
AppManager.save(userAccount4);
|
"Rita",
|
||||||
AppManager.save(userAccount5);
|
"She hates cats.");
|
||||||
|
var userAccount5 = new UserAccount("005",
|
||||||
|
"Isaac",
|
||||||
|
"He is allergic to mustard.");
|
||||||
|
appManager.save(userAccount3);
|
||||||
|
appManager.save(userAccount4);
|
||||||
|
appManager.save(userAccount5);
|
||||||
|
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("003");
|
appManager.find("003");
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
AppManager.find("004");
|
appManager.find("004");
|
||||||
LOGGER.info(AppManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,63 +23,80 @@
|
|||||||
|
|
||||||
package com.iluwatar.caching;
|
package com.iluwatar.caching;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import com.iluwatar.caching.database.DbManager;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppManager helps to bridge the gap in communication between the main class and the application's
|
* AppManager helps to bridge the gap in communication between the main class
|
||||||
* back-end. DB connection is initialized through this class. The chosen caching strategy/policy is
|
* and the application's back-end. DB connection is initialized through this
|
||||||
* also initialized here. Before the cache can be used, the size of the cache has to be set.
|
* class. The chosen caching strategy/policy is also initialized here.
|
||||||
* Depending on the chosen caching policy, AppManager will call the appropriate function in the
|
* Before the cache can be used, the size of the cache has to be set.
|
||||||
* CacheStore class.
|
* Depending on the chosen caching policy, AppManager will call the
|
||||||
|
* appropriate function in the CacheStore class.
|
||||||
*/
|
*/
|
||||||
public final class AppManager {
|
@Slf4j
|
||||||
|
public class AppManager {
|
||||||
|
/**
|
||||||
|
* Caching Policy.
|
||||||
|
*/
|
||||||
|
private CachingPolicy cachingPolicy;
|
||||||
|
/**
|
||||||
|
* Database Manager.
|
||||||
|
*/
|
||||||
|
private final DbManager dbManager;
|
||||||
|
/**
|
||||||
|
* Cache Store.
|
||||||
|
*/
|
||||||
|
private final CacheStore cacheStore;
|
||||||
|
|
||||||
private static CachingPolicy cachingPolicy;
|
/**
|
||||||
|
* Constructor.
|
||||||
private AppManager() {
|
*
|
||||||
|
* @param newDbManager database manager
|
||||||
|
*/
|
||||||
|
public AppManager(final DbManager newDbManager) {
|
||||||
|
this.dbManager = newDbManager;
|
||||||
|
this.cacheStore = new CacheStore(newDbManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Developer/Tester is able to choose whether the application should use MongoDB as its underlying
|
* Developer/Tester is able to choose whether the application should use
|
||||||
* data storage or a simple Java data structure to (temporarily) store the data/objects during
|
* MongoDB as its underlying data storage or a simple Java data structure
|
||||||
* runtime.
|
* to (temporarily) store the data/objects during runtime.
|
||||||
*/
|
*/
|
||||||
public static void initDb(boolean useMongoDb) {
|
public void initDb() {
|
||||||
if (useMongoDb) {
|
dbManager.connect();
|
||||||
try {
|
|
||||||
DbManager.connect();
|
|
||||||
} catch (ParseException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DbManager.createVirtualDb();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize caching policy.
|
* Initialize caching policy.
|
||||||
|
*
|
||||||
|
* @param policy is a {@link CachingPolicy}
|
||||||
*/
|
*/
|
||||||
public static void initCachingPolicy(CachingPolicy policy) {
|
public void initCachingPolicy(final CachingPolicy policy) {
|
||||||
cachingPolicy = policy;
|
cachingPolicy = policy;
|
||||||
if (cachingPolicy == CachingPolicy.BEHIND) {
|
if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(CacheStore::flushCache));
|
Runtime.getRuntime().addShutdownHook(new Thread(cacheStore::flushCache));
|
||||||
}
|
}
|
||||||
CacheStore.clearCache();
|
cacheStore.clearCache();
|
||||||
}
|
|
||||||
|
|
||||||
public static void initCacheCapacity(int capacity) {
|
|
||||||
CacheStore.initCapacity(capacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find user account.
|
* Find user account.
|
||||||
|
*
|
||||||
|
* @param userId String
|
||||||
|
* @return {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static UserAccount find(String userId) {
|
public UserAccount find(final String userId) {
|
||||||
if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) {
|
LOGGER.info("Trying to find {} in cache", userId);
|
||||||
return CacheStore.readThrough(userId);
|
if (cachingPolicy == CachingPolicy.THROUGH
|
||||||
|
|| cachingPolicy == CachingPolicy.AROUND) {
|
||||||
|
return cacheStore.readThrough(userId);
|
||||||
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
return CacheStore.readThroughWithWriteBackPolicy(userId);
|
return cacheStore.readThroughWithWriteBackPolicy(userId);
|
||||||
} else if (cachingPolicy == CachingPolicy.ASIDE) {
|
} else if (cachingPolicy == CachingPolicy.ASIDE) {
|
||||||
return findAside(userId);
|
return findAside(userId);
|
||||||
}
|
}
|
||||||
@ -88,39 +105,53 @@ public final class AppManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save user account.
|
* Save user account.
|
||||||
|
*
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static void save(UserAccount userAccount) {
|
public void save(final UserAccount userAccount) {
|
||||||
|
LOGGER.info("Save record!");
|
||||||
if (cachingPolicy == CachingPolicy.THROUGH) {
|
if (cachingPolicy == CachingPolicy.THROUGH) {
|
||||||
CacheStore.writeThrough(userAccount);
|
cacheStore.writeThrough(userAccount);
|
||||||
} else if (cachingPolicy == CachingPolicy.AROUND) {
|
} else if (cachingPolicy == CachingPolicy.AROUND) {
|
||||||
CacheStore.writeAround(userAccount);
|
cacheStore.writeAround(userAccount);
|
||||||
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
CacheStore.writeBehind(userAccount);
|
cacheStore.writeBehind(userAccount);
|
||||||
} else if (cachingPolicy == CachingPolicy.ASIDE) {
|
} else if (cachingPolicy == CachingPolicy.ASIDE) {
|
||||||
saveAside(userAccount);
|
saveAside(userAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String printCacheContent() {
|
/**
|
||||||
return CacheStore.print();
|
* Returns String.
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String printCacheContent() {
|
||||||
|
return cacheStore.print();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache-Aside save user account helper.
|
* Cache-Aside save user account helper.
|
||||||
|
*
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
private static void saveAside(UserAccount userAccount) {
|
private void saveAside(final UserAccount userAccount) {
|
||||||
DbManager.updateDb(userAccount);
|
dbManager.updateDb(userAccount);
|
||||||
CacheStore.invalidate(userAccount.getUserId());
|
cacheStore.invalidate(userAccount.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache-Aside find user account helper.
|
* Cache-Aside find user account helper.
|
||||||
|
*
|
||||||
|
* @param userId String
|
||||||
|
* @return {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
private static UserAccount findAside(String userId) {
|
private UserAccount findAside(final String userId) {
|
||||||
return Optional.ofNullable(CacheStore.get(userId))
|
return Optional.ofNullable(cacheStore.get(userId))
|
||||||
.or(() -> {
|
.or(() -> {
|
||||||
Optional<UserAccount> userAccount = Optional.ofNullable(DbManager.readFromDb(userId));
|
Optional<UserAccount> userAccount =
|
||||||
userAccount.ifPresent(account -> CacheStore.set(userId, account));
|
Optional.ofNullable(dbManager.readFromDb(userId));
|
||||||
|
userAccount.ifPresent(account -> cacheStore.set(userId, account));
|
||||||
return userAccount;
|
return userAccount;
|
||||||
})
|
})
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
@ -23,9 +23,11 @@
|
|||||||
|
|
||||||
package com.iluwatar.caching;
|
package com.iluwatar.caching;
|
||||||
|
|
||||||
|
import com.iluwatar.caching.database.DbManager;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,16 +35,34 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CacheStore {
|
public class CacheStore {
|
||||||
|
/**
|
||||||
|
* Cache capacity.
|
||||||
|
*/
|
||||||
|
private static final int CAPACITY = 3;
|
||||||
|
|
||||||
private static LruCache cache;
|
/**
|
||||||
|
* Lru cache see {@link LruCache}.
|
||||||
|
*/
|
||||||
|
private LruCache cache;
|
||||||
|
/**
|
||||||
|
* DbManager.
|
||||||
|
*/
|
||||||
|
private final DbManager dbManager;
|
||||||
|
|
||||||
private CacheStore() {
|
/**
|
||||||
|
* Cache Store.
|
||||||
|
* @param dataBaseManager {@link DbManager}
|
||||||
|
*/
|
||||||
|
public CacheStore(final DbManager dataBaseManager) {
|
||||||
|
this.dbManager = dataBaseManager;
|
||||||
|
initCapacity(CAPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init cache capacity.
|
* Init cache capacity.
|
||||||
|
* @param capacity int
|
||||||
*/
|
*/
|
||||||
public static void initCapacity(int capacity) {
|
public void initCapacity(final int capacity) {
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
cache = new LruCache(capacity);
|
cache = new LruCache(capacity);
|
||||||
} else {
|
} else {
|
||||||
@ -52,57 +72,64 @@ public class CacheStore {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user account using read-through cache.
|
* Get user account using read-through cache.
|
||||||
|
* @param userId {@link String}
|
||||||
|
* @return {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static UserAccount readThrough(String userId) {
|
public UserAccount readThrough(final String userId) {
|
||||||
if (cache.contains(userId)) {
|
if (cache.contains(userId)) {
|
||||||
LOGGER.info("# Cache Hit!");
|
LOGGER.info("# Found in Cache!");
|
||||||
return cache.get(userId);
|
return cache.get(userId);
|
||||||
}
|
}
|
||||||
LOGGER.info("# Cache Miss!");
|
LOGGER.info("# Not found in cache! Go to DB!!");
|
||||||
UserAccount userAccount = DbManager.readFromDb(userId);
|
UserAccount userAccount = dbManager.readFromDb(userId);
|
||||||
cache.set(userId, userAccount);
|
cache.set(userId, userAccount);
|
||||||
return userAccount;
|
return userAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user account using write-through cache.
|
* Get user account using write-through cache.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static void writeThrough(UserAccount userAccount) {
|
public void writeThrough(final UserAccount userAccount) {
|
||||||
if (cache.contains(userAccount.getUserId())) {
|
if (cache.contains(userAccount.getUserId())) {
|
||||||
DbManager.updateDb(userAccount);
|
dbManager.updateDb(userAccount);
|
||||||
} else {
|
} else {
|
||||||
DbManager.writeToDb(userAccount);
|
dbManager.writeToDb(userAccount);
|
||||||
}
|
}
|
||||||
cache.set(userAccount.getUserId(), userAccount);
|
cache.set(userAccount.getUserId(), userAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user account using write-around cache.
|
* Get user account using write-around cache.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static void writeAround(UserAccount userAccount) {
|
public void writeAround(final UserAccount userAccount) {
|
||||||
if (cache.contains(userAccount.getUserId())) {
|
if (cache.contains(userAccount.getUserId())) {
|
||||||
DbManager.updateDb(userAccount);
|
dbManager.updateDb(userAccount);
|
||||||
cache.invalidate(userAccount.getUserId()); // Cache data has been updated -- remove older
|
// Cache data has been updated -- remove older
|
||||||
|
cache.invalidate(userAccount.getUserId());
|
||||||
// version from cache.
|
// version from cache.
|
||||||
} else {
|
} else {
|
||||||
DbManager.writeToDb(userAccount);
|
dbManager.writeToDb(userAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user account using read-through cache with write-back policy.
|
* Get user account using read-through cache with write-back policy.
|
||||||
|
* @param userId {@link String}
|
||||||
|
* @return {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static UserAccount readThroughWithWriteBackPolicy(String userId) {
|
public UserAccount readThroughWithWriteBackPolicy(final String userId) {
|
||||||
if (cache.contains(userId)) {
|
if (cache.contains(userId)) {
|
||||||
LOGGER.info("# Cache Hit!");
|
LOGGER.info("# Found in cache!");
|
||||||
return cache.get(userId);
|
return cache.get(userId);
|
||||||
}
|
}
|
||||||
LOGGER.info("# Cache Miss!");
|
LOGGER.info("# Not found in Cache!");
|
||||||
UserAccount userAccount = DbManager.readFromDb(userId);
|
UserAccount userAccount = dbManager.readFromDb(userId);
|
||||||
if (cache.isFull()) {
|
if (cache.isFull()) {
|
||||||
LOGGER.info("# Cache is FULL! Writing LRU data to DB...");
|
LOGGER.info("# Cache is FULL! Writing LRU data to DB...");
|
||||||
UserAccount toBeWrittenToDb = cache.getLruData();
|
UserAccount toBeWrittenToDb = cache.getLruData();
|
||||||
DbManager.upsertDb(toBeWrittenToDb);
|
dbManager.upsertDb(toBeWrittenToDb);
|
||||||
}
|
}
|
||||||
cache.set(userId, userAccount);
|
cache.set(userId, userAccount);
|
||||||
return userAccount;
|
return userAccount;
|
||||||
@ -110,12 +137,13 @@ public class CacheStore {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set user account.
|
* Set user account.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static void writeBehind(UserAccount userAccount) {
|
public void writeBehind(final UserAccount userAccount) {
|
||||||
if (cache.isFull() && !cache.contains(userAccount.getUserId())) {
|
if (cache.isFull() && !cache.contains(userAccount.getUserId())) {
|
||||||
LOGGER.info("# Cache is FULL! Writing LRU data to DB...");
|
LOGGER.info("# Cache is FULL! Writing LRU data to DB...");
|
||||||
UserAccount toBeWrittenToDb = cache.getLruData();
|
UserAccount toBeWrittenToDb = cache.getLruData();
|
||||||
DbManager.upsertDb(toBeWrittenToDb);
|
dbManager.upsertDb(toBeWrittenToDb);
|
||||||
}
|
}
|
||||||
cache.set(userAccount.getUserId(), userAccount);
|
cache.set(userAccount.getUserId(), userAccount);
|
||||||
}
|
}
|
||||||
@ -123,7 +151,7 @@ public class CacheStore {
|
|||||||
/**
|
/**
|
||||||
* Clears cache.
|
* Clears cache.
|
||||||
*/
|
*/
|
||||||
public static void clearCache() {
|
public void clearCache() {
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
@ -132,44 +160,51 @@ public class CacheStore {
|
|||||||
/**
|
/**
|
||||||
* Writes remaining content in the cache into the DB.
|
* Writes remaining content in the cache into the DB.
|
||||||
*/
|
*/
|
||||||
public static void flushCache() {
|
public void flushCache() {
|
||||||
LOGGER.info("# flushCache...");
|
LOGGER.info("# flushCache...");
|
||||||
Optional.ofNullable(cache)
|
Optional.ofNullable(cache)
|
||||||
.map(LruCache::getCacheDataInListForm)
|
.map(LruCache::getCacheDataInListForm)
|
||||||
.orElse(List.of())
|
.orElse(List.of())
|
||||||
.forEach(DbManager::updateDb);
|
.forEach(dbManager::updateDb);
|
||||||
|
dbManager.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print user accounts.
|
* Print user accounts.
|
||||||
|
* @return {@link String}
|
||||||
*/
|
*/
|
||||||
public static String print() {
|
public String print() {
|
||||||
return Optional.ofNullable(cache)
|
return Optional.ofNullable(cache)
|
||||||
.map(LruCache::getCacheDataInListForm)
|
.map(LruCache::getCacheDataInListForm)
|
||||||
.orElse(List.of())
|
.orElse(List.of())
|
||||||
.stream()
|
.stream()
|
||||||
.map(userAccount -> userAccount.toString() + "\n")
|
.map(userAccount -> userAccount.toString() + "\n")
|
||||||
.collect(Collectors.joining("", "\n--CACHE CONTENT--\n", "----\n"));
|
.collect(Collectors.joining("", "\n--CACHE CONTENT--\n", "----"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate to backing cache store.
|
* Delegate to backing cache store.
|
||||||
|
* @param userId {@link String}
|
||||||
|
* @return {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static UserAccount get(String userId) {
|
public UserAccount get(final String userId) {
|
||||||
return cache.get(userId);
|
return cache.get(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate to backing cache store.
|
* Delegate to backing cache store.
|
||||||
|
* @param userId {@link String}
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public static void set(String userId, UserAccount userAccount) {
|
public void set(final String userId, final UserAccount userAccount) {
|
||||||
cache.set(userId, userAccount);
|
cache.set(userId, userAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate to backing cache store.
|
* Delegate to backing cache store.
|
||||||
|
* @param userId {@link String}
|
||||||
*/
|
*/
|
||||||
public static void invalidate(String userId) {
|
public void invalidate(final String userId) {
|
||||||
cache.invalidate(userId);
|
cache.invalidate(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,25 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public enum CachingPolicy {
|
public enum CachingPolicy {
|
||||||
|
/**
|
||||||
|
* Through.
|
||||||
|
*/
|
||||||
THROUGH("through"),
|
THROUGH("through"),
|
||||||
|
/**
|
||||||
|
* AROUND.
|
||||||
|
*/
|
||||||
AROUND("around"),
|
AROUND("around"),
|
||||||
|
/**
|
||||||
|
* BEHIND.
|
||||||
|
*/
|
||||||
BEHIND("behind"),
|
BEHIND("behind"),
|
||||||
|
/**
|
||||||
|
* ASIDE.
|
||||||
|
*/
|
||||||
ASIDE("aside");
|
ASIDE("aside");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy value.
|
||||||
|
*/
|
||||||
private final String policy;
|
private final String policy;
|
||||||
}
|
}
|
||||||
|