Compare commits
1054 Commits
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 | ||
|
b5ed8b2278 | ||
|
8fc64a2d38 | ||
|
7e91322a43 | ||
|
e9106ccfc5 | ||
|
77ffae5ecc | ||
|
74abc7a0d6 | ||
|
ccf350b611 | ||
|
c8a2ef01d3 | ||
|
cbf1847425 | ||
|
5cf2fe009b | ||
|
0e26a6adb5 | ||
|
b423002e6c | ||
|
c150871a94 | ||
|
e9d0b3e98c | ||
|
903453229c | ||
|
c3c90e2bd4 | ||
|
268e4148b4 | ||
|
0220f3df12 | ||
|
846d05672a | ||
|
03bc4a6b9a | ||
|
cda2675221 | ||
|
a79bed9a46 | ||
|
7c01bc7464 | ||
|
edbea7d50b | ||
|
d2f926e3e8 | ||
|
fc837e289f | ||
|
fce8d25736 | ||
|
cbffcb28c8 | ||
|
7891c2b117 | ||
|
b3fc60fe92 | ||
|
2207ea4ce9 | ||
|
934578d6d2 | ||
|
cdc2a154df | ||
|
d620dbbc05 | ||
|
a86bdfd14d | ||
|
7408620a71 | ||
|
a94737075e | ||
|
3f09fb70bb | ||
|
663dbd298e | ||
|
8a9e26e77a | ||
|
462b581b34 | ||
|
9abfd5777c | ||
|
b9da15dda3 | ||
|
0010fb55c5 | ||
|
3adc3cda05 | ||
|
18a1a725ee | ||
|
25ed2540f4 | ||
|
aa46e119d6 | ||
|
7e56491e92 | ||
|
6918a4bac2 | ||
|
dea7ecfb7a | ||
|
bbc4fdfc24 | ||
|
829cd41455 | ||
|
85a05dd718 | ||
|
0c66e48d81 | ||
|
801006337a | ||
|
2aa4c963eb | ||
|
8632962362 | ||
|
5bc61c8c28 | ||
|
a94615ac54 | ||
|
14c4710435 | ||
|
428cbc1027 | ||
|
a118a995ec | ||
|
759c99d078 | ||
|
e9f73bcf0b | ||
|
29ceac2fb0 | ||
|
7255c2c5e7 | ||
|
68308dc550 | ||
|
1e10951c23 | ||
|
f3c876ed2e | ||
|
ecd1a5d07f | ||
|
8b15c24753 | ||
|
f5a6161044 | ||
|
76eefa80b5 | ||
|
c282ab80fd | ||
|
1edfb44642 | ||
|
e185c497ac | ||
|
d5a054c1f8 | ||
|
ced7a9deb0 | ||
|
90c6cf94d5 | ||
|
996bd937fb | ||
|
7931471b99 | ||
|
b8ecbaa451 | ||
|
fb4df48cb3 | ||
|
96fadf3bd7 | ||
|
dd599595cc | ||
|
fcd7785f0d | ||
|
2432d120b4 | ||
|
4b18e223cd | ||
|
13c6de036f | ||
|
6f979d0cb2 | ||
|
f084f8bf41 | ||
|
6c95868b8d | ||
|
4c7f1b7822 | ||
|
0c44b53909 | ||
|
9ead3adf73 | ||
|
97e3a3debc | ||
|
43ed09015d | ||
|
7eee546208 | ||
|
dc31960710 | ||
|
7c0fdad5a2 | ||
|
5a8933ea17 | ||
|
d02233f0b7 | ||
|
d42bcab9fc | ||
|
77b2ff2150 | ||
|
cff072d1ca | ||
|
80ba0407db | ||
|
6a09b909f2 | ||
|
53ccc0e7e6 | ||
|
a7a8e23b01 | ||
|
2783251d00 | ||
|
ac432968ae | ||
|
26b5364cbd | ||
|
f006782805 | ||
|
38cc490e3f | ||
|
911cfd64af | ||
|
2332520d67 | ||
|
af1b611136 | ||
|
4ff196ce35 | ||
|
242ae6a412 | ||
|
b689fe0a26 | ||
|
7aea765dd1 | ||
|
ea49cbfe94 | ||
|
1f4a412e70 | ||
|
36d0a3718c | ||
|
195a735814 | ||
|
633d45aa67 | ||
|
adc267e48e | ||
|
cc8d209c22 | ||
|
578b3528d5 | ||
|
5674f3c52e | ||
|
4ad2bfefad | ||
|
e5d219609d | ||
|
21ca47a22e | ||
|
ebd38bcfaa | ||
|
a3753807ae | ||
|
64266d63fd | ||
|
4f62070eb2 | ||
|
b29bd66369 | ||
|
ad435dd2fd | ||
|
a125879d15 | ||
|
dac8e659ce | ||
|
a1515b3b52 | ||
|
d2e070d21d | ||
|
82eb41b641 | ||
|
24e8fa1bad | ||
|
9017975276 | ||
|
87093cf221 | ||
|
6cb5b4a683 | ||
|
e6ddff5f25 | ||
|
b5fddd469a | ||
|
9cbc509c3a | ||
|
9c648cbdb8 | ||
|
e6cca86e25 | ||
|
c204b242df | ||
|
2e98dcf217 | ||
|
9d44eea64f | ||
|
6f592f5e8a | ||
|
74b968942f | ||
|
ebc0e8b3cd | ||
|
9088ac51f6 | ||
|
c8f7a8f0e6 | ||
|
c63af2ccbf | ||
|
9f3f5322d2 | ||
|
5607a4974c | ||
|
93aa1046aa | ||
|
a2967c5a40 | ||
|
7fd7735527 | ||
|
f6942cf18d | ||
|
ef326ee77e | ||
|
8b5f532a50 | ||
|
a1da1e4973 | ||
|
9d21dff855 | ||
|
9d75592e8b | ||
|
8d6738b729 | ||
|
3205dc2cf0 | ||
|
16e1863ae7 | ||
|
b9db3c4763 | ||
|
d72206ba72 | ||
|
922c699e49 | ||
|
bab48efd7c | ||
|
29eecfd048 | ||
|
87cf6b791c | ||
|
2e36a11e24 | ||
|
bf41b1d9c9 | ||
|
b3ef214cd6 | ||
|
6caf78e4e5 | ||
|
bd48d6ce10 | ||
|
8b26452c75 | ||
|
2bb252e08f | ||
|
a023cfbb1a | ||
|
badf0c6b8c | ||
|
c9718a5227 | ||
|
e89042a782 | ||
|
fb890e80dd | ||
|
b423fd30d4 | ||
|
3df8472bf8 | ||
|
ac98b31b68 | ||
|
46b23f322f | ||
|
e231cd8d1a | ||
|
19378f3fdd | ||
|
3f4d637510 | ||
|
25cca3547d | ||
|
b9b6777d15 | ||
|
2a5b8c977a | ||
|
daa94c7b6d | ||
|
7aca64a3c9 | ||
|
6628bccecc | ||
|
aebdb88a83 | ||
|
9c0c17b87a | ||
|
20fac32ac2 | ||
|
82842d614b | ||
|
9b71479d04 | ||
|
3c4ae6c4ca | ||
|
9ff42389c6 | ||
|
b80b9354c6 | ||
|
67d1d16e1f | ||
|
bc35911475 | ||
|
b5c6a89ec9 | ||
|
74360a7ecb | ||
|
3544a8366f | ||
|
bcca9beb4d | ||
|
6606d6cd08 | ||
|
f3fd49870c | ||
|
1fbef60f37 | ||
|
b77a05f0fb | ||
|
0ee03db4d0 | ||
|
c541176b38 | ||
|
b53856b64f | ||
|
1973d1bc63 | ||
|
f5886325ec | ||
|
8afe4c314a | ||
|
2dd2cfb8ca | ||
|
8512c65aef | ||
|
6373f7b115 | ||
|
e8b42bd135 | ||
|
2bb2134636 | ||
|
675b2f14b2 | ||
|
338c146c78 | ||
|
8135dbecdb | ||
|
a4f2d14848 | ||
|
96c16a8f3a | ||
|
47e746c3ba | ||
|
7118ccafa9 | ||
|
8983f9c11c | ||
|
9b464e0be1 | ||
|
b07d33f332 | ||
|
6c4c6097be | ||
|
9dd46d7b4a | ||
|
723afb85ba | ||
|
a0e5d061cb | ||
|
687648af0a | ||
|
96aa21d0e8 | ||
|
b8f83c326d | ||
|
15d795bf8a | ||
|
3754c66604 | ||
|
6d83ceba28 | ||
|
015b418114 | ||
|
0cba307844 | ||
|
a66edc84a0 | ||
|
c18282ad5d | ||
|
7411ea86bf | ||
|
ef033b66a6 | ||
|
e65b65257e | ||
|
3d9afbaeec | ||
|
61a819aab8 | ||
|
61b95c294b | ||
|
4068d1fead | ||
|
b284230ecf | ||
|
0529b77abb | ||
|
a2ae5d1324 | ||
|
25159ed9a8 | ||
|
7f09cd5b2d | ||
|
b388020fc0 | ||
|
0c552effc3 | ||
|
905b5dc6d8 | ||
|
885c8a6765 | ||
|
6b5b2ac1e8 | ||
|
c35b98b4d7 | ||
|
f5fddeb7f0 | ||
|
292ec5b8e5 | ||
|
60d87789a6 | ||
|
860453b46b | ||
|
6921b0dce0 | ||
|
1e385056fc | ||
|
847585334c | ||
|
9bb0b6fe6f | ||
|
31881f500d | ||
|
06f20570b6 | ||
|
017ee23793 | ||
|
6c7715ace6 | ||
|
ef43af3b23 | ||
|
95e513b6ec | ||
|
194040543e | ||
|
846a174ade | ||
|
7f60f7be25 | ||
|
cfb58191ea | ||
|
82bf9fdd61 | ||
|
be552d0ece | ||
|
d584404df6 | ||
|
353a2d9fcf | ||
|
8c5740563d | ||
|
89bda692f8 | ||
|
241f93f3cc | ||
|
57e45a329f | ||
|
79a6af703e | ||
|
00d06871f4 | ||
|
133ef52898 | ||
|
7afb065a10 | ||
|
af9f8fe4e1 | ||
|
a1c96ede13 | ||
|
0d2c4abe5a | ||
|
31471acb69 | ||
|
e7e3ace01f | ||
|
41dacc2e2e | ||
|
dc7bf6190d | ||
|
98d2dc0104 | ||
|
870d44b127 | ||
|
834f20911b | ||
|
2b7949ce6a | ||
|
4ffab7da85 | ||
|
1683fbdf9c | ||
|
d091e369ec | ||
|
b91bbc773d | ||
|
3c07a42e9d | ||
|
e99bcf772b | ||
|
2d16e5afbf | ||
|
2c6f1832b0 | ||
|
04a2be0c99 | ||
|
10815b6469 | ||
|
75b10ed657 | ||
|
108532d8dd | ||
|
5527cf4234 | ||
|
4008ae41b5 | ||
|
8166a1835d | ||
|
4c9cad5475 | ||
|
24126edd86 | ||
|
c0edac0046 | ||
|
f5c337981b | ||
|
5441db6582 | ||
|
87f3a4d956 | ||
|
31d753e59d | ||
|
6cef98d41e | ||
|
7450456dae | ||
|
45e416928d | ||
|
94c131f7e9 | ||
|
5eb9b98e78 | ||
|
8305e9365d | ||
|
04e3368a81 | ||
|
d219a104c7 | ||
|
700f5c6d27 | ||
|
f4fa73cd48 | ||
|
e09de2fb36 | ||
|
a59c9bba97 | ||
|
7acc5fbf95 | ||
|
bdf2145b3f | ||
|
1e90d0d645 | ||
|
b8c0985b97 | ||
|
c40d6ae9d7 | ||
|
76bfc68cd6 | ||
|
d0ed10a619 | ||
|
5bfaeffecf | ||
|
c0acaf073b | ||
|
9f190c59c4 | ||
|
50ed5ca699 | ||
|
08cec0e254 | ||
|
1f6e6f34ea | ||
|
134ccdb5a1 | ||
|
fa68789cd5 | ||
|
8b92bc6bb6 | ||
|
8e060ad0ad | ||
|
a5038c4329 | ||
|
b0ac4c1ca3 | ||
|
0ead283f55 | ||
|
888af23219 | ||
|
0c83ccc2fe | ||
|
a7095602d6 | ||
|
4b38746ce9 | ||
|
cd20e7a3f4 | ||
|
7f29c2455f | ||
|
51e8900d31 | ||
|
20a5dde8a4 | ||
|
bf4706addf | ||
|
97285d3724 | ||
|
f234baf258 | ||
|
ca58fa3f21 | ||
|
ca7192889d | ||
|
fa3b93bf8d | ||
|
a7b4194a71 | ||
|
054b1eaac6 | ||
|
44a654a2e3 | ||
|
10988526a2 | ||
|
b9f17824fa | ||
|
3ae7466647 | ||
|
9ff5b9e7c0 | ||
|
4941e8ebc4 | ||
|
081d789749 | ||
|
f84f7b973c | ||
|
83acaa82d4 | ||
|
b0ded54c66 | ||
|
689cc8b59b | ||
|
8c7dd72d5a | ||
|
14487261d0 | ||
|
a9b7111b39 | ||
|
b3bfd43bff | ||
|
6a8297598e | ||
|
7ac8eba434 | ||
|
595086aa13 | ||
|
38791a6a66 | ||
|
27c40826de | ||
|
d1d67bcb6c | ||
|
d41077f355 | ||
|
e4473e5c88 | ||
|
7af544998d | ||
|
0a2c87d49a | ||
|
15eb49e574 | ||
|
661f9e1373 | ||
|
7908d38604 | ||
|
41020982de | ||
|
43569ecd66 | ||
|
fb6507ceda | ||
|
29f799c815 | ||
|
55bb1f11e0 | ||
|
8364b289b4 | ||
|
417f21ed3d | ||
|
5381387026 | ||
|
f95aadc8f5 | ||
|
402b753480 | ||
|
6a28d09a3c | ||
|
1e38edec15 | ||
|
ec7a2025f0 | ||
|
de79019ece | ||
|
f2ac53edca | ||
|
c9e30390d3 | ||
|
f49f9a15b6 | ||
|
f878bf63aa | ||
|
51ef7176b1 | ||
|
46d4155328 | ||
|
a968dce586 | ||
|
047285aed7 | ||
|
4db3a1cfb2 | ||
|
075fbe7433 | ||
|
1f0a24cefa | ||
|
69341ff712 | ||
|
a1b2ab129e | ||
|
87c2644842 | ||
|
1d025b7019 | ||
|
34a36cb519 | ||
|
62ac59afda | ||
|
beffc87deb | ||
|
706c5092c1 | ||
|
e222a69964 | ||
|
9483888b5e | ||
|
73d55afd58 | ||
|
1f900d164d | ||
|
5d21a03acd | ||
|
6c9b912620 | ||
|
7fdcd2ec5a | ||
|
dafe495610 | ||
|
6f0035e7c2 | ||
|
652a68b134 | ||
|
b5fac5cf86 | ||
|
ecb7b44f97 | ||
|
1841fba831 | ||
|
325f0d93b2 | ||
|
efd8c8156e | ||
|
ae57ec75f3 | ||
|
47acedaaf7 | ||
|
65d627b2ed | ||
|
b4e4cf9cfe | ||
|
b67a019c48 | ||
|
1bbae5fd5a | ||
|
d11b2f06ea | ||
|
2a66fec6fe | ||
|
a475df845b | ||
|
1bc77a80f2 | ||
|
9b5ae765fc | ||
|
8e268cf261 | ||
|
fe2f8f74a1 | ||
|
e2a42b0051 | ||
|
54bb02f691 | ||
|
a70213f852 | ||
|
19929d9e72 | ||
|
09880e3850 | ||
|
96bfb8bd9f | ||
|
a727a1d05b | ||
|
46fdc5a54f | ||
|
8137609e2f | ||
|
e924c9399a | ||
|
d791c78501 | ||
|
ba485e2c3e | ||
|
be54dc1c7e | ||
|
ec80402fe5 | ||
|
d1de465780 | ||
|
c2fb591749 | ||
|
c5479cc882 | ||
|
7968615ad4 | ||
|
c0d7c8922e | ||
|
5a23fab795 | ||
|
8c21809dad | ||
|
37bffb4a99 | ||
|
8182405796 | ||
|
39e5436ed5 | ||
|
8d6791490b | ||
|
eb8ddde98f | ||
|
0358fcec4c | ||
|
023865ad4c | ||
|
60ab9fa3ce | ||
|
f85e4db0be | ||
|
2b095bec28 | ||
|
cfba28f9a4 | ||
|
c0d2c7fdb0 | ||
|
96344142e9 | ||
|
0bc3756250 | ||
|
d94199f5ff | ||
|
b805a7526e | ||
|
0cff538c27 | ||
|
452981669b | ||
|
2706c8fc37 | ||
|
03ebd5f353 | ||
|
5b269d5af1 | ||
|
0563ac7645 | ||
|
a5ff32c13e | ||
|
97adc13a1b | ||
|
d8f12529f2 | ||
|
4c766b9e71 | ||
|
c85d764e39 | ||
|
f360b64877 | ||
|
a77e9620b5 | ||
|
cf8e366e25 | ||
|
80605283f5 | ||
|
8ba111fe60 | ||
|
1cb9c2bcde | ||
|
d6edeee326 | ||
|
781a7c8b52 | ||
|
960adfc37a | ||
|
b3eb6ccea4 | ||
|
d609f3eec6 | ||
|
09dd0bee30 | ||
|
64eff5eb93 | ||
|
05dfd31fb7 | ||
|
2c8535e839 | ||
|
aea90ab115 | ||
|
211d7903ae | ||
|
02b6aba6ae | ||
|
76f634ff7a | ||
|
ae7a0b8a4a | ||
|
b7d122f614 | ||
|
93c11fdf23 | ||
|
ef4de30310 | ||
|
b62bed7e43 | ||
|
54c0b1725c | ||
|
9b25d302b7 | ||
|
4b88214bae | ||
|
eee409f284 | ||
|
2fdd7a11e9 | ||
|
12d392931e | ||
|
f37d697a60 | ||
|
4017c37b6f | ||
|
3e1a83e29d | ||
|
9d191324ff | ||
|
75ab3b5245 | ||
|
e0fb2d014a | ||
|
0a35cdfbe4 | ||
|
1eafb46b61 | ||
|
2ee5789c77 | ||
|
d9ed8a52b5 | ||
|
205b87cd93 | ||
|
689486267d | ||
|
9deb587c52 | ||
|
645fb20730 | ||
|
1886a6f969 | ||
|
9db997d0ae | ||
|
8982392fea | ||
|
082d63a1b3 | ||
|
6c21143303 | ||
|
172964e75c | ||
|
ab4e53a468 | ||
|
b907a2a9bc | ||
|
467f647ca2 | ||
|
a18c0f76ea | ||
|
e34de39ae7 | ||
|
c4b1b89f1f | ||
|
4d95d38b8d | ||
|
52e6ea2b68 | ||
|
d2724e8091 | ||
|
9a81ddb7d8 | ||
|
112973482d | ||
|
58e3fbfc6a | ||
|
bf01f3e68b | ||
|
58b98c54e5 | ||
|
61dfa50822 | ||
|
09cee8ffa7 | ||
|
5aacdecc6c | ||
|
eeea3c7b1f | ||
|
76fb9aff8b | ||
|
68fa6f451b | ||
|
e98ad671e9 | ||
|
4264f52d49 | ||
|
ee654cf7b2 | ||
|
51f6282e9b | ||
|
2212690468 | ||
|
4beb53b8b8 | ||
|
0b1a98137a | ||
|
bd1dbec19f | ||
|
a3564a8847 | ||
|
9e30383eb6 | ||
|
6fe219d644 | ||
|
5192beb5dd | ||
|
f4f9c1a441 | ||
|
a396d972f6 | ||
|
30678792fd | ||
|
cfa2b35bff | ||
|
5db8037b8b | ||
|
71affacee2 | ||
|
371263d1b3 | ||
|
0b41aaaa76 | ||
|
f28a63a46c | ||
|
3ea65e06bc | ||
|
1aea35f8e5 | ||
|
0f751d40cb | ||
|
92ecd63ccf | ||
|
3033e4c9fc | ||
|
e68beb40ec | ||
|
a3c4d36c3d | ||
|
1c26bd7416 | ||
|
daf53225d8 | ||
|
845da1fa16 | ||
|
d733122e7a | ||
|
2fa938c02d | ||
|
9b105d770d | ||
|
109d33c710 | ||
|
a142c06048 | ||
|
f1b27ef5c7 | ||
|
99c70af16a | ||
|
edcb520d08 | ||
|
a00622c656 | ||
|
93e5570778 | ||
|
59e050b20b | ||
|
e6c74a5fb9 | ||
|
751b3b9452 | ||
|
be1c0b8143 | ||
|
6ce33ed6df | ||
|
a4be693de6 | ||
|
80519379f1 | ||
|
95bef5f0e8 | ||
|
d429865c54 | ||
|
37a34ae174 | ||
|
67edeb806d | ||
|
0ad67c8726 | ||
|
a410004a8f | ||
|
16ef70bfdc | ||
|
6bf3a13064 | ||
|
54db4497a3 | ||
|
eaf3598807 | ||
|
4e01ca39fd | ||
|
1c558ff4c5 | ||
|
33e4a870ca | ||
|
33682ad3e8 | ||
|
2d6c372f21 | ||
|
f2bb46f9b4 | ||
|
81cc85a9cd | ||
|
f942bfa51c | ||
|
d2fdd7d82b | ||
|
365c74ddde | ||
|
728de1bb34 | ||
|
428efc7d53 | ||
|
1401accb4f | ||
|
6dba5b9b58 | ||
|
1ffb28ba4f | ||
|
c7c8940c5a | ||
|
e88ea8a870 | ||
|
8618ab64f6 | ||
|
f1471641b0 | ||
|
b99d37506f | ||
|
6c545c93e5 | ||
|
f00523f7c0 | ||
|
346cf0f793 | ||
|
20ea465b7f | ||
|
cd2a2e7711 | ||
|
310ae50248 | ||
|
670c4e43f3 | ||
|
f835d3d516 | ||
|
7d0a5c0edb | ||
|
ea57934db6 | ||
|
5681684157 | ||
|
b2b1ba95eb | ||
|
0335c61512 | ||
|
fb2c026822 | ||
|
b09b100614 | ||
|
0685a505d3 | ||
|
55769e9841 | ||
|
05e582ca3e | ||
|
a9c3df78ee | ||
|
1fbe9bbac5 | ||
|
e0b728c5e2 | ||
|
515b7e7134 | ||
|
d4b2496e60 | ||
|
7e4d0b4cdc | ||
|
8037495e04 | ||
|
6941e65cb4 | ||
|
7d845505b5 | ||
|
73f9b8bef1 | ||
|
19b129c28e | ||
|
63c707fcb1 | ||
|
cc4b990ae8 | ||
|
8747f1fd7a | ||
|
9e58edf05e | ||
|
271d7ae9bd | ||
|
26f4aa8001 | ||
|
1fdc650545 | ||
|
3ccc9baa1a | ||
|
df8a4e3b47 | ||
|
cc571f4149 | ||
|
51b444dccf | ||
|
50467c9e76 | ||
|
87af122509 | ||
|
160b737dcc | ||
|
f04fc3c0dc | ||
|
3c57bf7078 | ||
|
33ea7335b1 | ||
|
6ef840f3cf | ||
|
1e76d91929 | ||
|
390795154f | ||
|
37599eb48f | ||
|
c954a436ad | ||
|
2628cc0dfc | ||
|
0272d71851 | ||
|
329479dda0 | ||
|
c4418311c6 | ||
|
f0f0143d48 | ||
|
b92eb5229d | ||
|
9c8ad4485b | ||
|
4dae1fae57 | ||
|
5ae2ce6e2e | ||
|
7c888e8886 | ||
|
f2c91eb836 | ||
|
01e489c77b | ||
|
eae09fc07e | ||
|
7f06f3b78c | ||
|
dda09535e6 | ||
|
4f9ee0189c | ||
|
de56cbb971 | ||
|
2f49648047 | ||
|
31f27a720b | ||
|
efc17fcc70 | ||
|
6d1c0b1563 | ||
|
74c7273381 | ||
|
8f85353baf | ||
|
09b4663b9a | ||
|
1fa8a604eb | ||
|
50986fa15b | ||
|
8ecdee44c8 | ||
|
47ae477a56 | ||
|
7dc47da131 | ||
|
fbcfeb072a | ||
|
ffeee2f1a4 | ||
|
1b32e23493 | ||
|
3a4677c56d | ||
|
c4c37d77e9 | ||
|
0b17abdf11 | ||
|
7ac47b291d | ||
|
564cf1239f | ||
|
768e647108 | ||
|
a8c7771784 | ||
|
1d4a7681e2 | ||
|
55b0341c8d | ||
|
3b1a28149b | ||
|
1eb1961f1b | ||
|
cc85c73fbc | ||
|
cdb80b8ddd | ||
|
a9dfd7e809 | ||
|
fca7e9c8c7 | ||
|
91a085d3d1 | ||
|
ff52848481 | ||
|
ccc1a6340b | ||
|
a65a601835 | ||
|
c8a481bb77 | ||
|
dd971d8c19 | ||
|
6bb3438965 | ||
|
63fb8dc318 | ||
|
b50189e283 | ||
|
9f7e3fe552 | ||
|
d1767bbb51 | ||
|
5d47488fe9 | ||
|
d01a3a66b4 | ||
|
e3827945c8 | ||
|
fadad43f8b | ||
|
c7fee7bb07 | ||
|
954e7300e9 | ||
|
03e1e92b52 | ||
|
af8c5ed0dd | ||
|
349d8edebf | ||
|
12f13a631e | ||
|
0b8d78e4bf | ||
|
58d8fa1758 | ||
|
f7a53f2d17 | ||
|
70ddeaa194 | ||
|
6aeafcf2aa | ||
|
1cb1bdcb57 | ||
|
1b6cecda19 | ||
|
9403d53096 | ||
|
630532cdda | ||
|
acaa6cdc62 | ||
|
4904d7eea0 | ||
|
c81c3ff1c7 | ||
|
5fc03ee9f8 | ||
|
20b4195fb2 | ||
|
f00ebe1a8d | ||
|
2217fbc5ff | ||
|
82f9a6c232 | ||
|
f671f03d13 | ||
|
f09a7eb468 | ||
|
7c5d5f6b0d | ||
|
8a4844792f | ||
|
0c60a95d8f | ||
|
c3656109a7 | ||
|
a204383f45 | ||
|
2982db456d | ||
|
c308ca09e5 | ||
|
880b234d8f | ||
|
a5646b63c1 | ||
|
27c131c2cb | ||
|
c438ec0557 | ||
|
dd5997b495 | ||
|
e6c71b63fc | ||
|
7e698a90dd | ||
|
088bb764f3 | ||
|
47d92bbffb | ||
|
cfdfedbd2e | ||
|
72b174619f | ||
|
9ebbc421dd | ||
|
fcc1c0a27c | ||
|
6faec9901a | ||
|
e36bbbb22b | ||
|
71f26c3e59 | ||
|
795b6be17d | ||
|
90ea4506ca | ||
|
41b8d80479 | ||
|
f903d7e9a9 | ||
|
84c4b034a9 | ||
|
f5455f9887 | ||
|
2b1c09aa72 | ||
|
94ca254626 | ||
|
60171e3c87 | ||
|
933de30d42 | ||
|
364c43a73a | ||
|
218ba44dbf | ||
|
05d0f0babf | ||
|
823c58bef2 | ||
|
b03e0b8c35 | ||
|
3d62e02891 | ||
|
06fa92af2c | ||
|
6b297b701f | ||
|
5f39f7fbf7 | ||
|
019abc9980 | ||
|
b874adc296 | ||
|
9bf7a059b8 | ||
|
88fae070e6 | ||
|
f1410337b5 | ||
|
8c865e6b4d | ||
|
c653edf38f | ||
|
35dc25d480 | ||
|
318f811fea | ||
|
7f6067f19f | ||
|
11c0550559 | ||
|
085e47b50d | ||
|
61ef59de02 | ||
|
ccb257d525 | ||
|
6daaeec5c6 | ||
|
517c20960d | ||
|
36e80c4e69 | ||
|
3454941dcd | ||
|
b497d41f61 | ||
|
aaabc8f517 | ||
|
2757b210ea | ||
|
d9a567cf97 | ||
|
a113de6a14 | ||
|
f7e22a1cf6 | ||
|
c6ecf58687 | ||
|
17bfc91f45 | ||
|
0c6237c225 | ||
|
fedc2d9e47 | ||
|
b6b4602baf | ||
|
eafe52e17a | ||
|
5251ec4a93 | ||
|
26f1a608ab | ||
|
7a25c57474 | ||
|
55c7579983 | ||
|
10cb191533 | ||
|
a6749cb63e | ||
|
7b8c9b07ed | ||
|
0fa18d91c6 | ||
|
53b673d5b0 | ||
|
966c56311c | ||
|
150f72758e | ||
|
4446e74338 | ||
|
70f6e54353 | ||
|
1f1fcae513 | ||
|
2aa9e78ddd | ||
|
25ed7c09c5 | ||
|
922fd62da6 | ||
|
9e7a500743 | ||
|
21a149ee77 | ||
|
f5eaf06c1c | ||
|
3c6fb0c53b | ||
|
37ae182630 | ||
|
ab2c12e734 | ||
|
b3f0cc7e00 | ||
|
86e9c66ca5 | ||
|
a6e6c22bf6 |
1815
.all-contributorsrc
Normal file
@ -1,7 +1,6 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
#
|
||||||
# The MIT License
|
# The MIT License
|
||||||
# Copyright (c) 2014-2016 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
|
||||||
@ -22,24 +21,32 @@
|
|||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
|
||||||
# Clone gh-pages
|
jobs:
|
||||||
git clone -b gh-pages "https://${GH_REF}" ghpagesclone
|
sonar-pr:
|
||||||
cd ghpagesclone
|
docker:
|
||||||
|
- image: circleci/openjdk:11-node
|
||||||
# Init and update submodule to latest
|
steps:
|
||||||
git submodule update --init --recursive
|
- checkout
|
||||||
git submodule update --remote
|
- restore_cache:
|
||||||
|
key: jdp-sonar-pr-{{ checksum "pom.xml" }}
|
||||||
# Setup Git
|
- run: |
|
||||||
git config user.name "Travis-CI"
|
if [ -n "${CIRCLE_PR_NUMBER}" ]; then
|
||||||
git config user.email "travis@no.reply"
|
MAVEN_OPTS="-Xmx3000m" xvfb-run ./mvnw -B clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
|
||||||
|
-Dsonar.pullrequest.key=${CIRCLE_PR_NUMBER} \
|
||||||
# If there is a new version of the master branch
|
-Dsonar.pullrequest.branch=${CIRCLE_BRANCH} \
|
||||||
if git status | grep patterns > /dev/null 2>&1
|
-Dsonar.pullrequest.base=master
|
||||||
then
|
else
|
||||||
# it should be committed
|
echo "No Sonar PR analysis as this is not a pull request"
|
||||||
git add .
|
|
||||||
git commit -m ":sparkles: :up: Automagic Update via Travis-CI"
|
|
||||||
git push --quiet "https://${GH_TOKEN}:x-oauth-basic@${GH_REF}" gh-pages > /dev/null 2>&1
|
|
||||||
fi
|
fi
|
||||||
|
- save_cache:
|
||||||
|
key: jdp-sonar-pr-{{ checksum "pom.xml" }}
|
||||||
|
paths:
|
||||||
|
- ~/.m2
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
all:
|
||||||
|
jobs:
|
||||||
|
- sonar-pr
|
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
github: [iluwatar]
|
101
.github/workflows/maven-ci.yml
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
# 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
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# Disabling shallow clone for improving relevancy of SonarQube reporting
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up JDK 11.0.3
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
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
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.sonar/cache
|
||||||
|
key: ${{ runner.os }}-sonar
|
||||||
|
restore-keys: ${{ runner.os }}-sonar
|
||||||
|
|
||||||
|
# Some tests need screen access
|
||||||
|
- name: Install xvfb
|
||||||
|
run: sudo apt-get install -y xvfb
|
||||||
|
|
||||||
|
- name: Build with Maven and run SonarQube analysis
|
||||||
|
run: xvfb-run ./mvnw clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
||||||
|
env:
|
||||||
|
# These two env variables are needed for sonar analysis
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
# The MIT License
|
# The MIT License
|
||||||
# Copyright (c) 2014 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
|
||||||
@ -21,9 +21,39 @@
|
|||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
log = .
|
# This workflow will build a Java project with Maven
|
||||||
log4j.rootLogger = DEBUG, LAMBDA
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||||
|
|
||||||
log4j.appender.LAMBDA=com.amazonaws.services.lambda.runtime.log4j.LambdaAppender
|
name: Java PR Builder
|
||||||
log4j.appender.LAMBDA.layout=org.apache.log4j.PatternLayout
|
|
||||||
log4j.appender.LAMBDA.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} <%X{AWSRequestId}> %-5p %c:%L - %m%n
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
types: [ opened, reopened, synchronize ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
name: Build JDP
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
java-version: [ 11.0.3, 11 ]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: ${{ matrix.java-version }}
|
||||||
|
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
|
47
.gitignore
vendored
@ -1,20 +1,55 @@
|
|||||||
|
################## Eclipse ######################
|
||||||
target
|
target
|
||||||
.metadata
|
.metadata
|
||||||
.settings
|
.settings
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
*.class
|
*.class
|
||||||
# Package Files #
|
tmp/
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.loadpath
|
||||||
|
.recommenders
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
####### Java annotation processor (APT) ########
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
################ Package Files ##################
|
||||||
*.jar
|
*.jar
|
||||||
*.war
|
*.war
|
||||||
*.ear
|
*.ear
|
||||||
.idea
|
|
||||||
*.iml
|
|
||||||
*.swp
|
*.swp
|
||||||
datanucleus.log
|
datanucleus.log
|
||||||
/bin/
|
/bin/
|
||||||
/bin/
|
|
||||||
/bin/
|
|
||||||
*.log
|
*.log
|
||||||
data-mapper/src/main/resources/log4j.xml
|
|
||||||
event-sourcing/Journal.json
|
event-sourcing/Journal.json
|
||||||
|
|
||||||
|
################## Checkstyle ###################
|
||||||
|
.checkstyle
|
||||||
|
|
||||||
|
##################### STS #######################
|
||||||
|
.apt_generated
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
################# IntelliJ IDEA #################
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
################### NetBeans ####################
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
#################### VS Code ####################
|
||||||
|
.vscode/
|
||||||
|
125
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class MavenWrapperDownloader {
|
||||||
|
|
||||||
|
private static final String WRAPPER_VERSION = "0.5.6";
|
||||||
|
/**
|
||||||
|
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||||
|
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||||
|
* use instead of the default one.
|
||||||
|
*/
|
||||||
|
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||||
|
".mvn/wrapper/maven-wrapper.properties";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path where the maven-wrapper.jar will be saved to.
|
||||||
|
*/
|
||||||
|
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||||
|
".mvn/wrapper/maven-wrapper.jar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the property which should be used to override the default download url for the wrapper.
|
||||||
|
*/
|
||||||
|
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
System.out.println("- Downloader started");
|
||||||
|
File baseDirectory = new File(args[0]);
|
||||||
|
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||||
|
|
||||||
|
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||||
|
// wrapperUrl parameter.
|
||||||
|
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||||
|
String url = DEFAULT_DOWNLOAD_URL;
|
||||||
|
if(mavenWrapperPropertyFile.exists()) {
|
||||||
|
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||||
|
try {
|
||||||
|
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||||
|
Properties mavenWrapperProperties = new Properties();
|
||||||
|
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||||
|
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if(mavenWrapperPropertyFileInputStream != null) {
|
||||||
|
mavenWrapperPropertyFileInputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignore ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("- Downloading from: " + url);
|
||||||
|
|
||||||
|
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||||
|
if(!outputFile.getParentFile().exists()) {
|
||||||
|
if(!outputFile.getParentFile().mkdirs()) {
|
||||||
|
System.out.println(
|
||||||
|
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||||
|
try {
|
||||||
|
downloadFileFromURL(url, outputFile);
|
||||||
|
System.out.println("Done");
|
||||||
|
System.exit(0);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
System.out.println("- Error downloading");
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||||
|
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||||
|
String username = System.getenv("MVNW_USERNAME");
|
||||||
|
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||||
|
Authenticator.setDefault(new Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication(username, password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
URL website = new URL(urlString);
|
||||||
|
ReadableByteChannel rbc;
|
||||||
|
rbc = Channels.newChannel(website.openStream());
|
||||||
|
FileOutputStream fos = new FileOutputStream(destination);
|
||||||
|
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||||
|
fos.close();
|
||||||
|
rbc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@ -0,0 +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
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
|
||||||
|
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
39
.travis.yml
@ -1,39 +0,0 @@
|
|||||||
language: java
|
|
||||||
jdk:
|
|
||||||
- oraclejdk8
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- GH_REF: github.com/iluwatar/java-design-patterns.git
|
|
||||||
- secure: LxTDuNS/rBWIvKkaEqr79ImZAe48mCdoYCF41coxNXgNoippo4GIBArknqtv+XvdkiuRZ1yGyj6pn8GU33c/yn+krddTUkVCwTbVatbalW5jhQjDbHYym/JcxaK9ZS/3JTeGcWrBgiPqHEEDhCf26vPZsXoMSeVCEORVKTp1BSg=
|
|
||||||
- secure: "eoWlW9GyTJY04P8K3pxayXwU9/hmptQg/LfirispQkV9YvmziCfSzXnatnBhNfud98sCzY8BScXnb+OWLTnjLKpId4rtEqb0aJ40Jc32cUKzgzFAUn7cNcDAbUIfyPAGVqyQqfj/11wYSADwWMMOPlW97ExUtoyiH2WenXuRHso="
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- export DISPLAY=:99.0
|
|
||||||
- sh -e /etc/init.d/xvfb start
|
|
||||||
|
|
||||||
# default install command is just "mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V"
|
|
||||||
install:
|
|
||||||
- mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -e
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN
|
|
||||||
- bash update-ghpages.sh
|
|
||||||
|
|
||||||
# use latest java version available instead of travis default
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- oracle-java8-installer
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
- iluwatar@gmail.com
|
|
||||||
webhooks:
|
|
||||||
urls:
|
|
||||||
- https://webhooks.gitter.im/e/3319623945358a093a6f
|
|
||||||
on_success: change # options: [always|never|change] default: always
|
|
||||||
on_failure: always # options: [always|never|change] default: always
|
|
||||||
on_start: never # options: [always|never|change] default: always
|
|
||||||
|
|
||||||
sudo: required
|
|
@ -1,13 +0,0 @@
|
|||||||
# Code Coverage Report generation
|
|
||||||
|
|
||||||
To generate the code coverage report, execute the following command:
|
|
||||||
> mvn clean verify jacoco:report
|
|
||||||
|
|
||||||
This will generate code coverage report in each of the modules. In order to view the same, open the following file in your browser.
|
|
||||||
> target/site/jacoco/index.html
|
|
||||||
|
|
||||||
Please note that the above folder is created under each of the modules. For example:
|
|
||||||
* adapter/target/site/jacoco/index.html
|
|
||||||
* busniess-delegate/target/site/jacoco/index.html
|
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014-2016 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
|
||||||
|
314
README.md
@ -4,44 +4,336 @@
|
|||||||
|
|
||||||
# Design patterns implemented in Java
|
# Design patterns implemented in Java
|
||||||
|
|
||||||
[](https://travis-ci.org/iluwatar/java-design-patterns)
|

|
||||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||||
|
[](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)
|
||||||
[](https://sonarcloud.io/dashboard/index/com.iluwatar%3Ajava-design-patterns)
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
|
[](#contributors-)
|
||||||
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
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/>
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Design patterns are formalized best practices that the 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
|
||||||
development paradigms.
|
development paradigms.
|
||||||
|
|
||||||
Reusing design patterns helps to prevent subtle issues that can cause major
|
Reusing design patterns help prevent subtle issues that cause major
|
||||||
problems, and it also improves code readability for coders and architects who
|
problems, and it also improves code readability for coders and architects who
|
||||||
are familiar with the patterns.
|
are familiar with the patterns.
|
||||||
|
|
||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
|
This site showcases Java Design Patterns. The solutions have been developed by
|
||||||
|
experienced programmers and architects from the open-source community. The
|
||||||
|
patterns can be browsed by their high-level descriptions or by looking at their
|
||||||
|
source code. The source code examples are well commented and can be thought of as
|
||||||
|
programming tutorials on how to implement a specific pattern. We use the most
|
||||||
|
popular battle-proven open-source Java technologies.
|
||||||
|
|
||||||
Before you dive into the material, you should be familiar with various
|
Before you dive into the material, you should be familiar with various
|
||||||
Programming/Software Design Principles.
|
[Software Design Principles](https://java-design-patterns.com/principles/).
|
||||||
|
|
||||||
All designs should be as simple as possible. You should start with KISS, YAGNI,
|
All designs should be as simple as possible. You should start with KISS, YAGNI,
|
||||||
and Do The Simplest Thing That Could Possibly Work principles. Complexity and
|
and Do The Simplest Thing That Could Possibly Work principles. Complexity and
|
||||||
patterns should only be introduced when they are needed for practical
|
patterns should only be introduced when they are needed for practical
|
||||||
extensibility.
|
extensibility.
|
||||||
|
|
||||||
Once you are familiar with these concepts you can start drilling down into
|
Once you are familiar with these concepts you can start drilling down into the
|
||||||
patterns by any of the following approaches
|
[available design patterns](https://java-design-patterns.com/patterns/) by any
|
||||||
|
of the following approaches
|
||||||
|
|
||||||
- Using difficulty tags, `Difficulty-Beginner`, `Difficulty-Intermediate` & `Difficulty-Expert`.
|
- Search for a specific pattern by name. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
|
||||||
- Using pattern categories, `Creational`, `Behavioral` and others.
|
- Using tags such as `Performance`, `Gang of Four` or `Data access`.
|
||||||
- Search for a specific pattern. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
|
- Using pattern categories, `Creational`, `Behavioral`, and others.
|
||||||
|
|
||||||
|
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 while developing them.
|
||||||
|
|
||||||
# How to contribute
|
# How to contribute
|
||||||
|
|
||||||
If you are willing to contribute to the project you will find the relevant information in our [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki). We will help you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
|
If you are willing to contribute to the project you will find the relevant information in
|
||||||
|
our [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki). We will help
|
||||||
|
you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
This project is licensed under the terms of the MIT license.
|
This project is licensed under the terms of the MIT license.
|
||||||
|
|
||||||
|
# Contributors
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
<!-- markdownlint-disable -->
|
||||||
|
<table>
|
||||||
|
<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="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/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="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>
|
||||||
|
</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="http://inbravo.github.io"><img src="https://avatars3.githubusercontent.com/u/5253764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Dixit</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=inbravo" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/piyushchaudhari04"><img src="https://avatars3.githubusercontent.com/u/10268029?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piyush Kailash Chaudhari</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=piyushchaudhari04" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/joshzambales"><img src="https://avatars1.githubusercontent.com/u/8704552?v=4?s=100" width="100px;" alt=""/><br /><sub><b>joshzambales</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joshzambales" title="Code">💻</a></td>
|
||||||
|
<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>
|
||||||
|
<td align="center"><a href="http://cs.joensuu.fi/~zkhayda"><img src="https://avatars2.githubusercontent.com/u/660742?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zafar Khaydarov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://kemitix.github.io/"><img src="https://avatars1.githubusercontent.com/u/1147749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Campbell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kemitix" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Argyro-Sioziou"><img src="https://avatars0.githubusercontent.com/u/22822639?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Argyro Sioziou</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Argyro-Sioziou" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/TylerMcConville"><img src="https://avatars0.githubusercontent.com/u/4946449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>TylerMcConville</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=TylerMcConville" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/saksham93"><img src="https://avatars1.githubusercontent.com/u/37399540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>saksham93</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=saksham93" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/nikhilbarar"><img src="https://avatars2.githubusercontent.com/u/37332144?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nikhilbarar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nikhilbarar" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://colinbut.com"><img src="https://avatars2.githubusercontent.com/u/10725674?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Colin But</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=colinbut" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/ruslanpa"><img src="https://avatars2.githubusercontent.com/u/1503411?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ruslan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruslanpa" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juho Kang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JuhoKang" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/dheeraj-mummareddy"><img src="https://avatars2.githubusercontent.com/u/7002230?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dheeraj Mummareddy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dheeraj-mummareddy" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.bernardosulzbach.com"><img src="https://avatars0.githubusercontent.com/u/8271090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bernardo Sulzbach</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=bernardosulzbach" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/4lexis"><img src="https://avatars0.githubusercontent.com/u/19871727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandar Dudukovic</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=4lexis" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.yusufaytas.com"><img src="https://avatars2.githubusercontent.com/u/1049483?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yusuf Aytaş</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yusufaytas" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://futurehomes.hu"><img src="https://avatars2.githubusercontent.com/u/1001491?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihály Kuprivecz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qpi" title="Code">💻</a></td>
|
||||||
|
</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/SrdjanPaunovic"><img src="https://avatars1.githubusercontent.com/u/22815104?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Srđan Paunović</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=SrdjanPaunovic" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://sideris.xyz/"><img src="https://avatars3.githubusercontent.com/u/5484694?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Petros G. Sideris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sideris" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/pramodgupta3/"><img src="https://avatars1.githubusercontent.com/u/2184241?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pramod Gupta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AIAmPramod" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
<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>
|
||||||
|
</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://alexsomai.com"><img src="https://avatars1.githubusercontent.com/u/5720977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandru Somai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=alexsomai" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/amogozov"><img src="https://avatars3.githubusercontent.com/u/7372215?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artur Mogozov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amogozov" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/anthonycampbell"><img src="https://avatars3.githubusercontent.com/u/10249255?v=4?s=100" width="100px;" alt=""/><br /><sub><b>anthony</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anthonycampbell" title="Code">💻</a></td>
|
||||||
|
<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>
|
||||||
|
<td align="center"><a href="https://about.me/dzmitryh"><img src="https://avatars2.githubusercontent.com/u/5390492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dima Gubin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dzmitryh" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/jjjimenez100"><img src="https://avatars3.githubusercontent.com/u/22243493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joshua Jimenez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jjjimenez100" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://about.me/kaiwinter"><img src="https://avatars0.githubusercontent.com/u/110982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Winter</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kaiwinter" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/lbroman"><img src="https://avatars1.githubusercontent.com/u/86007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lbroman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=lbroman" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://przemeknowak.com"><img src="https://avatars1.githubusercontent.com/u/3254609?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Przemek</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pnowy" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/prafful1"><img src="https://avatars0.githubusercontent.com/u/14350274?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Prafful Agarwal</b></sub></a><br /><a href="#content-prafful1" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/sankypanhale"><img src="https://avatars1.githubusercontent.com/u/6478783?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sanket Panhale</b></sub></a><br /><a href="#content-sankypanhale" title="Content">🖋</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/staillebois"><img src="https://avatars0.githubusercontent.com/u/23701200?v=4?s=100" width="100px;" alt=""/><br /><sub><b>staillebois</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=staillebois" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/valdar-hu"><img src="https://avatars3.githubusercontent.com/u/17962817?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krisztián Nagy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=valdar-hu" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.vanogrid.com"><img src="https://avatars0.githubusercontent.com/u/4307918?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Ivanov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vanogrid" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/yosfik"><img src="https://avatars3.githubusercontent.com/u/4850270?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yosfik Alqadri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yosfik" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/7agustibm"><img src="https://avatars0.githubusercontent.com/u/8149332?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Agustí Becerra Milà</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=7agustibm" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Juaanma"><img src="https://avatars3.githubusercontent.com/u/7390500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Suárez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Juaanma" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://www.devsedge.net/"><img src="https://avatars0.githubusercontent.com/u/9956006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luigi Cortese</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=LuigiCortese" title="Code">💻</a></td>
|
||||||
|
</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="https://github.com/baislsl"><img src="https://avatars0.githubusercontent.com/u/17060584?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shengli Bai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=baislsl" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/besok"><img src="https://avatars2.githubusercontent.com/u/29834592?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=besok" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/dmitraver"><img src="https://avatars3.githubusercontent.com/u/1798156?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Avershin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dmitraver" title="Code">💻</a></td>
|
||||||
|
<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>
|
||||||
|
</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="http://mitchell-irvin.com"><img src="https://avatars0.githubusercontent.com/u/16233245?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mitchell Irvin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mitchellirvin" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://ranjeet-floyd.github.io"><img src="https://avatars0.githubusercontent.com/u/1992972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ranjeet</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ranjeet-floyd" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://alwayswithme.github.io"><img src="https://avatars3.githubusercontent.com/u/3234786?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PhoenixYip</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Alwayswithme" title="Code">💻</a></td>
|
||||||
|
<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>
|
||||||
|
<td align="center"><a href="https://github.com/kanwarpreet25"><img src="https://avatars0.githubusercontent.com/u/39183641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kanwarpreet25</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kanwarpreet25" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://leonmak.me"><img src="https://avatars3.githubusercontent.com/u/13071508?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leon Mak</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leonmak" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://www.wramdemark.se"><img src="https://avatars2.githubusercontent.com/u/7052193?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Per Wramdemark</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=perwramdemark" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/waisuan"><img src="https://avatars2.githubusercontent.com/u/10975700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evan Sia Wai Suan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=waisuan" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/AnaghaSasikumar"><img src="https://avatars2.githubusercontent.com/u/42939261?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AnaghaSasikumar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AnaghaSasikumar" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://christofferh.com"><img src="https://avatars1.githubusercontent.com/u/767643?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoffer Hamberg</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christofferh" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/dgruntz"><img src="https://avatars0.githubusercontent.com/u/1516800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dominik Gruntz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dgruntz" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://bitbucket.org/hannespernpeintner/"><img src="https://avatars3.githubusercontent.com/u/1679437?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hannes</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hannespernpeintner" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/leogtzr"><img src="https://avatars0.githubusercontent.com/u/1211969?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leo Gutiérrez Ramírez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leogtzr" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/npczwh"><img src="https://avatars0.githubusercontent.com/u/14066422?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zhang WH</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npczwh" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/oconnelc"><img src="https://avatars0.githubusercontent.com/u/1112973?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christopher O'Connell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=oconnelc" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/giorgosmav21"><img src="https://avatars2.githubusercontent.com/u/22855493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Mavroeidis</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=giorgosmav21" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/hbothra15"><img src="https://avatars1.githubusercontent.com/u/7418012?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hemant Bothra</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hbothra15" title="Code">💻</a> <a href="#design-hbothra15" title="Design">🎨</a></td>
|
||||||
|
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars1.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=igeligel" title="Code">💻</a></td>
|
||||||
|
</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/Azureyjt"><img src="https://avatars2.githubusercontent.com/u/18476317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Azureyjt</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Azureyjt" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/vehpsr"><img src="https://avatars2.githubusercontent.com/u/3133265?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vehpsr" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/ThatGuyWithTheHat"><img src="https://avatars0.githubusercontent.com/u/24470582?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt</b></sub></a><br /><a href="#content-ThatGuyWithTheHat" title="Content">🖋</a></td>
|
||||||
|
<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>
|
||||||
|
</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://twitter.com/StPitsios"><img src="https://avatars1.githubusercontent.com/u/6773603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stamatis Pitsios</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pitsios-s" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/qza"><img src="https://avatars3.githubusercontent.com/u/233149?v=4?s=100" width="100px;" alt=""/><br /><sub><b>qza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qza" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://tschis.github.io"><img src="https://avatars1.githubusercontent.com/u/20662669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodolfo Forte</b></sub></a><br /><a href="#content-Tschis" title="Content">🖋</a></td>
|
||||||
|
<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>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/ovidijus-okinskas/"><img src="https://avatars0.githubusercontent.com/u/20372387?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ovidijus Okinskas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=okinskas" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/robertt240"><img src="https://avatars1.githubusercontent.com/u/9137432?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert Kasperczyk</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=robertt240" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/trautonen"><img src="https://avatars3.githubusercontent.com/u/1641063?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tapio Rautonen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=trautonen" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://vk.com/yuri.orlov"><img src="https://avatars0.githubusercontent.com/u/1595733?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yuri Orlov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yorlov" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/varunu28/"><img src="https://avatars0.githubusercontent.com/u/7676016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Varun Upadhyay</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=varunu28" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/PalAditya"><img src="https://avatars2.githubusercontent.com/u/25523604?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aditya Pal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=PalAditya" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/grzesiekkedzior"><img src="https://avatars3.githubusercontent.com/u/23739158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>grzesiekkedzior</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=grzesiekkedzior" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Agrzesiekkedzior" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/sivasubramanim"><img src="https://avatars2.githubusercontent.com/u/51107434?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sivasubramani M</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sivasubramanim" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/d4gg4d"><img src="https://avatars2.githubusercontent.com/u/99457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sami Airaksinen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=d4gg4d" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/vertti"><img src="https://avatars0.githubusercontent.com/u/557751?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Janne Sinivirta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vertti" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Bobo1239"><img src="https://avatars1.githubusercontent.com/u/2302947?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris-Chengbiao Zhou</b></sub></a><br /><a href="#content-Bobo1239" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://jahhein.github.io"><img src="https://avatars2.githubusercontent.com/u/10779515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob Hein</b></sub></a><br /><a href="#content-Jahhein" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/iamrichardjones"><img src="https://avatars3.githubusercontent.com/u/14842151?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richard Jones</b></sub></a><br /><a href="#content-iamrichardjones" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://rachelcarmena.github.io"><img src="https://avatars0.githubusercontent.com/u/22792183?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rachel M. Carmena</b></sub></a><br /><a href="#content-rachelcarmena" title="Content">🖋</a></td>
|
||||||
|
</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://xiaod.info"><img src="https://avatars2.githubusercontent.com/u/21277644?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Liu</b></sub></a><br /><a href="#translation-xiaod-dev" title="Translation">🌍</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
<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>
|
||||||
|
</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://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://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>
|
||||||
|
</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://github.com/fedorskvorcov"><img src="https://avatars3.githubusercontent.com/u/43882212?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fedor Skvorcov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fedorskvorcov" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/samilAyoub"><img src="https://avatars0.githubusercontent.com/u/61546990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>samilAyoub</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samilAyoub" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/vdlald"><img src="https://avatars0.githubusercontent.com/u/29997701?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Golubinov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vdlald" title="Code">💻</a></td>
|
||||||
|
<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>
|
||||||
|
<td align="center"><a href="http://christophflick.de"><img src="https://avatars0.githubusercontent.com/u/4465376?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoph Flick</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ChFlick" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Ascenio"><img src="https://avatars1.githubusercontent.com/u/7662016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ascênio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AAscenio" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
<td align="center"><a href="https://www.linkedin.com/in/domenico-sibilio/"><img src="https://avatars2.githubusercontent.com/u/24280982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Domenico Sibilio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dsibilio" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/akashchandwani"><img src="https://avatars2.githubusercontent.com/u/3483277?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akash Chandwani</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aakashchandwani" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
<td align="center"><a href="http://www.linkedin.com/in/manannikov"><img src="https://avatars2.githubusercontent.com/u/7019769?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pavlo Manannikov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=manannikov" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/eimanip"><img src="https://avatars0.githubusercontent.com/u/20307301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eiman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eimanip" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/OrangePants-R"><img src="https://avatars0.githubusercontent.com/u/42976136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rocky</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=OrangePants-R" title="Documentation">📖</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://ibrahimalii.github.io/"><img src="https://avatars2.githubusercontent.com/u/21141301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ibrahim ali abdelghany</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AibrahimAlii" title="Reviewed Pull Requests">👀</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/gkulkarni2020"><img src="https://avatars3.githubusercontent.com/u/5161548?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Girish Kulkarni</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gkulkarni2020" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/omk13"><img src="https://avatars0.githubusercontent.com/u/59054172?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Omar Karazoun</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=omk13" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/jeff303"><img src="https://avatars0.githubusercontent.com/u/3521562?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeff Evans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jeff303" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://viveksb007.github.io"><img src="https://avatars1.githubusercontent.com/u/12713808?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vivek Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=viveksb007" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/siavashsoleymani"><img src="https://avatars2.githubusercontent.com/u/18074419?v=4?s=100" width="100px;" alt=""/><br /><sub><b>siavash</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=siavashsoleymani" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/ruchpeanuts"><img src="https://avatars0.githubusercontent.com/u/29301900?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ruchpeanuts</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruchpeanuts" title="Documentation">📖</a></td>
|
||||||
|
</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="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/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/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>
|
||||||
|
</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://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>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- markdownlint-restore -->
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
@ -4,26 +4,188 @@ 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:
|
||||||
- Java
|
- Extensibility
|
||||||
- Difficulty-Intermediate
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Achieve flexibility of untyped languages and keep the type-safety
|
|
||||||
|
Use dynamic properties and achieve flexibility of untyped languages while keeping type-safety.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
The Abstract Document pattern enables handling additional, non-static properties. This pattern
|
||||||
|
uses concept of traits to enable type safety and separate properties of different classes into
|
||||||
|
set of interfaces.
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> Consider a car that consists of multiple parts. However we don't know if the specific car really has all the parts, or just some of them. Our cars are dynamic and extremely flexible.
|
||||||
|
|
||||||
|
In plain words
|
||||||
|
|
||||||
|
> Abstract Document pattern allows attaching properties to objects without them knowing about it.
|
||||||
|
|
||||||
|
Wikipedia says
|
||||||
|
|
||||||
|
> An object-oriented structural design pattern for organizing objects in loosely typed key-value stores and exposing
|
||||||
|
the data using typed views. The purpose of the pattern is to achieve a high degree of flexibility between components
|
||||||
|
in a strongly typed language where new properties can be added to the object-tree on the fly, without losing the
|
||||||
|
support of type-safety. The pattern makes use of traits to separate different properties of a class into different
|
||||||
|
interfaces.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
Let's first define the base classes `Document` and `AbstractDocument`. They basically make the object hold a property
|
||||||
|
map and any amount of child objects.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface Document {
|
||||||
|
|
||||||
|
Void put(String key, Object value);
|
||||||
|
|
||||||
|
Object get(String key);
|
||||||
|
|
||||||
|
<T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class AbstractDocument implements Document {
|
||||||
|
|
||||||
|
private final Map<String, Object> properties;
|
||||||
|
|
||||||
|
protected AbstractDocument(Map<String, Object> properties) {
|
||||||
|
Objects.requireNonNull(properties, "properties map is required");
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void put(String key, Object value) {
|
||||||
|
properties.put(key, value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object get(String key) {
|
||||||
|
return properties.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
|
||||||
|
return Stream.ofNullable(get(key))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(el -> (List<Map<String, Object>>) el)
|
||||||
|
.findAny()
|
||||||
|
.stream()
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.map(constructor);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Next we define an enum `Property` and a set of interfaces for type, price, model and parts. This allows us to create
|
||||||
|
static looking interface to our `Car` class.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public enum Property {
|
||||||
|
|
||||||
|
PARTS, TYPE, PRICE, MODEL
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface HasType extends Document {
|
||||||
|
|
||||||
|
default Optional<String> getType() {
|
||||||
|
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface HasPrice extends Document {
|
||||||
|
|
||||||
|
default Optional<Number> getPrice() {
|
||||||
|
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public interface HasModel extends Document {
|
||||||
|
|
||||||
|
default Optional<String> getModel() {
|
||||||
|
return Optional.ofNullable((String) get(Property.MODEL.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface HasParts extends Document {
|
||||||
|
|
||||||
|
default Stream<Part> getParts() {
|
||||||
|
return children(Property.PARTS.toString(), Part::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we are ready to introduce the `Car`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
|
||||||
|
|
||||||
|
public Car(Map<String, Object> properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally here's how we construct and use the `Car` in a full example.
|
||||||
|
|
||||||
|
```java
|
||||||
|
LOGGER.info("Constructing parts and car");
|
||||||
|
|
||||||
|
var wheelProperties = Map.of(
|
||||||
|
Property.TYPE.toString(), "wheel",
|
||||||
|
Property.MODEL.toString(), "15C",
|
||||||
|
Property.PRICE.toString(), 100L);
|
||||||
|
|
||||||
|
var doorProperties = Map.of(
|
||||||
|
Property.TYPE.toString(), "door",
|
||||||
|
Property.MODEL.toString(), "Lambo",
|
||||||
|
Property.PRICE.toString(), 300L);
|
||||||
|
|
||||||
|
var carProperties = Map.of(
|
||||||
|
Property.MODEL.toString(), "300SL",
|
||||||
|
Property.PRICE.toString(), 10000L,
|
||||||
|
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
|
||||||
|
|
||||||
|
var car = new Car(carProperties);
|
||||||
|
|
||||||
|
LOGGER.info("Here is our car:");
|
||||||
|
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
|
||||||
|
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
|
||||||
|
LOGGER.info("-> parts: ");
|
||||||
|
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
|
||||||
|
p.getType().orElse(null),
|
||||||
|
p.getModel().orElse(null),
|
||||||
|
p.getPrice().orElse(null))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Constructing parts and car
|
||||||
|
// Here is our car:
|
||||||
|
// model: 300SL
|
||||||
|
// price: 10000
|
||||||
|
// parts:
|
||||||
|
// wheel/15C/100
|
||||||
|
// door/Lambo/300
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Abstract Document Pattern when
|
Use the Abstract Document Pattern when
|
||||||
|
|
||||||
* there is a need to add new properties on the fly
|
* There is a need to add new properties on the fly
|
||||||
* you want a flexible way to organize domain in tree like structure
|
* You want a flexible way to organize domain in tree like structure
|
||||||
* you want more loosely coupled system
|
* You want more loosely coupled system
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
|
* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
|
||||||
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
|
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
|
||||||
|
* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://www.amazon.com/gp/product/0470059028/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0470059028&linkId=e3aacaea7017258acf184f9f3283b492)
|
||||||
|
65
abstract-document/etc/abstract-document.urm.puml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.abstractdocument.domain.enums {
|
||||||
|
enum Property {
|
||||||
|
+ MODEL {static}
|
||||||
|
+ PARTS {static}
|
||||||
|
+ PRICE {static}
|
||||||
|
+ TYPE {static}
|
||||||
|
+ valueOf(name : String) : Property {static}
|
||||||
|
+ values() : Property[] {static}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
package com.iluwatar.abstractdocument.domain {
|
||||||
|
class Car {
|
||||||
|
+ Car(properties : Map<String, Object>)
|
||||||
|
}
|
||||||
|
interface HasModel {
|
||||||
|
+ getModel() : Optional<String>
|
||||||
|
}
|
||||||
|
interface HasParts {
|
||||||
|
+ getParts() : Stream<Part>
|
||||||
|
}
|
||||||
|
interface HasPrice {
|
||||||
|
+ getPrice() : Optional<Number>
|
||||||
|
}
|
||||||
|
interface HasType {
|
||||||
|
+ getType() : Optional<String>
|
||||||
|
}
|
||||||
|
class Part {
|
||||||
|
+ Part(properties : Map<String, Object>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
package com.iluwatar.abstractdocument {
|
||||||
|
abstract class AbstractDocument {
|
||||||
|
- properties : Map<String, Object>
|
||||||
|
# AbstractDocument(properties : Map<String, Object>)
|
||||||
|
+ children(key : String, constructor : Function<Map<String, Object>, T>) : Stream<T>
|
||||||
|
+ get(key : String) : Object
|
||||||
|
+ put(key : String, value : Object)
|
||||||
|
+ toString() : String
|
||||||
|
}
|
||||||
|
class App {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ App()
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
}
|
||||||
|
interface Document {
|
||||||
|
+ children(String, Function<Map<String, Object>, T>) : Stream<T> {abstract}
|
||||||
|
+ get(String) : Object {abstract}
|
||||||
|
+ put(String, Object) {abstract}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AbstractDocument ..|> Document
|
||||||
|
Car ..|> HasModel
|
||||||
|
Car ..|> HasPrice
|
||||||
|
Car ..|> HasParts
|
||||||
|
Car --|> AbstractDocument
|
||||||
|
HasModel --|> Document
|
||||||
|
HasParts --|> Document
|
||||||
|
HasPrice --|> Document
|
||||||
|
HasType --|> Document
|
||||||
|
Part ..|> HasType
|
||||||
|
Part ..|> HasModel
|
||||||
|
Part ..|> HasPrice
|
||||||
|
Part --|> AbstractDocument
|
||||||
|
@enduml
|
@ -2,7 +2,7 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
Copyright (c) 2014-2016 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
|
||||||
@ -23,25 +23,40 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
|
||||||
<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.21.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>abstract-document</artifactId>
|
<artifactId>abstract-document</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven assembly plugin is invoked with default setting which we have
|
||||||
|
in parent pom and specifying the class having main method -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.abstractdocument.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,17 +20,18 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation of Document interface
|
* Abstract implementation of Document interface.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractDocument implements Document {
|
public abstract class AbstractDocument implements Document {
|
||||||
|
|
||||||
@ -54,17 +55,21 @@ public abstract class AbstractDocument implements Document {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
|
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
|
||||||
Optional<List<Map<String, Object>>> any = Stream.of(get(key)).filter(el -> el != null)
|
return Stream.ofNullable(get(key))
|
||||||
.map(el -> (List<Map<String, Object>>) el).findAny();
|
.filter(Objects::nonNull)
|
||||||
return any.isPresent() ? any.get().stream().map(constructor) : Stream.empty();
|
.map(el -> (List<Map<String, Object>>) el)
|
||||||
|
.findAny()
|
||||||
|
.stream()
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.map(constructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
builder.append(getClass().getName()).append("[");
|
builder.append(getClass().getName()).append("[");
|
||||||
properties.entrySet()
|
properties.forEach((key, value) -> builder.append("[").append(key).append(" : ").append(value)
|
||||||
.forEach(e -> builder.append("[").append(e.getKey()).append(" : ").append(e.getValue()).append("]"));
|
.append("]"));
|
||||||
builder.append("]");
|
builder.append("]");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,72 +20,59 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.domain.Car;
|
import com.iluwatar.abstractdocument.domain.Car;
|
||||||
import com.iluwatar.abstractdocument.domain.HasModel;
|
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||||
import com.iluwatar.abstractdocument.domain.HasParts;
|
import java.util.List;
|
||||||
import com.iluwatar.abstractdocument.domain.HasPrice;
|
|
||||||
import com.iluwatar.abstractdocument.domain.HasType;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Abstract Document pattern enables handling additional, non-static
|
* The Abstract Document pattern enables handling additional, non-static properties. This pattern
|
||||||
* properties. This pattern uses concept of traits to enable type safety and
|
* uses concept of traits to enable type safety and separate properties of different classes into
|
||||||
* separate properties of different classes into set of interfaces.
|
* set of interfaces.
|
||||||
* <p>
|
*
|
||||||
* <p>
|
* <p>In Abstract Document pattern,({@link AbstractDocument}) fully implements {@link Document})
|
||||||
* In Abstract Document pattern,({@link AbstractDocument}) fully implements
|
* interface. Traits are then defined to enable access to properties in usual, static way.
|
||||||
* {@link Document}) interface. Traits are then defined to enable access to
|
|
||||||
* properties in usual, static way.
|
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the App
|
* Program entry point.
|
||||||
*/
|
|
||||||
public App() {
|
|
||||||
LOGGER.info("Constructing parts and car");
|
|
||||||
|
|
||||||
Map<String, Object> carProperties = new HashMap<>();
|
|
||||||
carProperties.put(HasModel.PROPERTY, "300SL");
|
|
||||||
carProperties.put(HasPrice.PROPERTY, 10000L);
|
|
||||||
|
|
||||||
Map<String, Object> wheelProperties = new HashMap<>();
|
|
||||||
wheelProperties.put(HasType.PROPERTY, "wheel");
|
|
||||||
wheelProperties.put(HasModel.PROPERTY, "15C");
|
|
||||||
wheelProperties.put(HasPrice.PROPERTY, 100L);
|
|
||||||
|
|
||||||
Map<String, Object> doorProperties = new HashMap<>();
|
|
||||||
doorProperties.put(HasType.PROPERTY, "door");
|
|
||||||
doorProperties.put(HasModel.PROPERTY, "Lambo");
|
|
||||||
doorProperties.put(HasPrice.PROPERTY, 300L);
|
|
||||||
|
|
||||||
carProperties.put(HasParts.PROPERTY, Arrays.asList(wheelProperties, doorProperties));
|
|
||||||
|
|
||||||
Car car = new Car(carProperties);
|
|
||||||
|
|
||||||
LOGGER.info("Here is our car:");
|
|
||||||
LOGGER.info("-> model: {}", car.getModel().get());
|
|
||||||
LOGGER.info("-> price: {}", car.getPrice().get());
|
|
||||||
LOGGER.info("-> parts: ");
|
|
||||||
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", p.getType().get(), p.getModel().get(), p.getPrice().get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Program entry point
|
|
||||||
*
|
*
|
||||||
* @param args command line args
|
* @param args command line args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new App();
|
LOGGER.info("Constructing parts and car");
|
||||||
}
|
|
||||||
|
|
||||||
|
var wheelProperties = Map.of(
|
||||||
|
Property.TYPE.toString(), "wheel",
|
||||||
|
Property.MODEL.toString(), "15C",
|
||||||
|
Property.PRICE.toString(), 100L);
|
||||||
|
|
||||||
|
var doorProperties = Map.of(
|
||||||
|
Property.TYPE.toString(), "door",
|
||||||
|
Property.MODEL.toString(), "Lambo",
|
||||||
|
Property.PRICE.toString(), 300L);
|
||||||
|
|
||||||
|
var carProperties = Map.of(
|
||||||
|
Property.MODEL.toString(), "300SL",
|
||||||
|
Property.PRICE.toString(), 10000L,
|
||||||
|
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
|
||||||
|
|
||||||
|
var car = new Car(carProperties);
|
||||||
|
|
||||||
|
LOGGER.info("Here is our car:");
|
||||||
|
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
|
||||||
|
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
|
||||||
|
LOGGER.info("-> parts: ");
|
||||||
|
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
|
||||||
|
p.getType().orElse(null),
|
||||||
|
p.getModel().orElse(null),
|
||||||
|
p.getPrice().orElse(null))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,6 +20,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -27,12 +28,12 @@ import java.util.function.Function;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document interface
|
* Document interface.
|
||||||
*/
|
*/
|
||||||
public interface Document {
|
public interface Document {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the value related to the key
|
* Puts the value related to the key.
|
||||||
*
|
*
|
||||||
* @param key element key
|
* @param key element key
|
||||||
* @param value element value
|
* @param value element value
|
||||||
@ -41,7 +42,7 @@ public interface Document {
|
|||||||
Void put(String key, Object value);
|
Void put(String key, Object value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value for the key
|
* Gets the value for the key.
|
||||||
*
|
*
|
||||||
* @param key element key
|
* @param key element key
|
||||||
* @return value or null
|
* @return value or null
|
||||||
@ -49,7 +50,7 @@ public interface Document {
|
|||||||
Object get(String key);
|
Object get(String key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the stream of child documents
|
* Gets the stream of child documents.
|
||||||
*
|
*
|
||||||
* @param key element key
|
* @param key element key
|
||||||
* @param constructor constructor of child class
|
* @param constructor constructor of child class
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,14 +20,14 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument.domain;
|
package com.iluwatar.abstractdocument.domain;
|
||||||
|
|
||||||
|
import com.iluwatar.abstractdocument.AbstractDocument;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.AbstractDocument;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Car entity
|
* Car entity.
|
||||||
*/
|
*/
|
||||||
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
|
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,21 +20,20 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument.domain;
|
package com.iluwatar.abstractdocument.domain;
|
||||||
|
|
||||||
|
import com.iluwatar.abstractdocument.Document;
|
||||||
|
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.Document;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasModel trait for static access to 'model' property
|
* HasModel trait for static access to 'model' property.
|
||||||
*/
|
*/
|
||||||
public interface HasModel extends Document {
|
public interface HasModel extends Document {
|
||||||
|
|
||||||
String PROPERTY = "model";
|
|
||||||
|
|
||||||
default Optional<String> getModel() {
|
default Optional<String> getModel() {
|
||||||
return Optional.ofNullable((String) get(PROPERTY));
|
return Optional.ofNullable((String) get(Property.MODEL.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,21 +20,20 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument.domain;
|
package com.iluwatar.abstractdocument.domain;
|
||||||
|
|
||||||
|
import com.iluwatar.abstractdocument.Document;
|
||||||
|
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.Document;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasParts trait for static access to 'parts' property
|
* HasParts trait for static access to 'parts' property.
|
||||||
*/
|
*/
|
||||||
public interface HasParts extends Document {
|
public interface HasParts extends Document {
|
||||||
|
|
||||||
String PROPERTY = "parts";
|
|
||||||
|
|
||||||
default Stream<Part> getParts() {
|
default Stream<Part> getParts() {
|
||||||
return children(PROPERTY, Part::new);
|
return children(Property.PARTS.toString(), Part::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,21 +20,20 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument.domain;
|
package com.iluwatar.abstractdocument.domain;
|
||||||
|
|
||||||
|
import com.iluwatar.abstractdocument.Document;
|
||||||
|
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.Document;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasPrice trait for static access to 'price' property
|
* HasPrice trait for static access to 'price' property.
|
||||||
*/
|
*/
|
||||||
public interface HasPrice extends Document {
|
public interface HasPrice extends Document {
|
||||||
|
|
||||||
String PROPERTY = "price";
|
|
||||||
|
|
||||||
default Optional<Number> getPrice() {
|
default Optional<Number> getPrice() {
|
||||||
return Optional.ofNullable((Number) get(PROPERTY));
|
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,21 +20,20 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument.domain;
|
package com.iluwatar.abstractdocument.domain;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.Document;
|
import com.iluwatar.abstractdocument.Document;
|
||||||
|
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasType trait for static access to 'type' property
|
* HasType trait for static access to 'type' property.
|
||||||
*/
|
*/
|
||||||
public interface HasType extends Document {
|
public interface HasType extends Document {
|
||||||
|
|
||||||
String PROPERTY = "type";
|
|
||||||
|
|
||||||
default Optional<String> getType() {
|
default Optional<String> getType() {
|
||||||
return Optional.ofNullable((String) get(PROPERTY));
|
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,14 +20,14 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument.domain;
|
package com.iluwatar.abstractdocument.domain;
|
||||||
|
|
||||||
|
import com.iluwatar.abstractdocument.AbstractDocument;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.AbstractDocument;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Part entity
|
* Part entity.
|
||||||
*/
|
*/
|
||||||
public class Part extends AbstractDocument implements HasType, HasModel, HasPrice {
|
public class Part extends AbstractDocument implements HasType, HasModel, HasPrice {
|
||||||
|
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.abstractdocument.domain.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum To Describe Property type.
|
||||||
|
*/
|
||||||
|
public enum Property {
|
||||||
|
|
||||||
|
PARTS, TYPE, PRICE, MODEL
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,69 +20,64 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AbstractDocument test class
|
* AbstractDocument test class
|
||||||
*/
|
*/
|
||||||
public class AbstractDocumentTest {
|
class AbstractDocumentTest {
|
||||||
|
|
||||||
private static final String KEY = "key";
|
private static final String KEY = "key";
|
||||||
private static final String VALUE = "value";
|
private static final String VALUE = "value";
|
||||||
|
|
||||||
private class DocumentImplementation extends AbstractDocument {
|
private static class DocumentImplementation extends AbstractDocument {
|
||||||
|
|
||||||
DocumentImplementation(Map<String, Object> properties) {
|
DocumentImplementation(Map<String, Object> properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DocumentImplementation document = new DocumentImplementation(new HashMap<>());
|
private final DocumentImplementation document = new DocumentImplementation(new HashMap<>());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldPutAndGetValue() {
|
void shouldPutAndGetValue() {
|
||||||
document.put(KEY, VALUE);
|
document.put(KEY, VALUE);
|
||||||
assertEquals(VALUE, document.get(KEY));
|
assertEquals(VALUE, document.get(KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldRetrieveChildren() {
|
void shouldRetrieveChildren() {
|
||||||
Map<String, Object> child1 = new HashMap<>();
|
var children = List.of(Map.of(), Map.of());
|
||||||
Map<String, Object> child2 = new HashMap<>();
|
|
||||||
List<Map<String, Object>> children = Arrays.asList(child1, child2);
|
|
||||||
|
|
||||||
document.put(KEY, children);
|
document.put(KEY, children);
|
||||||
|
|
||||||
Stream<DocumentImplementation> childrenStream = document.children(KEY, DocumentImplementation::new);
|
var childrenStream = document.children(KEY, DocumentImplementation::new);
|
||||||
assertNotNull(children);
|
assertNotNull(children);
|
||||||
assertEquals(2, childrenStream.count());
|
assertEquals(2, childrenStream.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldRetrieveEmptyStreamForNonExistingChildren() {
|
void shouldRetrieveEmptyStreamForNonExistingChildren() {
|
||||||
Stream<DocumentImplementation> children = document.children(KEY, DocumentImplementation::new);
|
var children = document.children(KEY, DocumentImplementation::new);
|
||||||
assertNotNull(children);
|
assertNotNull(children);
|
||||||
assertEquals(0, children.count());
|
assertEquals(0, children.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldIncludePropsInToString() {
|
void shouldIncludePropsInToString() {
|
||||||
Map<String, Object> props = new HashMap<>();
|
var props = Map.of(KEY, (Object) VALUE);
|
||||||
props.put(KEY, VALUE);
|
var document = new DocumentImplementation(props);
|
||||||
DocumentImplementation document = new DocumentImplementation(props);
|
assertTrue(document.toString().contains(KEY));
|
||||||
assertNotNull(document.toString().contains(KEY));
|
assertTrue(document.toString().contains(VALUE));
|
||||||
assertNotNull(document.toString().contains(VALUE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,18 +20,28 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple App test
|
* Simple App test
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
class AppTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue: Add at least one assertion to this test case.
|
||||||
|
*
|
||||||
|
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
|
||||||
|
* throws an exception.
|
||||||
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldExecuteAppWithoutException() {
|
void shouldExecuteAppWithoutException() {
|
||||||
App.main(null);
|
assertDoesNotThrow(() -> App.main(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,18 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import com.iluwatar.abstractdocument.domain.Car;
|
import com.iluwatar.abstractdocument.domain.Car;
|
||||||
import com.iluwatar.abstractdocument.domain.HasModel;
|
|
||||||
import com.iluwatar.abstractdocument.domain.HasParts;
|
|
||||||
import com.iluwatar.abstractdocument.domain.HasPrice;
|
|
||||||
import com.iluwatar.abstractdocument.domain.HasType;
|
|
||||||
import com.iluwatar.abstractdocument.domain.Part;
|
import com.iluwatar.abstractdocument.domain.Part;
|
||||||
|
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
@ -39,7 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
/**
|
/**
|
||||||
* Test for Part and Car
|
* Test for Part and Car
|
||||||
*/
|
*/
|
||||||
public class DomainTest {
|
class DomainTest {
|
||||||
|
|
||||||
private static final String TEST_PART_TYPE = "test-part-type";
|
private static final String TEST_PART_TYPE = "test-part-type";
|
||||||
private static final String TEST_PART_MODEL = "test-part-model";
|
private static final String TEST_PART_MODEL = "test-part-model";
|
||||||
@ -49,28 +46,28 @@ public class DomainTest {
|
|||||||
private static final long TEST_CAR_PRICE = 1L;
|
private static final long TEST_CAR_PRICE = 1L;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldConstructPart() {
|
void shouldConstructPart() {
|
||||||
Map<String, Object> partProperties = new HashMap<>();
|
var partProperties = Map.of(
|
||||||
partProperties.put(HasType.PROPERTY, TEST_PART_TYPE);
|
Property.TYPE.toString(), TEST_PART_TYPE,
|
||||||
partProperties.put(HasModel.PROPERTY, TEST_PART_MODEL);
|
Property.MODEL.toString(), TEST_PART_MODEL,
|
||||||
partProperties.put(HasPrice.PROPERTY, TEST_PART_PRICE);
|
Property.PRICE.toString(), (Object) TEST_PART_PRICE
|
||||||
Part part = new Part(partProperties);
|
);
|
||||||
|
var part = new Part(partProperties);
|
||||||
assertEquals(TEST_PART_TYPE, part.getType().get());
|
assertEquals(TEST_PART_TYPE, part.getType().orElseThrow());
|
||||||
assertEquals(TEST_PART_MODEL, part.getModel().get());
|
assertEquals(TEST_PART_MODEL, part.getModel().orElseThrow());
|
||||||
assertEquals(TEST_PART_PRICE, part.getPrice().get());
|
assertEquals(TEST_PART_PRICE, part.getPrice().orElseThrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldConstructCar() {
|
void shouldConstructCar() {
|
||||||
Map<String, Object> carProperties = new HashMap<>();
|
var carProperties = Map.of(
|
||||||
carProperties.put(HasModel.PROPERTY, TEST_CAR_MODEL);
|
Property.MODEL.toString(), TEST_CAR_MODEL,
|
||||||
carProperties.put(HasPrice.PROPERTY, TEST_CAR_PRICE);
|
Property.PRICE.toString(), TEST_CAR_PRICE,
|
||||||
carProperties.put(HasParts.PROPERTY, Arrays.asList(new HashMap<>(), new HashMap<>()));
|
Property.PARTS.toString(), List.of(Map.of(), Map.of())
|
||||||
Car car = new Car(carProperties);
|
);
|
||||||
|
var car = new Car(carProperties);
|
||||||
assertEquals(TEST_CAR_MODEL, car.getModel().get());
|
assertEquals(TEST_CAR_MODEL, car.getModel().orElseThrow());
|
||||||
assertEquals(TEST_CAR_PRICE, car.getPrice().get());
|
assertEquals(TEST_CAR_PRICE, car.getPrice().orElseThrow());
|
||||||
assertEquals(2, car.getParts().count());
|
assertEquals(2, car.getParts().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,23 +4,25 @@ 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:
|
||||||
- Java
|
- Gang of Four
|
||||||
- Gang Of Four
|
|
||||||
- Difficulty-Intermediate
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Also known as
|
## Also known as
|
||||||
|
|
||||||
Kit
|
Kit
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
Provide an interface for creating families of related or dependent
|
Provide an interface for creating families of related or dependent
|
||||||
objects without specifying their concrete classes.
|
objects without specifying their concrete classes.
|
||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
Real world example
|
|
||||||
|
|
||||||
> To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
|
Real-world example
|
||||||
|
|
||||||
|
> 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
|
||||||
|
|
||||||
@ -32,47 +34,50 @@ 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 kingdom
|
Translating the kingdom example above. First of all, we have some interfaces and implementation for the objects in the
|
||||||
|
kingdom.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Castle {
|
public interface Castle {
|
||||||
String getDescription();
|
String getDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface King {
|
public interface King {
|
||||||
String getDescription();
|
String getDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Army {
|
public interface Army {
|
||||||
String getDescription();
|
String getDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orcish implementations similarly...
|
// Orcish implementations similarly -> ...
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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 {
|
||||||
@ -82,45 +87,65 @@ 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
|
||||||
KingdomFactory factory = new ElfKingdomFactory();
|
var factory = new ElfKingdomFactory();
|
||||||
Castle castle = factory.createCastle();
|
var castle = factory.createCastle();
|
||||||
King king = factory.createKing();
|
var king = factory.createKing();
|
||||||
Army army = factory.createArmy();
|
var army = factory.createArmy();
|
||||||
|
|
||||||
castle.getDescription(); // Output: This is the Elven castle!
|
castle.getDescription();
|
||||||
king.getDescription(); // Output: This is the Elven king!
|
king.getDescription();
|
||||||
army.getDescription(); // Output: This is the Elven Army!
|
army.getDescription();
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
Program output:
|
||||||
The client can use FactoryMaker to create the desired concrete factory which, in turn, will produce different concrete objects (Army, King, Castle).
|
|
||||||
|
```java
|
||||||
|
This is the elven castle!
|
||||||
|
This is the elven king!
|
||||||
|
This is the elven Army!
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, we can design a factory for our different kingdom factories. In this example, we created `FactoryMaker`, responsible for returning an instance of either `ElfKingdomFactory` or `OrcKingdomFactory`.
|
||||||
|
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
|
||||||
@ -143,7 +168,7 @@ public static class FactoryMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
App app = new App();
|
var app = new App();
|
||||||
|
|
||||||
LOGGER.info("Elf Kingdom");
|
LOGGER.info("Elf Kingdom");
|
||||||
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
|
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
|
||||||
@ -157,43 +182,54 @@ public static void main(String[] args) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Abstract Factory pattern when
|
Use the Abstract Factory pattern when
|
||||||
|
|
||||||
* a 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
|
||||||
* a system should be configured with one of multiple families of products
|
* The system should be configured with one of the multiple families of products
|
||||||
* a 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.
|
||||||
* you need a run-time value to construct a particular dependency
|
* You need a run-time value to construct a particular dependency
|
||||||
* you want to decide which product to call from a family at runtime.
|
* You want to decide which product to call from a family at runtime.
|
||||||
* you need to supply one or more parameters only known at run-time before you can resolve a dependency.
|
* You need to supply one or more parameters only known at run-time before you can resolve a dependency.
|
||||||
|
* When you need consistency among products
|
||||||
|
* You don’t want to change existing code when adding new products or families of products to the program.
|
||||||
|
|
||||||
## Use Cases:
|
Example use cases
|
||||||
|
|
||||||
* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
|
* Selecting to call to the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
|
||||||
* Unit test case writing becomes much easier
|
* Unit test case writing becomes much easier
|
||||||
|
* 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.
|
||||||
|
* The code becomes more complicated than it should be since a lot of new interfaces and classes are introduced along with the pattern.
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
## Tutorial
|
|
||||||
* [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)
|
||||||
|
|
||||||
## Presentations
|
## Known uses
|
||||||
|
|
||||||
* [Abstract Factory Pattern](etc/presentation.html)
|
|
||||||
|
|
||||||
|
|
||||||
## Real world examples
|
|
||||||
|
|
||||||
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
||||||
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
||||||
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
||||||
|
|
||||||
|
## Related patterns
|
||||||
|
|
||||||
|
* [Factory Method](https://java-design-patterns.com/patterns/factory-method/)
|
||||||
|
* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||||
|
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||||
|
BIN
abstract-factory/etc/abstract-factory.urm.png
Normal file
After Width: | Height: | Size: 80 KiB |
101
abstract-factory/etc/abstract-factory.urm.puml
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.abstractfactory {
|
||||||
|
class App {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
- army : Army
|
||||||
|
- castle : Castle
|
||||||
|
- king : King
|
||||||
|
+ App()
|
||||||
|
+ createKingdom(factory : KingdomFactory)
|
||||||
|
+ getArmy() : Army
|
||||||
|
~ getArmy(factory : KingdomFactory) : Army
|
||||||
|
+ getCastle() : Castle
|
||||||
|
~ getCastle(factory : KingdomFactory) : Castle
|
||||||
|
+ getKing() : King
|
||||||
|
~ getKing(factory : KingdomFactory) : King
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
- setArmy(army : Army)
|
||||||
|
- setCastle(castle : Castle)
|
||||||
|
- setKing(king : King)
|
||||||
|
}
|
||||||
|
class FactoryMaker {
|
||||||
|
+ FactoryMaker()
|
||||||
|
+ makeFactory(type : KingdomType) : KingdomFactory {static}
|
||||||
|
}
|
||||||
|
enum KingdomType {
|
||||||
|
+ ELF {static}
|
||||||
|
+ ORC {static}
|
||||||
|
+ valueOf(name : String) : KingdomType {static}
|
||||||
|
+ values() : KingdomType[] {static}
|
||||||
|
}
|
||||||
|
interface Army {
|
||||||
|
+ getDescription() : String {abstract}
|
||||||
|
}
|
||||||
|
interface Castle {
|
||||||
|
+ getDescription() : String {abstract}
|
||||||
|
}
|
||||||
|
class ElfArmy {
|
||||||
|
~ DESCRIPTION : String {static}
|
||||||
|
+ ElfArmy()
|
||||||
|
+ getDescription() : String
|
||||||
|
}
|
||||||
|
class ElfCastle {
|
||||||
|
~ DESCRIPTION : String {static}
|
||||||
|
+ ElfCastle()
|
||||||
|
+ getDescription() : String
|
||||||
|
}
|
||||||
|
class ElfKing {
|
||||||
|
~ DESCRIPTION : String {static}
|
||||||
|
+ ElfKing()
|
||||||
|
+ getDescription() : String
|
||||||
|
}
|
||||||
|
class ElfKingdomFactory {
|
||||||
|
+ ElfKingdomFactory()
|
||||||
|
+ createArmy() : Army
|
||||||
|
+ createCastle() : Castle
|
||||||
|
+ createKing() : King
|
||||||
|
}
|
||||||
|
interface King {
|
||||||
|
+ getDescription() : String {abstract}
|
||||||
|
}
|
||||||
|
interface KingdomFactory {
|
||||||
|
+ createArmy() : Army {abstract}
|
||||||
|
+ createCastle() : Castle {abstract}
|
||||||
|
+ createKing() : King {abstract}
|
||||||
|
}
|
||||||
|
class OrcArmy {
|
||||||
|
~ DESCRIPTION : String {static}
|
||||||
|
+ OrcArmy()
|
||||||
|
+ getDescription() : String
|
||||||
|
}
|
||||||
|
class OrcCastle {
|
||||||
|
~ DESCRIPTION : String {static}
|
||||||
|
+ OrcCastle()
|
||||||
|
+ getDescription() : String
|
||||||
|
}
|
||||||
|
class OrcKing {
|
||||||
|
~ DESCRIPTION : String {static}
|
||||||
|
+ OrcKing()
|
||||||
|
+ getDescription() : String
|
||||||
|
}
|
||||||
|
class OrcKingdomFactory {
|
||||||
|
+ OrcKingdomFactory()
|
||||||
|
+ createArmy() : Army
|
||||||
|
+ createCastle() : Castle
|
||||||
|
+ createKing() : King
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KingdomType ..+ FactoryMaker
|
||||||
|
App --> "-castle" Castle
|
||||||
|
FactoryMaker ..+ App
|
||||||
|
App --> "-king" King
|
||||||
|
App --> "-army" Army
|
||||||
|
ElfArmy ..|> Army
|
||||||
|
ElfCastle ..|> Castle
|
||||||
|
ElfKing ..|> King
|
||||||
|
ElfKingdomFactory ..|> KingdomFactory
|
||||||
|
OrcArmy ..|> Army
|
||||||
|
OrcCastle ..|> Castle
|
||||||
|
OrcKing ..|> King
|
||||||
|
OrcKingdomFactory ..|> KingdomFactory
|
||||||
|
@enduml
|
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 26 KiB |
@ -1,190 +0,0 @@
|
|||||||
<!--
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
Copyright (c) 2017 Rodolfo Forte
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Design Patterns - Abstract Factory Presentation</title>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<style>
|
|
||||||
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
|
|
||||||
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
|
|
||||||
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
|
|
||||||
|
|
||||||
body { font-family: 'Droid Serif'; }
|
|
||||||
h1, h2, h3 {
|
|
||||||
font-family: 'Yanone Kaffeesatz';
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border-left: 0.3em solid rgba(0,0,0,0.5);
|
|
||||||
padding: 0 15px;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width:100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<textarea id="source">
|
|
||||||
|
|
||||||
class: center, middle
|
|
||||||
|
|
||||||
# Abstract Factory
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Also known as
|
|
||||||
|
|
||||||
* Kit
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Intent
|
|
||||||
|
|
||||||
* Provide an interface for creating families of related or dependent objects without specifying their concrete classes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Explanation
|
|
||||||
|
|
||||||
* [Wikipedia](https://en.wikipedia.org/wiki/Abstract_factory_pattern) says:
|
|
||||||
> "The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes"
|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
* In plain words:
|
|
||||||
* A factory that groups individual but related/dependent factories together without specifying their concrete classes;
|
|
||||||
* A factory of factories;
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Example
|
|
||||||
|
|
||||||
* In a factory that creates kingdoms, we need objects with common theme:
|
|
||||||
|
|
||||||
* Elven kingdom needs an Elven king, Elven castle and Elven army;
|
|
||||||
|
|
||||||
* Orcish kingdom needs an Orcish king, Orcish castle and Orcish army;
|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
* There is a dependency between the objects in the kingdom;
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Diagram
|
|
||||||
|
|
||||||
* Based on the kingdom example, the diagram below showcases the different concrete factories and their concrete products:
|
|
||||||
|
|
||||||
.center[]
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Diagram
|
|
||||||
|
|
||||||
* The class diagram below showcases the factory of factories;
|
|
||||||
|
|
||||||
* At runtime, we can define which Kingdom type is needed and pass it as a parameter to define which concrete KingdomFactory to instantiate;
|
|
||||||
|
|
||||||
* The concrete factory returned will then be able to produce the related objects of the specified type;
|
|
||||||
|
|
||||||
.center[]
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Applicability
|
|
||||||
|
|
||||||
Use the Abstract Factory pattern when:
|
|
||||||
|
|
||||||
* A system should be independent of how its products are created, composed and represented;
|
|
||||||
|
|
||||||
* A system should be configured with one of multiple families of products;
|
|
||||||
|
|
||||||
* A family of related product objects is designed to be used together, and you need to enforce this constraint;
|
|
||||||
|
|
||||||
* You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations;
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Applicability
|
|
||||||
|
|
||||||
Use the Abstract Factory pattern when:
|
|
||||||
|
|
||||||
* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer;
|
|
||||||
|
|
||||||
* You need a run-time value to construct a particular dependency;
|
|
||||||
|
|
||||||
* You want to decide which product to call from a family at runtime;
|
|
||||||
|
|
||||||
* You need to supply one or more parameters only known at run-time before you can resolve a dependency;
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#Use Cases
|
|
||||||
|
|
||||||
* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime;
|
|
||||||
* Unit test case writing becomes much easier;
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Consequences
|
|
||||||
|
|
||||||
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Real world examples
|
|
||||||
|
|
||||||
[javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
|
||||||
|
|
||||||
[javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
|
||||||
|
|
||||||
[javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Credits
|
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Tutorials
|
|
||||||
|
|
||||||
* Source code http://java-design-patterns.com/patterns/abstract-factory/
|
|
||||||
|
|
||||||
</textarea>
|
|
||||||
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
var slideshow = remark.create();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
Copyright (c) 2014-2016 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
|
||||||
@ -23,25 +23,40 @@
|
|||||||
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.21.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>abstract-factory</artifactId>
|
<artifactId>abstract-factory</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven assembly plugin is invoked with default setting which we have
|
||||||
|
in parent pom and specifying the class having main method -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.abstractfactory.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,128 +20,67 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that
|
||||||
|
* have a common theme without specifying their concrete classes. In normal usage, the client
|
||||||
|
* software creates a concrete implementation of the abstract factory and then uses the generic
|
||||||
|
* interface of the factory to create the concrete objects that are part of the theme. The client
|
||||||
|
* does not know (or care) which concrete objects it gets from each of these internal factories,
|
||||||
|
* since it uses only the generic interfaces of their products. This pattern separates the details
|
||||||
|
* of implementation of a set of objects from their general usage and relies on object composition,
|
||||||
|
* as object creation is implemented in methods exposed in the factory interface.
|
||||||
*
|
*
|
||||||
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
|
* <p>The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory})
|
||||||
* without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of
|
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
|
||||||
* the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part
|
* both concrete implementations to create a king, a castle, and an army.
|
||||||
* of the theme. The client does not know (or care) which concrete objects it gets from each of these internal
|
|
||||||
* factories, since it uses only the generic interfaces of their products. This pattern separates the details of
|
|
||||||
* implementation of a set of objects from their general usage and relies on object composition, as object creation is
|
|
||||||
* implemented in methods exposed in the factory interface.
|
|
||||||
* <p>
|
|
||||||
* The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and its implementations (
|
|
||||||
* {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both concrete implementations to create a
|
|
||||||
* king, a castle and an army.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class App {
|
@Slf4j
|
||||||
|
public class App implements Runnable {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
private final Kingdom kingdom = new Kingdom();
|
||||||
|
|
||||||
private King king;
|
public Kingdom getKingdom() {
|
||||||
private Castle castle;
|
return kingdom;
|
||||||
private Army army;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates kingdom
|
|
||||||
*/
|
|
||||||
public void createKingdom(final KingdomFactory factory) {
|
|
||||||
setKing(factory.createKing());
|
|
||||||
setCastle(factory.createCastle());
|
|
||||||
setArmy(factory.createArmy());
|
|
||||||
}
|
|
||||||
|
|
||||||
King getKing(final KingdomFactory factory) {
|
|
||||||
return factory.createKing();
|
|
||||||
}
|
|
||||||
|
|
||||||
public King getKing() {
|
|
||||||
return king;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setKing(final King king) {
|
|
||||||
this.king = king;
|
|
||||||
}
|
|
||||||
|
|
||||||
Castle getCastle(final KingdomFactory factory) {
|
|
||||||
return factory.createCastle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Castle getCastle() {
|
|
||||||
return castle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCastle(final Castle castle) {
|
|
||||||
this.castle = castle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Army getArmy(final KingdomFactory factory) {
|
|
||||||
return factory.createArmy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Army getArmy() {
|
|
||||||
return army;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setArmy(final Army army) {
|
|
||||||
this.army = army;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The factory of kingdom factories.
|
|
||||||
*/
|
|
||||||
public static class FactoryMaker {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enumeration for the different types of Kingdoms.
|
|
||||||
*/
|
|
||||||
public enum KingdomType {
|
|
||||||
ELF, ORC
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The factory method to create KingdomFactory concrete objects.
|
|
||||||
*/
|
|
||||||
public static KingdomFactory makeFactory(KingdomType type) {
|
|
||||||
switch (type) {
|
|
||||||
case ELF:
|
|
||||||
return new ElfKingdomFactory();
|
|
||||||
case ORC:
|
|
||||||
return new OrcKingdomFactory();
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("KingdomType not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point.
|
* Program entry point.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param args command line args
|
||||||
* command line args
|
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
var app = new App();
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
|
||||||
App app = new App();
|
@Override
|
||||||
|
public void run() {
|
||||||
|
LOGGER.info("elf kingdom");
|
||||||
|
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
|
LOGGER.info(kingdom.getArmy().getDescription());
|
||||||
|
LOGGER.info(kingdom.getCastle().getDescription());
|
||||||
|
LOGGER.info(kingdom.getKing().getDescription());
|
||||||
|
|
||||||
LOGGER.info("Elf Kingdom");
|
LOGGER.info("orc kingdom");
|
||||||
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
|
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
LOGGER.info(app.getArmy().getDescription());
|
LOGGER.info(kingdom.getArmy().getDescription());
|
||||||
LOGGER.info(app.getCastle().getDescription());
|
LOGGER.info(kingdom.getCastle().getDescription());
|
||||||
LOGGER.info(app.getKing().getDescription());
|
LOGGER.info(kingdom.getKing().getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
LOGGER.info("Orc Kingdom");
|
/**
|
||||||
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
|
* Creates kingdom.
|
||||||
LOGGER.info(app.getArmy().getDescription());
|
* @param kingdomType type of Kingdom
|
||||||
LOGGER.info(app.getCastle().getDescription());
|
*/
|
||||||
LOGGER.info(app.getKing().getDescription());
|
public void createKingdom(final Kingdom.FactoryMaker.KingdomType kingdomType) {
|
||||||
|
final KingdomFactory kingdomFactory = Kingdom.FactoryMaker.makeFactory(kingdomType);
|
||||||
|
kingdom.setKing(kingdomFactory.createKing());
|
||||||
|
kingdom.setCastle(kingdomFactory.createCastle());
|
||||||
|
kingdom.setArmy(kingdomFactory.createArmy());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,12 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Army interface.
|
||||||
* Army interface
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface Army {
|
public interface Army {
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,12 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Castle interface.
|
||||||
* Castle interface
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface Castle {
|
public interface Castle {
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,16 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* ElfArmy.
|
||||||
* ElfArmy
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,16 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* ElfCastle.
|
||||||
* ElfCastle
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,16 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* ElfKing.
|
||||||
* ElfKing
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,23 +20,25 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* ElfKingdomFactory concrete factory.
|
* ElfKingdomFactory concrete factory.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,12 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* King interface.
|
||||||
* King interface
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface King {
|
public interface King {
|
||||||
|
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.abstractfactory;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Kingdom {
|
||||||
|
|
||||||
|
private King king;
|
||||||
|
private Castle castle;
|
||||||
|
private Army army;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The factory of kingdom factories.
|
||||||
|
*/
|
||||||
|
public static class FactoryMaker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration for the different types of Kingdoms.
|
||||||
|
*/
|
||||||
|
public enum KingdomType {
|
||||||
|
ELF, ORC
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The factory method to create KingdomFactory concrete objects.
|
||||||
|
*/
|
||||||
|
public static KingdomFactory makeFactory(KingdomType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ELF:
|
||||||
|
return new ElfKingdomFactory();
|
||||||
|
case ORC:
|
||||||
|
return new OrcKingdomFactory();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("KingdomType not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,12 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* KingdomFactory factory interface.
|
* KingdomFactory factory interface.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface KingdomFactory {
|
public interface KingdomFactory {
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,16 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* OrcArmy.
|
||||||
* OrcArmy
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,16 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* OrcCastle.
|
||||||
* OrcCastle
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,16 +20,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* OrcKing.
|
||||||
* OrcKing
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,23 +20,25 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* OrcKingdomFactory concrete factory.
|
* OrcKingdomFactory concrete factory.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,68 +20,74 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.iluwatar.abstractfactory.App.FactoryMaker;
|
|
||||||
import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for abstract factory
|
* Tests for abstract factory.
|
||||||
*/
|
*/
|
||||||
public class AbstractFactoryTest {
|
class AbstractFactoryTest {
|
||||||
|
|
||||||
private App app = new App();
|
private final App app = new App();
|
||||||
private KingdomFactory elfFactory;
|
|
||||||
private KingdomFactory orcFactory;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp() {
|
|
||||||
elfFactory = FactoryMaker.makeFactory(KingdomType.ELF);
|
|
||||||
orcFactory = FactoryMaker.makeFactory(KingdomType.ORC);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void king() {
|
void verifyKingCreation() {
|
||||||
final King elfKing = app.getKing(elfFactory);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
|
final var elfKing = kingdom.getKing();
|
||||||
assertTrue(elfKing instanceof ElfKing);
|
assertTrue(elfKing instanceof ElfKing);
|
||||||
assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription());
|
assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription());
|
||||||
final King orcKing = app.getKing(orcFactory);
|
|
||||||
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
|
final var orcKing = kingdom.getKing();
|
||||||
assertTrue(orcKing instanceof OrcKing);
|
assertTrue(orcKing instanceof OrcKing);
|
||||||
assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription());
|
assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void castle() {
|
void verifyCastleCreation() {
|
||||||
final Castle elfCastle = app.getCastle(elfFactory);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
|
final var elfCastle = kingdom.getCastle();
|
||||||
assertTrue(elfCastle instanceof ElfCastle);
|
assertTrue(elfCastle instanceof ElfCastle);
|
||||||
assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription());
|
assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription());
|
||||||
final Castle orcCastle = app.getCastle(orcFactory);
|
|
||||||
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
|
final var orcCastle = kingdom.getCastle();
|
||||||
assertTrue(orcCastle instanceof OrcCastle);
|
assertTrue(orcCastle instanceof OrcCastle);
|
||||||
assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription());
|
assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void army() {
|
void verifyArmyCreation() {
|
||||||
final Army elfArmy = app.getArmy(elfFactory);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
|
final var kingdom = app.getKingdom();
|
||||||
|
|
||||||
|
final var elfArmy = kingdom.getArmy();
|
||||||
assertTrue(elfArmy instanceof ElfArmy);
|
assertTrue(elfArmy instanceof ElfArmy);
|
||||||
assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription());
|
assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription());
|
||||||
final Army orcArmy = app.getArmy(orcFactory);
|
|
||||||
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
|
final var orcArmy = kingdom.getArmy();
|
||||||
assertTrue(orcArmy instanceof OrcArmy);
|
assertTrue(orcArmy instanceof OrcArmy);
|
||||||
assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription());
|
assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createElfKingdom() {
|
void verifyElfKingdomCreation() {
|
||||||
app.createKingdom(elfFactory);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||||
final King king = app.getKing();
|
final var kingdom = app.getKingdom();
|
||||||
final Castle castle = app.getCastle();
|
|
||||||
final Army army = app.getArmy();
|
final var king = kingdom.getKing();
|
||||||
|
final var castle = kingdom.getCastle();
|
||||||
|
final var army = kingdom.getArmy();
|
||||||
assertTrue(king instanceof ElfKing);
|
assertTrue(king instanceof ElfKing);
|
||||||
assertEquals(ElfKing.DESCRIPTION, king.getDescription());
|
assertEquals(ElfKing.DESCRIPTION, king.getDescription());
|
||||||
assertTrue(castle instanceof ElfCastle);
|
assertTrue(castle instanceof ElfCastle);
|
||||||
@ -91,11 +97,13 @@ public class AbstractFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createOrcKingdom() {
|
void verifyOrcKingdomCreation() {
|
||||||
app.createKingdom(orcFactory);
|
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||||
final King king = app.getKing();
|
final var kingdom = app.getKingdom();
|
||||||
final Castle castle = app.getCastle();
|
|
||||||
final Army army = app.getArmy();
|
final var king = kingdom.getKing();
|
||||||
|
final var castle = kingdom.getCastle();
|
||||||
|
final var army = kingdom.getArmy();
|
||||||
assertTrue(king instanceof OrcKing);
|
assertTrue(king instanceof OrcKing);
|
||||||
assertEquals(OrcKing.DESCRIPTION, king.getDescription());
|
assertEquals(OrcKing.DESCRIPTION, king.getDescription());
|
||||||
assertTrue(castle instanceof OrcCastle);
|
assertTrue(castle instanceof OrcCastle);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,19 +20,21 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that Abstract Factory example runs without errors.
|
* Check whether the execution of the main method in {@link App} throws an exception.
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
class AppTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException {
|
void shouldExecuteApplicationWithoutException() {
|
||||||
String[] args = {};
|
|
||||||
App.main(args);
|
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
130
active-object/README.md
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
---
|
||||||
|
layout: pattern
|
||||||
|
title: Active Object
|
||||||
|
folder: active-object
|
||||||
|
permalink: /patterns/active-object/
|
||||||
|
categories: Concurrency
|
||||||
|
language: en
|
||||||
|
tags:
|
||||||
|
- Performance
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
The class that implements the active object pattern will contain a self-synchronization mechanism without using 'synchronized' methods.
|
||||||
|
|
||||||
|
Real-world example
|
||||||
|
|
||||||
|
>The Orcs are known for their wildness and untameable soul. It seems like they have their own thread of control based on previous behavior.
|
||||||
|
|
||||||
|
To implement a creature that has its own thread of control mechanism and expose its API only and not the execution itself, we can use the Active Object pattern.
|
||||||
|
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
```java
|
||||||
|
public abstract class ActiveCreature{
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
|
||||||
|
|
||||||
|
private BlockingQueue<Runnable> requests;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
public ActiveCreature(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.requests = new LinkedBlockingQueue<Runnable>();
|
||||||
|
thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
requests.take().run();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void eat() throws InterruptedException {
|
||||||
|
requests.put(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logger.info("{} is eating!",name());
|
||||||
|
logger.info("{} has finished eating!",name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void roam() throws InterruptedException {
|
||||||
|
requests.put(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logger.info("{} has started to roam the wastelands.",name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class Orc extends ActiveCreature {
|
||||||
|
|
||||||
|
public Orc(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
public static void main(String[] args) {
|
||||||
|
var app = new App();
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ActiveCreature creature;
|
||||||
|
try {
|
||||||
|
for (int i = 0;i < creatures;i++) {
|
||||||
|
creature = new Orc(Orc.class.getSimpleName().toString() + i);
|
||||||
|
creature.eat();
|
||||||
|
creature.roam();
|
||||||
|
}
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
}
|
||||||
|
Runtime.getRuntime().exit(1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
* [Android and Java Concurrency: The Active Object Pattern](https://www.youtube.com/watch?v=Cd8t2u5Qmvc)
|
BIN
active-object/etc/active-object.urm.png
Normal file
After Width: | Height: | Size: 19 KiB |
25
active-object/etc/active-object.urm.puml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.activeobject {
|
||||||
|
abstract class ActiveCreature {
|
||||||
|
- logger : Logger
|
||||||
|
- name : String
|
||||||
|
- requests : BlockingQueue<Runnable>
|
||||||
|
- thread : Thread
|
||||||
|
+ ActiveCreature(name : String)
|
||||||
|
+ eat()
|
||||||
|
+ name() : String
|
||||||
|
+ roam()
|
||||||
|
}
|
||||||
|
class App {
|
||||||
|
- creatures : Integer
|
||||||
|
- logger : Logger
|
||||||
|
+ App()
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
+ run()
|
||||||
|
}
|
||||||
|
class Orc {
|
||||||
|
+ Orc(name : String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Orc --|> ActiveCreature
|
||||||
|
@enduml
|
62
active-object/pom.xml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.iluwatar</groupId>
|
||||||
|
<artifactId>java-design-patterns</artifactId>
|
||||||
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>active-object</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven assembly plugin is invoked with default setting which we have
|
||||||
|
in parent pom and specifying the class having main method -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.activeobject.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* 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.activeobject;
|
||||||
|
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActiveCreature class is the base of the active object example.
|
||||||
|
* @author Noam Greenshtain
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class ActiveCreature {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
|
||||||
|
|
||||||
|
private BlockingQueue<Runnable> requests;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Thread thread; // Thread of execution.
|
||||||
|
|
||||||
|
private int status; // status of the thread of execution.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor and initialization.
|
||||||
|
*/
|
||||||
|
protected ActiveCreature(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.status = 0;
|
||||||
|
this.requests = new LinkedBlockingQueue<>();
|
||||||
|
thread = new Thread(() -> {
|
||||||
|
boolean infinite = true;
|
||||||
|
while (infinite) {
|
||||||
|
try {
|
||||||
|
requests.take().run();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
if (this.status != 0) {
|
||||||
|
logger.error("Thread was interrupted. --> {}", e.getMessage());
|
||||||
|
}
|
||||||
|
infinite = false;
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eats the porridge.
|
||||||
|
* @throws InterruptedException due to firing a new Runnable.
|
||||||
|
*/
|
||||||
|
public void eat() throws InterruptedException {
|
||||||
|
requests.put(() -> {
|
||||||
|
logger.info("{} is eating!",name());
|
||||||
|
logger.info("{} has finished eating!",name());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roam the wastelands.
|
||||||
|
* @throws InterruptedException due to firing a new Runnable.
|
||||||
|
*/
|
||||||
|
public void roam() throws InterruptedException {
|
||||||
|
requests.put(() ->
|
||||||
|
logger.info("{} has started to roam in the wastelands.",name())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the creature.
|
||||||
|
* @return the name of the creature.
|
||||||
|
*/
|
||||||
|
public String name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kills the thread of execution.
|
||||||
|
* @param status of the thread of execution. 0 == OK, the rest is logging an error.
|
||||||
|
*/
|
||||||
|
public void kill(int status) {
|
||||||
|
this.status = status;
|
||||||
|
this.thread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the thread of execution.
|
||||||
|
* @return the status of the thread of execution.
|
||||||
|
*/
|
||||||
|
public int getStatus() {
|
||||||
|
return this.status;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.activeobject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Active Object pattern helps to solve synchronization difficulties without using
|
||||||
|
* 'synchronized' methods. The active object will contain a thread-safe data structure
|
||||||
|
* (such as BlockingQueue) and use to synchronize method calls by moving the logic of the method
|
||||||
|
* into an invocator(usually a Runnable) and store it in the DSA.
|
||||||
|
*
|
||||||
|
* <p>In this example, we fire 20 threads to modify a value in the target class.
|
||||||
|
*/
|
||||||
|
public class App implements Runnable {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(App.class.getName());
|
||||||
|
|
||||||
|
private static final int NUM_CREATURES = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program entry point.
|
||||||
|
*
|
||||||
|
* @param args command line arguments.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
var app = new App();
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<ActiveCreature> creatures = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
for (int i = 0;i < NUM_CREATURES;i++) {
|
||||||
|
creatures.add(new Orc(Orc.class.getSimpleName() + i));
|
||||||
|
creatures.get(i).eat();
|
||||||
|
creatures.get(i).roam();
|
||||||
|
}
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} finally {
|
||||||
|
for (int i = 0;i < NUM_CREATURES;i++) {
|
||||||
|
creatures.get(i).kill(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.activeobject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the ActiveCreature class.
|
||||||
|
* @author Noam Greenshtain
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Orc extends ActiveCreature {
|
||||||
|
|
||||||
|
public Orc(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.activeobject;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
class ActiveCreatureTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void executionTest() throws InterruptedException {
|
||||||
|
ActiveCreature orc = new Orc("orc1");
|
||||||
|
assertEquals("orc1",orc.name());
|
||||||
|
assertEquals(0,orc.getStatus());
|
||||||
|
orc.eat();
|
||||||
|
orc.roam();
|
||||||
|
orc.kill(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.activeobject;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
|
class AppTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExecuteApplicationWithoutException() {
|
||||||
|
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||||
|
}
|
||||||
|
}
|
@ -4,36 +4,162 @@ 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:
|
||||||
- Java
|
- Extensibility
|
||||||
- Difficulty-Intermediate
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
|
||||||
|
Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating
|
||||||
|
the troublesome dependency cycles that are inherent to the GoF Visitor Pattern.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based
|
||||||
|
> on filtering criteria (is it Unix or DOS compatible modem).
|
||||||
|
|
||||||
|
In plain words
|
||||||
|
|
||||||
|
> Acyclic Visitor allows functions to be added to existing class hierarchies without modifying the hierarchies.
|
||||||
|
|
||||||
|
[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) says
|
||||||
|
|
||||||
|
> The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies without affecting those
|
||||||
|
> hierarchies, and without creating the dependency cycles that are inherent to the GangOfFour VisitorPattern.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
Here's the `Modem` hierarchy.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public abstract class Modem {
|
||||||
|
public abstract void accept(ModemVisitor modemVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Zoom extends Modem {
|
||||||
|
...
|
||||||
|
@Override
|
||||||
|
public void accept(ModemVisitor modemVisitor) {
|
||||||
|
if (modemVisitor instanceof ZoomVisitor) {
|
||||||
|
((ZoomVisitor) modemVisitor).visit(this);
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Hayes extends Modem {
|
||||||
|
...
|
||||||
|
@Override
|
||||||
|
public void accept(ModemVisitor modemVisitor) {
|
||||||
|
if (modemVisitor instanceof HayesVisitor) {
|
||||||
|
((HayesVisitor) modemVisitor).visit(this);
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Next we introduce the `ModemVisitor` hierarchy.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface ModemVisitor {
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface HayesVisitor extends ModemVisitor {
|
||||||
|
void visit(Hayes hayes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ZoomVisitor extends ModemVisitor {
|
||||||
|
void visit(Zoom zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConfigureForDosVisitor implements AllModemVisitor {
|
||||||
|
...
|
||||||
|
@Override
|
||||||
|
public void visit(Hayes hayes) {
|
||||||
|
LOGGER.info(hayes + " used with Dos configurator.");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void visit(Zoom zoom) {
|
||||||
|
LOGGER.info(zoom + " used with Dos configurator.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||||
|
...
|
||||||
|
@Override
|
||||||
|
public void visit(Zoom zoom) {
|
||||||
|
LOGGER.info(zoom + " used with Unix configurator.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, here are the visitors in action.
|
||||||
|
|
||||||
|
```java
|
||||||
|
var conUnix = new ConfigureForUnixVisitor();
|
||||||
|
var conDos = new ConfigureForDosVisitor();
|
||||||
|
var zoom = new Zoom();
|
||||||
|
var hayes = new Hayes();
|
||||||
|
hayes.accept(conDos);
|
||||||
|
zoom.accept(conDos);
|
||||||
|
hayes.accept(conUnix);
|
||||||
|
zoom.accept(conUnix);
|
||||||
|
```
|
||||||
|
|
||||||
|
Program output:
|
||||||
|
|
||||||
|
```
|
||||||
|
// Hayes modem used with Dos configurator.
|
||||||
|
// Zoom modem used with Dos configurator.
|
||||||
|
// Only HayesVisitor is allowed to visit Hayes modem
|
||||||
|
// Zoom modem used with Unix configurator.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Intent
|
|
||||||
Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating the troublesome dependency cycles that are inherent to the GOF VISITOR Pattern.
|
|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
This pattern can be used:
|
This pattern can be used:
|
||||||
|
|
||||||
* When you need to add a new function to an existing hierarchy without the need to alter or affect that hierarchy.
|
* When you need to add a new function to an existing hierarchy without the need to alter or affect that hierarchy.
|
||||||
* When there are functions that operate upon a hierarchy, but which do not belong in the hierarchy itself. e.g. the ConfigureForDOS / ConfigureForUnix / ConfigureForX issue.
|
* When there are functions that operate upon a hierarchy, but which do not belong in the hierarchy itself. e.g. the ConfigureForDOS / ConfigureForUnix / ConfigureForX issue.
|
||||||
* When you need to perform very different operations on an object depending upon its type.
|
* When you need to perform very different operations on an object depending upon its type.
|
||||||
* 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:
|
||||||
|
|
||||||
* No dependency cycles between class hierarchies.
|
* No dependency cycles between class hierarchies.
|
||||||
* No need to recompile all the visitors if a new one is added.
|
* No need to recompile all the visitors if a new one is added.
|
||||||
* Does not cause compilation failure in existing visitors if class hierarchy has a new member.
|
* Does not cause compilation failure in existing visitors if class hierarchy has a new member.
|
||||||
|
|
||||||
The bad:
|
The bad:
|
||||||
* Violates the principle of least surprise or Liskov's Substitution principle by showing that it can accept all visitors but actually only being interested in particular visitors.
|
|
||||||
|
* Violates [Liskov's Substitution Principle](https://java-design-patterns.com/principles/#liskov-substitution-principle) by showing that it can accept all visitors but actually only being interested in particular visitors.
|
||||||
* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy.
|
* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy.
|
||||||
|
|
||||||
## Related patterns
|
## Related patterns
|
||||||
* [Visitor Pattern](../visitor/README.md)
|
|
||||||
|
* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
* [Acyclic Visitor](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
|
|
||||||
|
* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
|
||||||
|
* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor)
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
|
||||||
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
|
||||||
<interface id="1" language="java" name="com.iluwatar.acyclicvisitor.ModemVisitor" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="860" y="67"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<class id="2" language="java" name="com.iluwatar.acyclicvisitor.Modem" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="327" y="77"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="3" language="java" name="com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="124" width="196" x="647" y="225"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="4" language="java" name="com.iluwatar.acyclicvisitor.Zoom" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="203" y="305"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<interface id="5" language="java" name="com.iluwatar.acyclicvisitor.HayesVisitor" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="1019" y="468"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<interface id="6" language="java" name="com.iluwatar.acyclicvisitor.ZoomVisitor" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="758" y="467"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<class id="7" language="java" name="com.iluwatar.acyclicvisitor.Hayes" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="479" y="307"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="8" language="java" name="com.iluwatar.acyclicvisitor.ConfigureForDosVisitor" project="acyclic-visitor"
|
|
||||||
file="/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java" binary="false"
|
|
||||||
corner="BOTTOM_RIGHT">
|
|
||||||
<position height="142" width="192" x="883" y="225"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<generalization id="9">
|
|
||||||
<end type="SOURCE" refId="7"/>
|
|
||||||
<end type="TARGET" refId="2"/>
|
|
||||||
</generalization>
|
|
||||||
<realization id="10">
|
|
||||||
<end type="SOURCE" refId="8"/>
|
|
||||||
<end type="TARGET" refId="6"/>
|
|
||||||
</realization>
|
|
||||||
<realization id="11">
|
|
||||||
<end type="SOURCE" refId="8"/>
|
|
||||||
<end type="TARGET" refId="5"/>
|
|
||||||
</realization>
|
|
||||||
<realization id="12">
|
|
||||||
<end type="SOURCE" refId="3"/>
|
|
||||||
<end type="TARGET" refId="6"/>
|
|
||||||
</realization>
|
|
||||||
<realization id="13">
|
|
||||||
<end type="SOURCE" refId="3"/>
|
|
||||||
<end type="TARGET" refId="1"/>
|
|
||||||
</realization>
|
|
||||||
<realization id="14">
|
|
||||||
<end type="SOURCE" refId="8"/>
|
|
||||||
<end type="TARGET" refId="1"/>
|
|
||||||
</realization>
|
|
||||||
<generalization id="15">
|
|
||||||
<end type="SOURCE" refId="4"/>
|
|
||||||
<end type="TARGET" refId="2"/>
|
|
||||||
</generalization>
|
|
||||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</classifier-display>
|
|
||||||
<association-display labels="true" multiplicity="true"/>
|
|
||||||
</class-diagram>
|
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 48 KiB |
53
acyclic-visitor/etc/acyclic-visitor.urm.puml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.acyclicvisitor {
|
||||||
|
interface AllModemVisitor {
|
||||||
|
}
|
||||||
|
class App {
|
||||||
|
+ App()
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
}
|
||||||
|
class ConfigureForDosVisitor {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ ConfigureForDosVisitor()
|
||||||
|
+ visit(hayes : Hayes)
|
||||||
|
+ visit(zoom : Zoom)
|
||||||
|
}
|
||||||
|
class ConfigureForUnixVisitor {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ ConfigureForUnixVisitor()
|
||||||
|
+ visit(zoom : Zoom)
|
||||||
|
}
|
||||||
|
class Hayes {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ Hayes()
|
||||||
|
+ accept(modemVisitor : ModemVisitor)
|
||||||
|
+ toString() : String
|
||||||
|
}
|
||||||
|
interface HayesVisitor {
|
||||||
|
+ visit(Hayes) {abstract}
|
||||||
|
}
|
||||||
|
abstract class Modem {
|
||||||
|
+ Modem()
|
||||||
|
+ accept(ModemVisitor) {abstract}
|
||||||
|
}
|
||||||
|
interface ModemVisitor {
|
||||||
|
}
|
||||||
|
class Zoom {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ Zoom()
|
||||||
|
+ accept(modemVisitor : ModemVisitor)
|
||||||
|
+ toString() : String
|
||||||
|
}
|
||||||
|
interface ZoomVisitor {
|
||||||
|
+ visit(Zoom) {abstract}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllModemVisitor --|> ZoomVisitor
|
||||||
|
AllModemVisitor --|> HayesVisitor
|
||||||
|
ConfigureForDosVisitor ..|> AllModemVisitor
|
||||||
|
ConfigureForUnixVisitor ..|> ZoomVisitor
|
||||||
|
Hayes --|> Modem
|
||||||
|
HayesVisitor --|> ModemVisitor
|
||||||
|
Zoom --|> Modem
|
||||||
|
ZoomVisitor --|> ModemVisitor
|
||||||
|
@enduml
|
@ -1,7 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
Copyright (c) 2014 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
|
||||||
@ -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.21.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>
|
||||||
@ -53,12 +48,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>uk.org.lidalia</groupId>
|
<groupId>uk.org.lidalia</groupId>
|
||||||
<artifactId>slf4j-test</artifactId>
|
<artifactId>slf4j-test</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.2.0</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -69,8 +59,29 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-all</artifactId>
|
<artifactId>mockito-all</artifactId>
|
||||||
<version>1.9.5</version>
|
<version>1.10.19</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven assembly plugin is invoked with default setting which we have
|
||||||
|
in parent pom and specifying the class having main method -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.acyclicvisitor.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,11 +20,12 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All ModemVisitor interface extends all visitor interfaces. This interface
|
* All ModemVisitor interface extends all visitor interfaces. This interface provides ease of use
|
||||||
* provides ease of use when a visitor needs to visit all modem types.
|
* when a visitor needs to visit all modem types.
|
||||||
*/
|
*/
|
||||||
public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
|
public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,34 +20,33 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Acyclic Visitor pattern allows new functions to be added to existing class
|
* The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies
|
||||||
* hierarchies without affecting those hierarchies, and without creating the dependency
|
* without affecting those hierarchies, and without creating the dependency cycles that are inherent
|
||||||
* cycles that are inherent to the GoF Visitor pattern, by making the Visitor base class
|
* to the GoF Visitor pattern, by making the Visitor base class degenerate
|
||||||
* degenerate
|
*
|
||||||
* <p>
|
* <p>In this example the visitor base class is {@link ModemVisitor}. The base class of the visited
|
||||||
* In this example the visitor base class is {@link ModemVisitor}. The base class of the
|
* hierarchy is {@link Modem} and has two children {@link Hayes} and {@link Zoom} each one having
|
||||||
* visited hierarchy is {@link Modem} and has two children {@link Hayes} and {@link Zoom}
|
* its own visitor interface {@link HayesVisitor} and {@link ZoomVisitor} respectively. {@link
|
||||||
* each one having its own visitor interface {@link HayesVisitor} and {@link ZoomVisitor}
|
* ConfigureForUnixVisitor} and {@link ConfigureForDosVisitor} implement each derivative's visit
|
||||||
* respectively. {@link ConfigureForUnixVisitor} and {@link ConfigureForDosVisitor}
|
* method only if it is required
|
||||||
* implement each derivative's visit method only if it is required
|
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program's entry point
|
* Program's entry point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ConfigureForUnixVisitor conUnix = new ConfigureForUnixVisitor();
|
var conUnix = new ConfigureForUnixVisitor();
|
||||||
ConfigureForDosVisitor conDos = new ConfigureForDosVisitor();
|
var conDos = new ConfigureForDosVisitor();
|
||||||
|
|
||||||
Zoom zoom = new Zoom();
|
var zoom = new Zoom();
|
||||||
Hayes hayes = new Hayes();
|
var hayes = new Hayes();
|
||||||
|
|
||||||
hayes.accept(conDos); // Hayes modem with Unix configurator
|
hayes.accept(conDos); // Hayes modem with Dos configurator
|
||||||
zoom.accept(conDos); // Zoom modem with Dos configurator
|
zoom.accept(conDos); // Zoom modem with Dos configurator
|
||||||
hayes.accept(conUnix); // Hayes modem with Unix configurator
|
hayes.accept(conUnix); // Hayes modem with Unix configurator
|
||||||
zoom.accept(conUnix); // Zoom modem with Unix configurator
|
zoom.accept(conUnix); // Zoom modem with Unix configurator
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,23 +20,24 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConfigureForDosVisitor class implements both zoom's and hayes' visit method
|
* ConfigureForDosVisitor class implements both zoom's and hayes' visit method for Dos
|
||||||
* for Dos manufacturer
|
* manufacturer.
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class ConfigureForDosVisitor implements AllModemVisitor {
|
public class ConfigureForDosVisitor implements AllModemVisitor {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
@Override
|
||||||
|
|
||||||
public void visit(Hayes hayes) {
|
public void visit(Hayes hayes) {
|
||||||
LOGGER.info(hayes + " used with Dos configurator.");
|
LOGGER.info(hayes + " used with Dos configurator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void visit(Zoom zoom) {
|
public void visit(Zoom zoom) {
|
||||||
LOGGER.info(zoom + " used with Dos configurator.");
|
LOGGER.info(zoom + " used with Dos configurator.");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,20 +20,19 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConfigureForUnixVisitor class implements zoom's visit method for Unix
|
* ConfigureForUnixVisitor class implements zoom's visit method for Unix manufacturer, unlike
|
||||||
* manufacturer, unlike traditional visitor pattern, this class may selectively implement
|
* traditional visitor pattern, this class may selectively implement visit for other modems.
|
||||||
* visit for other modems.
|
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class ConfigureForUnixVisitor implements ZoomVisitor {
|
public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForUnixVisitor.class);
|
@Override
|
||||||
|
|
||||||
public void visit(Zoom zoom) {
|
public void visit(Zoom zoom) {
|
||||||
LOGGER.info(zoom + " used with Unix configurator.");
|
LOGGER.info(zoom + " used with Unix configurator.");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,20 +20,19 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hayes class implements its accept method
|
* Hayes class implements its accept method.
|
||||||
*/
|
*/
|
||||||
public class Hayes extends Modem {
|
@Slf4j
|
||||||
|
public class Hayes implements Modem {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts all visitors but honors only HayesVisitor
|
* Accepts all visitors but honors only HayesVisitor.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void accept(ModemVisitor modemVisitor) {
|
public void accept(ModemVisitor modemVisitor) {
|
||||||
@ -46,8 +45,7 @@ public class Hayes extends Modem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hayes' modem's toString
|
* Hayes' modem's toString method.
|
||||||
* method
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,10 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HayesVisitor interface
|
* HayesVisitor interface.
|
||||||
*/
|
*/
|
||||||
public interface HayesVisitor extends ModemVisitor {
|
public interface HayesVisitor extends ModemVisitor {
|
||||||
void visit(Hayes hayes);
|
void visit(Hayes hayes);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,11 +20,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,12 +20,12 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ModemVisitor interface does not contain any visit methods so that it does not
|
* ModemVisitor interface does not contain any visit methods so that it does not depend on the
|
||||||
* depend on the visited hierarchy. Each derivative's visit method is declared in
|
* visited hierarchy. Each derivative's visit method is declared in its own visitor interface
|
||||||
* its own visitor interface
|
|
||||||
*/
|
*/
|
||||||
public interface ModemVisitor {
|
public interface ModemVisitor {
|
||||||
// Visitor is a degenerate base class for all visitors.
|
// Visitor is a degenerate base class for all visitors.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,20 +20,19 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom class implements its accept method
|
* Zoom class implements its accept method.
|
||||||
*/
|
*/
|
||||||
public class Zoom extends Modem {
|
@Slf4j
|
||||||
|
public class Zoom implements Modem {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts all visitors but honors only ZoomVisitor
|
* Accepts all visitors but honors only ZoomVisitor.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void accept(ModemVisitor modemVisitor) {
|
public void accept(ModemVisitor modemVisitor) {
|
||||||
@ -45,8 +44,7 @@ public class Zoom extends Modem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom modem's toString
|
* Zoom modem's toString method.
|
||||||
* method
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,10 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZoomVisitor interface
|
* ZoomVisitor interface.
|
||||||
*/
|
*/
|
||||||
public interface ZoomVisitor extends ModemVisitor {
|
public interface ZoomVisitor extends ModemVisitor {
|
||||||
void visit(Zoom zoom);
|
void visit(Zoom zoom);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,20 +20,28 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.iluwatar.acyclicvisitor.App;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that the Acyclic Visitor example runs without errors.
|
* Tests that the Acyclic Visitor example runs without errors.
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
class AppTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue: Add at least one assertion to this test case.
|
||||||
|
*
|
||||||
|
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
|
||||||
|
* throws an exception.
|
||||||
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
void shouldExecuteApplicationWithoutException() {
|
||||||
String[] args = {};
|
|
||||||
App.main(args);
|
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,52 +20,47 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.groups.Tuple.tuple;
|
import static org.assertj.core.groups.Tuple.tuple;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static uk.org.lidalia.slf4jext.Level.INFO;
|
import static uk.org.lidalia.slf4jext.Level.INFO;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.iluwatar.acyclicvisitor.ConfigureForDosVisitor;
|
|
||||||
import com.iluwatar.acyclicvisitor.Hayes;
|
|
||||||
import com.iluwatar.acyclicvisitor.HayesVisitor;
|
|
||||||
import com.iluwatar.acyclicvisitor.Zoom;
|
|
||||||
import com.iluwatar.acyclicvisitor.ZoomVisitor;
|
|
||||||
|
|
||||||
import uk.org.lidalia.slf4jtest.TestLogger;
|
import uk.org.lidalia.slf4jtest.TestLogger;
|
||||||
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConfigureForDosVisitor test class
|
* ConfigureForDosVisitor test class
|
||||||
*/
|
*/
|
||||||
public class ConfigureForDosVisitorTest {
|
class ConfigureForDosVisitorTest {
|
||||||
|
|
||||||
TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
|
private final TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVisitForZoom() {
|
void testVisitForZoom() {
|
||||||
ConfigureForDosVisitor conDos = new ConfigureForDosVisitor();
|
var conDos = new ConfigureForDosVisitor();
|
||||||
Zoom zoom = new Zoom();
|
var zoom = new Zoom();
|
||||||
|
|
||||||
conDos.visit(zoom);
|
conDos.visit(zoom);
|
||||||
|
|
||||||
assertThat(logger.getLoggingEvents()).extracting("level", "message").contains(
|
assertThat(logger.getLoggingEvents())
|
||||||
tuple(INFO, zoom + " used with Dos configurator."));
|
.extracting("level", "message")
|
||||||
|
.contains(tuple(INFO, zoom + " used with Dos configurator."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVisitForHayes() {
|
void testVisitForHayes() {
|
||||||
ConfigureForDosVisitor conDos = new ConfigureForDosVisitor();
|
var conDos = new ConfigureForDosVisitor();
|
||||||
Hayes hayes = new Hayes();
|
var hayes = new Hayes();
|
||||||
|
|
||||||
conDos.visit(hayes);
|
conDos.visit(hayes);
|
||||||
|
|
||||||
assertThat(logger.getLoggingEvents()).extracting("level", "message").contains(
|
assertThat(logger.getLoggingEvents())
|
||||||
tuple(INFO, hayes + " used with Dos configurator."));
|
.extracting("level", "message")
|
||||||
|
.contains(tuple(INFO, hayes + " used with Dos configurator."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,32 +20,24 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import uk.org.lidalia.slf4jtest.TestLogger;
|
||||||
|
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.groups.Tuple.tuple;
|
import static org.assertj.core.groups.Tuple.tuple;
|
||||||
import static uk.org.lidalia.slf4jext.Level.INFO;
|
import static uk.org.lidalia.slf4jext.Level.INFO;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
import uk.org.lidalia.slf4jtest.TestLogger;
|
|
||||||
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor;
|
|
||||||
import com.iluwatar.acyclicvisitor.Hayes;
|
|
||||||
import com.iluwatar.acyclicvisitor.HayesVisitor;
|
|
||||||
import com.iluwatar.acyclicvisitor.Zoom;
|
|
||||||
import com.iluwatar.acyclicvisitor.ZoomVisitor;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConfigureForUnixVisitor test class
|
* ConfigureForUnixVisitor test class
|
||||||
*/
|
*/
|
||||||
public class ConfigureForUnixVisitorTest {
|
class ConfigureForUnixVisitorTest {
|
||||||
|
|
||||||
TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForUnixVisitor.class);
|
private static final TestLogger LOGGER = TestLoggerFactory.getTestLogger(ConfigureForUnixVisitor.class);
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void clearLoggers() {
|
public void clearLoggers() {
|
||||||
@ -53,13 +45,14 @@ public class ConfigureForUnixVisitorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVisitForZoom() {
|
void testVisitForZoom() {
|
||||||
ConfigureForUnixVisitor conUnix = new ConfigureForUnixVisitor();
|
var conUnix = new ConfigureForUnixVisitor();
|
||||||
Zoom zoom = new Zoom();
|
var zoom = new Zoom();
|
||||||
|
|
||||||
conUnix.visit(zoom);
|
conUnix.visit(zoom);
|
||||||
|
|
||||||
assertThat(logger.getLoggingEvents()).extracting("level", "message").contains(
|
assertThat(LOGGER.getLoggingEvents())
|
||||||
tuple(INFO, zoom + " used with Unix configurator."));
|
.extracting("level", "message")
|
||||||
|
.contains(tuple(INFO, zoom + " used with Unix configurator."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,38 +20,32 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.acyclicvisitor;
|
|
||||||
|
|
||||||
import static org.mockito.Matchers.eq;
|
package com.iluwatar.acyclicvisitor;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.iluwatar.acyclicvisitor.ConfigureForDosVisitor;
|
import static org.mockito.Matchers.eq;
|
||||||
import com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor;
|
import static org.mockito.Mockito.*;
|
||||||
import com.iluwatar.acyclicvisitor.Hayes;
|
|
||||||
import com.iluwatar.acyclicvisitor.HayesVisitor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hayes test class
|
* Hayes test class
|
||||||
*/
|
*/
|
||||||
public class HayesTest {
|
class HayesTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptForDos() {
|
void testAcceptForDos() {
|
||||||
Hayes hayes = new Hayes();
|
var hayes = new Hayes();
|
||||||
ConfigureForDosVisitor mockVisitor = mock(ConfigureForDosVisitor.class);
|
var mockVisitor = mock(ConfigureForDosVisitor.class);
|
||||||
|
|
||||||
hayes.accept(mockVisitor);
|
hayes.accept(mockVisitor);
|
||||||
verify((HayesVisitor) mockVisitor).visit(eq(hayes));
|
verify((HayesVisitor) mockVisitor).visit(eq(hayes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptForUnix() {
|
void testAcceptForUnix() {
|
||||||
Hayes hayes = new Hayes();
|
var hayes = new Hayes();
|
||||||
ConfigureForUnixVisitor mockVisitor = mock(ConfigureForUnixVisitor.class);
|
var mockVisitor = mock(ConfigureForUnixVisitor.class);
|
||||||
|
|
||||||
hayes.accept(mockVisitor);
|
hayes.accept(mockVisitor);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,38 +20,34 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.acyclicvisitor;
|
package com.iluwatar.acyclicvisitor;
|
||||||
|
|
||||||
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.iluwatar.acyclicvisitor.ConfigureForDosVisitor;
|
import static org.mockito.Matchers.eq;
|
||||||
import com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor;
|
import static org.mockito.Mockito.mock;
|
||||||
import com.iluwatar.acyclicvisitor.Zoom;
|
import static org.mockito.Mockito.verify;
|
||||||
import com.iluwatar.acyclicvisitor.ZoomVisitor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom test class
|
* Zoom test class
|
||||||
*/
|
*/
|
||||||
public class ZoomTest {
|
class ZoomTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptForDos() {
|
void testAcceptForDos() {
|
||||||
Zoom zoom = new Zoom();
|
var zoom = new Zoom();
|
||||||
ConfigureForDosVisitor mockVisitor = mock(ConfigureForDosVisitor.class);
|
var mockVisitor = mock(ConfigureForDosVisitor.class);
|
||||||
|
|
||||||
zoom.accept(mockVisitor);
|
zoom.accept(mockVisitor);
|
||||||
verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
|
verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptForUnix() {
|
void testAcceptForUnix() {
|
||||||
Zoom zoom = new Zoom();
|
var zoom = new Zoom();
|
||||||
ConfigureForUnixVisitor mockVisitor = mock(ConfigureForUnixVisitor.class);
|
var mockVisitor = mock(ConfigureForUnixVisitor.class);
|
||||||
|
|
||||||
zoom.accept(mockVisitor);
|
zoom.accept(mockVisitor);
|
||||||
verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
|
verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
|
||||||
|
@ -4,26 +4,24 @@ title: Adapter
|
|||||||
folder: adapter
|
folder: adapter
|
||||||
permalink: /patterns/adapter/
|
permalink: /patterns/adapter/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
|
language: en
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Gang of Four
|
||||||
- Gang Of Four
|
|
||||||
- Difficulty-Beginner
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Also known as
|
## Also known as
|
||||||
Wrapper
|
Wrapper
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Convert the interface of a class into another interface the clients
|
Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that
|
||||||
expect. Adapter lets classes work together that couldn't otherwise because of
|
couldn't otherwise because of incompatible interfaces.
|
||||||
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
|
||||||
@ -38,15 +36,15 @@ 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 {
|
||||||
void row();
|
void row();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class FishingBoat {
|
public class FishingBoat {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
|
|
||||||
public void sail() {
|
public void sail() {
|
||||||
LOGGER.info("The fishing boat is sailing");
|
LOGGER.info("The fishing boat is sailing");
|
||||||
}
|
}
|
||||||
@ -56,29 +54,27 @@ public class FishingBoat {
|
|||||||
And captain expects an implementation of `RowingBoat` interface to be able to move
|
And captain expects an implementation of `RowingBoat` interface to be able to move
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Captain implements RowingBoat {
|
public class Captain {
|
||||||
|
|
||||||
private RowingBoat rowingBoat;
|
|
||||||
|
|
||||||
|
private final RowingBoat rowingBoat;
|
||||||
|
// default constructor and setter for rowingBoat
|
||||||
public Captain(RowingBoat rowingBoat) {
|
public Captain(RowingBoat rowingBoat) {
|
||||||
this.rowingBoat = rowingBoat;
|
this.rowingBoat = rowingBoat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void row() {
|
public void row() {
|
||||||
rowingBoat.row();
|
rowingBoat.row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
||||||
public class FishingBoatAdapter implements RowingBoat {
|
public class FishingBoatAdapter implements RowingBoat {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
|
private final FishingBoat boat;
|
||||||
|
|
||||||
private FishingBoat boat;
|
|
||||||
|
|
||||||
public FishingBoatAdapter() {
|
public FishingBoatAdapter() {
|
||||||
boat = new FishingBoat();
|
boat = new FishingBoat();
|
||||||
@ -94,32 +90,41 @@ public class FishingBoatAdapter implements RowingBoat {
|
|||||||
And now the `Captain` can use the `FishingBoat` to escape the pirates.
|
And now the `Captain` can use the `FishingBoat` to escape the pirates.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Captain captain = new Captain(new FishingBoatAdapter());
|
var captain = new Captain(new FishingBoatAdapter());
|
||||||
captain.row();
|
captain.row();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|

|
||||||
|
|
||||||
## 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-)
|
||||||
@ -129,5 +134,7 @@ An object adapter
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||||
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
|
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
||||||
|
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||||
|
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
|
||||||
|
BIN
adapter/etc/adapter.urm.png
Normal file
After Width: | Height: | Size: 25 KiB |
31
adapter/etc/adapter.urm.puml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.adapter {
|
||||||
|
class App {
|
||||||
|
- App()
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
}
|
||||||
|
class Captain {
|
||||||
|
- rowingBoat : RowingBoat
|
||||||
|
+ Captain()
|
||||||
|
+ Captain(boat : RowingBoat)
|
||||||
|
~ row()
|
||||||
|
~ setRowingBoat(boat : RowingBoat)
|
||||||
|
}
|
||||||
|
~class FishingBoat {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
~ FishingBoat()
|
||||||
|
~ sail()
|
||||||
|
}
|
||||||
|
class FishingBoatAdapter {
|
||||||
|
- boat : FishingBoat
|
||||||
|
+ FishingBoatAdapter()
|
||||||
|
+ row()
|
||||||
|
}
|
||||||
|
interface RowingBoat {
|
||||||
|
+ row() {abstract}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FishingBoatAdapter --> "-boat" FishingBoat
|
||||||
|
Captain --> "-rowingBoat" RowingBoat
|
||||||
|
FishingBoatAdapter ..|> RowingBoat
|
||||||
|
@enduml
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
Copyright (c) 2014-2016 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
|
||||||
@ -23,21 +23,15 @@
|
|||||||
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.21.0-SNAPSHOT</version>
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>adapter</artifactId>
|
<artifactId>adapter</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
@ -49,4 +43,25 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven assembly plugin is invoked with default setting which we have
|
||||||
|
in parent pom and specifying the class having main method -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.adapter.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,6 +20,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,33 +29,33 @@ package com.iluwatar.adapter;
|
|||||||
* The Adapter design pattern allows otherwise incompatible classes to work together by converting
|
* The Adapter design pattern allows otherwise incompatible classes to work together by converting
|
||||||
* the interface of one class into an interface expected by the clients.
|
* the interface of one class into an interface expected by the clients.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>There are two variations of the Adapter pattern: The class adapter implements the adaptee's
|
||||||
* There are two variations of the Adapter pattern: The class adapter implements the adaptee's
|
|
||||||
* interface whereas the object adapter uses composition to contain the adaptee in the adapter
|
* interface whereas the object adapter uses composition to contain the adaptee in the adapter
|
||||||
* object. This example uses the object adapter approach.
|
* object. This example uses the object adapter approach.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>The Adapter ({@link FishingBoatAdapter}) converts the interface of the adaptee class ({@link
|
||||||
* The Adapter ({@link FishingBoatAdapter}) converts the interface of the adaptee class (
|
* FishingBoat}) into a suitable one expected by the client ({@link RowingBoat}).
|
||||||
* {@link FishingBoat}) into a suitable one expected by the client ( {@link RowingBoat} ).
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The story of this implementation is this. <br>
|
|
||||||
* Pirates are coming! we need a {@link RowingBoat} to flee! We have a {@link FishingBoat} and our
|
|
||||||
* captain. We have no time to make up a new ship! we need to reuse this {@link FishingBoat}. The
|
|
||||||
* captain needs a rowing boat which he can operate. The spec is in {@link RowingBoat}. We will
|
|
||||||
* use the Adapter pattern to reuse {@link FishingBoat}.
|
|
||||||
*
|
*
|
||||||
|
* <p>The story of this implementation is this. <br> Pirates are coming! we need a {@link
|
||||||
|
* RowingBoat} to flee! We have a {@link FishingBoat} and our captain. We have no time to make up a
|
||||||
|
* new ship! we need to reuse this {@link FishingBoat}. The captain needs a rowing boat which he can
|
||||||
|
* operate. The spec is in {@link RowingBoat}. We will use the Adapter pattern to reuse {@link
|
||||||
|
* FishingBoat}.
|
||||||
*/
|
*/
|
||||||
public class App {
|
public final class App {
|
||||||
|
|
||||||
|
private App() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
||||||
// The captain can only operate rowing boats but with adapter he is able to use fishing boats as well
|
// The captain can only operate rowing boats but with adapter he is able to
|
||||||
Captain captain = new Captain(new FishingBoatAdapter());
|
// use fishing boats as well
|
||||||
|
var captain = new Captain(new FishingBoatAdapter());
|
||||||
captain.row();
|
captain.row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,27 +20,24 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Captain uses {@link RowingBoat} to sail. <br>
|
* The Captain uses {@link RowingBoat} to sail. <br> This is the client in the pattern.
|
||||||
* This is the client in the pattern.
|
|
||||||
*/
|
*/
|
||||||
public class Captain {
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public final class Captain {
|
||||||
|
|
||||||
private RowingBoat rowingBoat;
|
private RowingBoat rowingBoat;
|
||||||
|
|
||||||
public Captain() {}
|
void row() {
|
||||||
|
|
||||||
public Captain(RowingBoat rowingBoat) {
|
|
||||||
this.rowingBoat = rowingBoat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRowingBoat(RowingBoat rowingBoat) {
|
|
||||||
this.rowingBoat = rowingBoat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void row() {
|
|
||||||
rowingBoat.row();
|
rowingBoat.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,22 +20,19 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Device class (adaptee in the pattern). We want to reuse this class. Fishing boat moves by
|
||||||
* Device class (adaptee in the pattern). We want to reuse this class.
|
* sailing.
|
||||||
* Fishing boat moves by sailing.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class FishingBoat {
|
@Slf4j
|
||||||
|
final class FishingBoat {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
|
void sail() {
|
||||||
|
|
||||||
public void sail() {
|
|
||||||
LOGGER.info("The fishing boat is sailing");
|
LOGGER.info("The fishing boat is sailing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,24 +20,18 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link RowingBoat}
|
* Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link RowingBoat}
|
||||||
* interface expected by the client ({@link Captain}).
|
* interface expected by the client ({@link Captain}).
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class FishingBoatAdapter implements RowingBoat {
|
public class FishingBoatAdapter implements RowingBoat {
|
||||||
|
|
||||||
private FishingBoat boat;
|
private final FishingBoat boat = new FishingBoat();
|
||||||
|
|
||||||
public FishingBoatAdapter() {
|
public final void row() {
|
||||||
boat = new FishingBoat();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void row() {
|
|
||||||
boat.sail();
|
boat.sail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,12 +20,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface expected by the client.<br>
|
* The interface expected by the client.<br> A rowing boat is rowed to move.
|
||||||
* A rowing boat is rowed to move.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface RowingBoat {
|
public interface RowingBoat {
|
||||||
|
|
||||||
|
24
adapter/src/main/java/com/iluwatar/adapter/package-info.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.adapter;
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,6 +20,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -32,10 +33,9 @@ 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.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class AdapterPatternTest {
|
class AdapterPatternTest {
|
||||||
|
|
||||||
private Map<String, Object> beans;
|
private Map<String, Object> beans;
|
||||||
|
|
||||||
@ -50,29 +50,29 @@ public class AdapterPatternTest {
|
|||||||
public void setup() {
|
public void setup() {
|
||||||
beans = new HashMap<>();
|
beans = new HashMap<>();
|
||||||
|
|
||||||
FishingBoatAdapter fishingBoatAdapter = spy(new FishingBoatAdapter());
|
var fishingBoatAdapter = spy(new FishingBoatAdapter());
|
||||||
beans.put(FISHING_BEAN, fishingBoatAdapter);
|
beans.put(FISHING_BEAN, fishingBoatAdapter);
|
||||||
|
|
||||||
Captain captain = new Captain();
|
var captain = new Captain();
|
||||||
captain.setRowingBoat((FishingBoatAdapter) beans.get(FISHING_BEAN));
|
captain.setRowingBoat((FishingBoatAdapter) beans.get(FISHING_BEAN));
|
||||||
beans.put(ROWING_BEAN, captain);
|
beans.put(ROWING_BEAN, captain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test asserts that when we use the row() method on a captain bean(client), it is
|
* This test asserts that when we use the row() method on a captain bean(client), it is internally
|
||||||
* internally calling sail method on the fishing boat object. The Adapter ({@link FishingBoatAdapter}
|
* calling sail method on the fishing boat object. The Adapter ({@link FishingBoatAdapter} )
|
||||||
* ) converts the interface of the target class ( {@link FishingBoat}) into a suitable one
|
* converts the interface of the target class ( {@link FishingBoat}) into a suitable one expected
|
||||||
* expected by the client ({@link Captain} ).
|
* by the client ({@link Captain} ).
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testAdapter() {
|
void testAdapter() {
|
||||||
Captain captain = (Captain) beans.get(ROWING_BEAN);
|
var captain = (Captain) beans.get(ROWING_BEAN);
|
||||||
|
|
||||||
// when captain moves
|
// when captain moves
|
||||||
captain.row();
|
captain.row();
|
||||||
|
|
||||||
// the captain internally calls the battleship object to move
|
// the captain internally calls the battleship object to move
|
||||||
RowingBoat adapter = (RowingBoat) beans.get(FISHING_BEAN);
|
var adapter = (RowingBoat) beans.get(FISHING_BEAN);
|
||||||
verify(adapter).row();
|
verify(adapter).row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 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
|
||||||
@ -20,19 +20,26 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that Adapter example runs without errors.
|
* Tests that Adapter example runs without errors.
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
class AppTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the execution of the main method in {@link App}
|
||||||
|
* throws an exception.
|
||||||
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException {
|
void shouldExecuteApplicationWithoutException() {
|
||||||
String[] args = {};
|
|
||||||
App.main(args);
|
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,21 +4,100 @@ 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:
|
||||||
- Java
|
- Cloud distributed
|
||||||
- Spring
|
- Decoupling
|
||||||
|
- Microservices
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
The user makes a single call to the Aggregator, and the aggregator then calls each relevant microservice and collects
|
The user makes a single call to the aggregator service, and the aggregator then calls each relevant microservice.
|
||||||
the data, apply business logic to it, and further publish is as a REST Endpoint.
|
|
||||||
More variations of the aggregator are:
|
|
||||||
- Proxy Microservice Design Pattern: A different microservice is called upon the business need.
|
|
||||||
- Chained Microservice Design Pattern: In this case each microservice is dependent/ chained to a series
|
|
||||||
of other microservices.
|
|
||||||
|
|
||||||

|
## Explanation
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
|
||||||
|
> Our web marketplace needs information about products and their current inventory. It makes a call to an aggregator
|
||||||
|
> service which in turn calls the product information microservice and product inventory microservice returning the
|
||||||
|
> combined information.
|
||||||
|
|
||||||
|
In plain words
|
||||||
|
|
||||||
|
> Aggregator Microservice collects pieces of data from various microservices and returns an aggregate for processing.
|
||||||
|
|
||||||
|
Stack Overflow says
|
||||||
|
|
||||||
|
> Aggregator Microservice invokes multiple services to achieve the functionality required by the application.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
Let's start from the data model. Here's our `Product`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class Product {
|
||||||
|
private String title;
|
||||||
|
private int productInventories;
|
||||||
|
// getters and setters ->
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Next we can introduce our `Aggregator` microservice. It contains clients `ProductInformationClient` and
|
||||||
|
`ProductInventoryClient` for calling respective microservices.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@RestController
|
||||||
|
public class Aggregator {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProductInformationClient informationClient;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProductInventoryClient inventoryClient;
|
||||||
|
|
||||||
|
@RequestMapping(path = "/product", method = RequestMethod.GET)
|
||||||
|
public Product getProduct() {
|
||||||
|
|
||||||
|
var product = new Product();
|
||||||
|
var productTitle = informationClient.getProductTitle();
|
||||||
|
var productInventory = inventoryClient.getProductInventories();
|
||||||
|
|
||||||
|
//Fallback to error message
|
||||||
|
product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed"));
|
||||||
|
|
||||||
|
//Fallback to default error inventory
|
||||||
|
product.setProductInventories(requireNonNullElse(productInventory, -1));
|
||||||
|
|
||||||
|
return product;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here's the essence of information microservice implementation. Inventory microservice is similar, it just returns
|
||||||
|
inventory counts.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@RestController
|
||||||
|
public class InformationController {
|
||||||
|
@RequestMapping(value = "/information", method = RequestMethod.GET)
|
||||||
|
public String getProductTitle() {
|
||||||
|
return "The Product Title.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now calling our `Aggregator` REST API returns the product information.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:50004/product
|
||||||
|
{"title":"The Product Title.","productInventories":5}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
@ -26,4 +105,6 @@ Use the Aggregator Microservices pattern when you need a unified API for various
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Microservice Design Patterns](http://blog.arungupta.me/microservice-design-patterns/)
|
* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/)
|
||||||
|
* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60)
|
||||||
|
* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4)
|
||||||
|
After Width: | Height: | Size: 40 KiB |
@ -0,0 +1,43 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.aggregator.microservices {
|
||||||
|
class Aggregator {
|
||||||
|
- informationClient : ProductInformationClient
|
||||||
|
- inventoryClient : ProductInventoryClient
|
||||||
|
+ Aggregator()
|
||||||
|
+ getProduct() : Product
|
||||||
|
}
|
||||||
|
class App {
|
||||||
|
+ App()
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
}
|
||||||
|
class Product {
|
||||||
|
- productInventories : int
|
||||||
|
- title : String
|
||||||
|
+ Product()
|
||||||
|
+ getProductInventories() : int
|
||||||
|
+ getTitle() : String
|
||||||
|
+ setProductInventories(productInventories : int)
|
||||||
|
+ setTitle(title : String)
|
||||||
|
}
|
||||||
|
interface ProductInformationClient {
|
||||||
|
+ getProductTitle() : String {abstract}
|
||||||
|
}
|
||||||
|
class ProductInformationClientImpl {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ ProductInformationClientImpl()
|
||||||
|
+ getProductTitle() : String
|
||||||
|
}
|
||||||
|
interface ProductInventoryClient {
|
||||||
|
+ getProductInventories() : Integer {abstract}
|
||||||
|
}
|
||||||
|
class ProductInventoryClientImpl {
|
||||||
|
- LOGGER : Logger {static}
|
||||||
|
+ ProductInventoryClientImpl()
|
||||||
|
+ getProductInventories() : Integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Aggregator --> "-informationClient" ProductInformationClient
|
||||||
|
Aggregator --> "-inventoryClient" ProductInventoryClient
|
||||||
|
ProductInformationClientImpl ..|> ProductInformationClient
|
||||||
|
ProductInventoryClientImpl ..|> ProductInventoryClient
|
||||||
|
@enduml
|
@ -2,7 +2,7 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
Copyright (c) 2014-2016 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
|
||||||
@ -23,27 +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.21.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>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-dependencies</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
@ -53,11 +41,6 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
@ -68,18 +51,12 @@
|
|||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
|
||||||
<artifactId>httpclient</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<version>${spring-boot.version}</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@ -88,6 +65,23 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<!-- Maven assembly plugin is invoked with default setting which we have
|
||||||
|
in parent pom and specifying the class having main method -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.aggregator.microservices.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p/>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p/>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p/>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,38 +20,46 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.aggregator.microservices;
|
package com.iluwatar.aggregator.microservices;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import static java.util.Objects.requireNonNullElse;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The aggregator aggregates calls on various micro-services, collects
|
* The aggregator aggregates calls on various micro-services, collects data and further publishes
|
||||||
* data and further publishes them under a REST endpoint.
|
* them under a REST endpoint.
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
public class Aggregator {
|
public class Aggregator {
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ProductInformationClient informationClient;
|
private ProductInformationClient informationClient;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ProductInventoryClient inventoryClient;
|
private ProductInventoryClient inventoryClient;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves product data.
|
* Retrieves product data.
|
||||||
*
|
*
|
||||||
* @return a Product.
|
* @return a Product.
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/product")
|
@GetMapping("/product")
|
||||||
public Product getProduct() {
|
public Product getProduct() {
|
||||||
Product product = new Product();
|
|
||||||
product.setTitle(informationClient.getProductTitle());
|
var product = new Product();
|
||||||
product.setProductInventories(inventoryClient.getProductInventories());
|
var productTitle = informationClient.getProductTitle();
|
||||||
|
var productInventory = inventoryClient.getProductInventories();
|
||||||
|
|
||||||
|
//Fallback to error message
|
||||||
|
product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed"));
|
||||||
|
|
||||||
|
//Fallback to default error inventory
|
||||||
|
product.setProductInventories(requireNonNullElse(productInventory, -1));
|
||||||
|
|
||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p/>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p/>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p/>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,19 +20,20 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.aggregator.microservices;
|
package com.iluwatar.aggregator.microservices;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Boot EntryPoint Class
|
* Spring Boot EntryPoint Class.
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point
|
* Program entry point.
|
||||||
*
|
*
|
||||||
* @param args command line args
|
* @param args command line args
|
||||||
*/
|
*/
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p/>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p/>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p/>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,11 +20,17 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.aggregator.microservices;
|
package com.iluwatar.aggregator.microservices;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates all the data for a Product that clients will request.
|
* Encapsulates all the data for a Product that clients will request.
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class Product {
|
public class Product {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,20 +44,4 @@ public class Product {
|
|||||||
*/
|
*/
|
||||||
private int productInventories;
|
private int productInventories;
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String title) {
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getProductInventories() {
|
|
||||||
return productInventories;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProductInventories(int productInventories) {
|
|
||||||
this.productInventories = productInventories;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/**
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
* Copyright © 2014-2021 Ilkka Seppälä
|
||||||
* <p/>
|
*
|
||||||
* 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
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* <p/>
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
* <p/>
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,6 +20,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.aggregator.microservices;
|
package com.iluwatar.aggregator.microservices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|