Compare commits
1 Commits
all-contri
...
some-test-
Author | SHA1 | Date | |
---|---|---|---|
68e1ca83e8 |
1067
.all-contributorsrc
1067
.all-contributorsrc
File diff suppressed because it is too large
Load Diff
32
.github/workflows/maven.yml
vendored
32
.github/workflows/maven.yml
vendored
@ -1,26 +1,3 @@
|
|||||||
#
|
|
||||||
# The MIT License
|
|
||||||
# Copyright © 2014-2019 Ilkka Seppälä
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
# THE SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
# This workflow will build a Java project with Maven
|
# This workflow will build a Java project with Maven
|
||||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||||
|
|
||||||
@ -43,18 +20,9 @@ jobs:
|
|||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
# Some tests need screen access
|
|
||||||
- name: Install xvfb
|
- name: Install xvfb
|
||||||
run: sudo apt-get install xvfb
|
run: sudo apt-get install xvfb
|
||||||
# SonarQube scan does not work for forked repositories
|
|
||||||
# See https://jira.sonarsource.com/browse/MMF-1371
|
|
||||||
- name: Build with Maven
|
- name: Build with Maven
|
||||||
if: github.ref != 'refs/heads/master'
|
|
||||||
run: xvfb-run mvn clean verify
|
|
||||||
- name: Build with Maven and run SonarQube analysis
|
|
||||||
if: github.ref == 'refs/heads/master'
|
|
||||||
run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
||||||
env:
|
env:
|
||||||
# These two env variables are needed for sonar analysis
|
|
||||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_ACCESS_TOKEN }}
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
200
README.md
200
README.md
@ -8,9 +8,6 @@
|
|||||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||||
[](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?id=iluwatar_java-design-patterns)
|
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
||||||
[](#contributors-)
|
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
@ -34,20 +31,19 @@ programming tutorials how to implement a specific pattern. We use the most
|
|||||||
popular battle-proven open source Java technologies.
|
popular battle-proven open source Java technologies.
|
||||||
|
|
||||||
Before you dive into the material, you should be familiar with various
|
Before you dive into the material, you should be familiar with various
|
||||||
[Software Design Principles](https://java-design-patterns.com/principles/).
|
software design principles.
|
||||||
|
|
||||||
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 the
|
Once you are familiar with these concepts you can start drilling down into
|
||||||
[available design patterns](https://java-design-patterns.com/patterns/) by any
|
patterns by any of the following approaches
|
||||||
of the following approaches
|
|
||||||
|
|
||||||
- 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 difficulty tags, `Difficulty-Beginner`, `Difficulty-Intermediate` & `Difficulty-Expert`.
|
||||||
- Using tags such as `Performance`, `Gang of Four` or `Data access`.
|
|
||||||
- Using pattern categories, `Creational`, `Behavioral`, and others.
|
- Using pattern categories, `Creational`, `Behavioral`, and others.
|
||||||
|
- Search for a specific pattern. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
|
||||||
|
|
||||||
Hopefully you find the object oriented solutions presented on this site useful
|
Hopefully you find the object oriented solutions presented on this site useful
|
||||||
in your architectures and have as much fun learning them as we had developing them.
|
in your architectures and have as much fun learning them as we had developing them.
|
||||||
@ -61,189 +57,3 @@ you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwata
|
|||||||
# 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" width="100px;" alt=""/><br /><sub><b>Ilkka Seppälä</b></sub></a><br /><a href="#projectManagement-iluwatar" title="Project Management">📆</a> <a href="#maintenance-iluwatar" title="Maintenance">🚧</a> <a href="#content-iluwatar" title="Content">🖋</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/amit1307"><img src="https://avatars0.githubusercontent.com/u/23420222?v=4" width="100px;" alt=""/><br /><sub><b>amit1307</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit1307" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/npathai"><img src="https://avatars2.githubusercontent.com/u/1792515?v=4" width="100px;" alt=""/><br /><sub><b>Narendra Pathai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npathai" title="Code">💻</a> <a href="#ideas-npathai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Anpathai" title="Reviewed Pull Requests">👀</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/fluxw42"><img src="https://avatars1.githubusercontent.com/u/1545460?v=4" width="100px;" alt=""/><br /><sub><b>Jeroen Meulemeester</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fluxw42" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="http://www.joemccarthy.co.uk"><img src="https://avatars0.githubusercontent.com/u/4526195?v=4" width="100px;" alt=""/><br /><sub><b>Joseph McCarthy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mikulucky" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/thomasoss"><img src="https://avatars1.githubusercontent.com/u/22516154?v=4" width="100px;" alt=""/><br /><sub><b>Thomas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=thomasoss" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/anuragagarwal561994"><img src="https://avatars1.githubusercontent.com/u/6075379?v=4" width="100px;" alt=""/><br /><sub><b>Anurag Agarwal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anuragagarwal561994" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://markusmo3.github.io"><img src="https://avatars1.githubusercontent.com/u/3317416?v=4" width="100px;" alt=""/><br /><sub><b>Markus Moser</b></sub></a><br /><a href="#design-markusmo3" title="Design">🎨</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=markusmo3" title="Code">💻</a> <a href="#ideas-markusmo3" title="Ideas, Planning, & Feedback">🤔</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://twitter.com/i_sabiq"><img src="https://avatars1.githubusercontent.com/u/19510920?v=4" width="100px;" alt=""/><br /><sub><b>Sabiq Ihab</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=isabiq" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="http://inbravo.github.io"><img src="https://avatars3.githubusercontent.com/u/5253764?v=4" width="100px;" alt=""/><br /><sub><b>Amit Dixit</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=inbravo" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/piyushchaudhari04"><img src="https://avatars3.githubusercontent.com/u/10268029?v=4" width="100px;" alt=""/><br /><sub><b>Piyush Kailash Chaudhari</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=piyushchaudhari04" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/joshzambales"><img src="https://avatars1.githubusercontent.com/u/8704552?v=4" width="100px;" alt=""/><br /><sub><b>joshzambales</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joshzambales" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/Crossy147"><img src="https://avatars2.githubusercontent.com/u/7272996?v=4" width="100px;" alt=""/><br /><sub><b>Kamil Pietruszka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Crossy147" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="http://cs.joensuu.fi/~zkhayda"><img src="https://avatars2.githubusercontent.com/u/660742?v=4" width="100px;" alt=""/><br /><sub><b>Zafar Khaydarov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Documentation">📖</a></td>
|
|
||||||
<td align="center"><a href="https://kemitix.github.io/"><img src="https://avatars1.githubusercontent.com/u/1147749?v=4" width="100px;" alt=""/><br /><sub><b>Paul Campbell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kemitix" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/Argyro-Sioziou"><img src="https://avatars0.githubusercontent.com/u/22822639?v=4" width="100px;" alt=""/><br /><sub><b>Argyro Sioziou</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Argyro-Sioziou" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/TylerMcConville"><img src="https://avatars0.githubusercontent.com/u/4946449?v=4" width="100px;" alt=""/><br /><sub><b>TylerMcConville</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=TylerMcConville" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/saksham93"><img src="https://avatars1.githubusercontent.com/u/37399540?v=4" width="100px;" alt=""/><br /><sub><b>saksham93</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=saksham93" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/nikhilbarar"><img src="https://avatars2.githubusercontent.com/u/37332144?v=4" width="100px;" alt=""/><br /><sub><b>nikhilbarar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nikhilbarar" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="http://colinbut.com"><img src="https://avatars2.githubusercontent.com/u/10725674?v=4" width="100px;" alt=""/><br /><sub><b>Colin But</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=colinbut" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/ruslanpa"><img src="https://avatars2.githubusercontent.com/u/1503411?v=4" width="100px;" alt=""/><br /><sub><b>Ruslan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruslanpa" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4" width="100px;" alt=""/><br /><sub><b>Juho Kang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JuhoKang" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/dheeraj-mummareddy"><img src="https://avatars2.githubusercontent.com/u/7002230?v=4" width="100px;" alt=""/><br /><sub><b>Dheeraj Mummareddy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dheeraj-mummareddy" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://www.bernardosulzbach.com"><img src="https://avatars0.githubusercontent.com/u/8271090?v=4" width="100px;" alt=""/><br /><sub><b>Bernardo Sulzbach</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=bernardosulzbach" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/4lexis"><img src="https://avatars0.githubusercontent.com/u/19871727?v=4" width="100px;" alt=""/><br /><sub><b>Aleksandar Dudukovic</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=4lexis" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://www.yusufaytas.com"><img src="https://avatars2.githubusercontent.com/u/1049483?v=4" width="100px;" alt=""/><br /><sub><b>Yusuf Aytaş</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yusufaytas" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="http://futurehomes.hu"><img src="https://avatars2.githubusercontent.com/u/1001491?v=4" width="100px;" alt=""/><br /><sub><b>Mihály Kuprivecz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qpi" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/kapinuss"><img src="https://avatars0.githubusercontent.com/u/17639945?v=4" width="100px;" alt=""/><br /><sub><b>Stanislav Kapinus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kapinuss" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/gvsharma"><img src="https://avatars1.githubusercontent.com/u/6648152?v=4" width="100px;" alt=""/><br /><sub><b>GVSharma</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gvsharma" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/SrdjanPaunovic"><img src="https://avatars1.githubusercontent.com/u/22815104?v=4" width="100px;" alt=""/><br /><sub><b>Srđan Paunović</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=SrdjanPaunovic" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://sideris.xyz/"><img src="https://avatars3.githubusercontent.com/u/5484694?v=4" width="100px;" alt=""/><br /><sub><b>Petros G. Sideris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sideris" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://www.linkedin.com/in/pramodgupta3/"><img src="https://avatars1.githubusercontent.com/u/2184241?v=4" width="100px;" alt=""/><br /><sub><b>Pramod Gupta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AIAmPramod" title="Reviewed Pull Requests">👀</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://amarnath510.github.io/portfolio"><img src="https://avatars0.githubusercontent.com/u/4599623?v=4" 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" 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></td>
|
|
||||||
<td align="center"><a href="http://theerroris.me"><img src="https://avatars0.githubusercontent.com/u/1685953?v=4" 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" width="100px;" alt=""/><br /><sub><b>Harshraj Thakor</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Harshrajsinh" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/MaVdbussche"><img src="https://avatars1.githubusercontent.com/u/26136934?v=4" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>anthony</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anthonycampbell" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="http://ccygnus.com/"><img src="https://avatars1.githubusercontent.com/u/9342724?v=4" width="100px;" alt=""/><br /><sub><b>Christian Cygnus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christophercolumbusdog" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://about.me/dzmitryh"><img src="https://avatars2.githubusercontent.com/u/5390492?v=4" 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" 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" width="100px;" alt=""/><br /><sub><b>Kai Winter</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kaiwinter" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/lbroman"><img src="https://avatars1.githubusercontent.com/u/86007?v=4" 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" 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" 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" 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" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>Yosfik Alqadri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yosfik" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/7agustibm"><img src="https://avatars0.githubusercontent.com/u/8149332?v=4" 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" 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" width="100px;" alt=""/><br /><sub><b>Luigi Cortese</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=LuigiCortese" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/Rzeposlaw"><img src="https://avatars2.githubusercontent.com/u/18425745?v=4" width="100px;" alt=""/><br /><sub><b>Katarzyna Rzepecka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Rzeposlaw" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="http://adamski.pro"><img src="https://avatars1.githubusercontent.com/u/6537430?v=4" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>Dmitry Avershin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dmitraver" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/fanofxiaofeng"><img src="https://avatars0.githubusercontent.com/u/3983683?v=4" 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" width="100px;" alt=""/><br /><sub><b>hoangnam2261</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoangnam2261" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/jarpit96"><img src="https://avatars2.githubusercontent.com/u/10098713?v=4" 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" width="100px;" alt=""/><br /><sub><b>Jón Ingi Sveinbjörnsson</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joningiwork" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/kirill-vlasov"><img src="https://avatars3.githubusercontent.com/u/16112495?v=4" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>PhoenixYip</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Alwayswithme" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/MSaifAsif"><img src="https://avatars1.githubusercontent.com/u/6280554?v=4" width="100px;" alt=""/><br /><sub><b>M Saif Asif</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MSaifAsif" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/kanwarpreet25"><img src="https://avatars0.githubusercontent.com/u/39183641?v=4" 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" 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" width="100px;" alt=""/><br /><sub><b>Per Wramdemark</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=perwramdemark" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/waisuan"><img src="https://avatars2.githubusercontent.com/u/10975700?v=4" 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" 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" 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" 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" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>Christopher O'Connell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=oconnelc" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/giorgosmav21"><img src="https://avatars2.githubusercontent.com/u/22855493?v=4" 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" 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" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=igeligel" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://llorllale.github.io/"><img src="https://avatars1.githubusercontent.com/u/2019896?v=4" width="100px;" alt=""/><br /><sub><b>George Aristy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=llorllale" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/mookkiah"><img src="https://avatars1.githubusercontent.com/u/8975264?v=4" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>Matt</b></sub></a><br /><a href="#content-ThatGuyWithTheHat" title="Content">🖋</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://www.linkedin.com/in/gopinathlangote/"><img src="https://avatars2.githubusercontent.com/u/10210778?v=4" 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" width="100px;" alt=""/><br /><sub><b>Hoswey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoswey" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/amit2103"><img src="https://avatars3.githubusercontent.com/u/7566692?v=4" 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" width="100px;" alt=""/><br /><sub><b>gwildor28</b></sub></a><br /><a href="#content-gwildor28" title="Content">🖋</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://t.me/paul_docker"><img src="https://avatars1.githubusercontent.com/u/2404785?v=4" 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" 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" width="100px;" alt=""/><br /><sub><b>qza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qza" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="http://tschis.github.io"><img src="https://avatars1.githubusercontent.com/u/20662669?v=4" width="100px;" alt=""/><br /><sub><b>Rodolfo Forte</b></sub></a><br /><a href="#content-Tschis" title="Content">🖋</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/ankurkaushal"><img src="https://avatars2.githubusercontent.com/u/2236616?v=4" width="100px;" alt=""/><br /><sub><b>Ankur Kaushal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ankurkaushal" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://www.linkedin.com/in/ovidijus-okinskas/"><img src="https://avatars0.githubusercontent.com/u/20372387?v=4" width="100px;" alt=""/><br /><sub><b>Ovidijus Okinskas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=okinskas" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/robertt240"><img src="https://avatars1.githubusercontent.com/u/9137432?v=4" width="100px;" alt=""/><br /><sub><b>Robert Kasperczyk</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=robertt240" title="Code">💻</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/trautonen"><img src="https://avatars3.githubusercontent.com/u/1641063?v=4" width="100px;" alt=""/><br /><sub><b>Tapio Rautonen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=trautonen" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="http://vk.com/yuri.orlov"><img src="https://avatars0.githubusercontent.com/u/1595733?v=4" 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" 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" 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" 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></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/sivasubramanim"><img src="https://avatars2.githubusercontent.com/u/51107434?v=4" 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" 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" 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" width="100px;" alt=""/><br /><sub><b>Boris-Chengbiao Zhou</b></sub></a><br /><a href="#content-Bobo1239" title="Content">🖋</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://jahhein.github.io"><img src="https://avatars2.githubusercontent.com/u/10779515?v=4" 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" 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" width="100px;" alt=""/><br /><sub><b>Rachel M. Carmena</b></sub></a><br /><a href="#content-rachelcarmena" title="Content">🖋</a></td>
|
|
||||||
<td align="center"><a href="https://zd-zero.github.io"><img src="https://avatars0.githubusercontent.com/u/21978370?v=4" width="100px;" alt=""/><br /><sub><b>Zaerald Denze Lungos</b></sub></a><br /><a href="#content-zd-zero" title="Content">🖋</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://webpro.nl"><img src="https://avatars1.githubusercontent.com/u/456426?v=4" 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" 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" 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></td>
|
|
||||||
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- markdownlint-enable -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
||||||
|
@ -9,182 +9,21 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
## 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
|
## 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)
|
|
||||||
|
@ -32,6 +32,7 @@ import java.util.stream.Stream;
|
|||||||
*/
|
*/
|
||||||
public interface HasParts extends Document {
|
public interface HasParts extends Document {
|
||||||
|
|
||||||
|
|
||||||
default Stream<Part> getParts() {
|
default Stream<Part> getParts() {
|
||||||
return children(Property.PARTS.toString(), Part::new);
|
return children(Property.PARTS.toString(), Part::new);
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public interface HasPrice extends Document {
|
public interface HasPrice extends Document {
|
||||||
|
|
||||||
|
|
||||||
default Optional<Number> getPrice() {
|
default Optional<Number> getPrice() {
|
||||||
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public interface HasType extends Document {
|
public interface HasType extends Document {
|
||||||
|
|
||||||
|
|
||||||
default Optional<String> getType() {
|
default Optional<String> getType() {
|
||||||
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public class AbstractDocumentTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DocumentImplementation document = new DocumentImplementation(new HashMap<>());
|
private DocumentImplementation document = new DocumentImplementation(new HashMap<>());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldPutAndGetValue() {
|
public void shouldPutAndGetValue() {
|
||||||
|
@ -198,5 +198,4 @@ Use the Abstract Factory pattern when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [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)
|
|
||||||
|
@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
*/
|
*/
|
||||||
public class AbstractFactoryTest {
|
public class AbstractFactoryTest {
|
||||||
|
|
||||||
private final App app = new App();
|
private App app = new App();
|
||||||
private KingdomFactory elfFactory;
|
private KingdomFactory elfFactory;
|
||||||
private KingdomFactory orcFactory;
|
private KingdomFactory orcFactory;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
|||||||
*/
|
*/
|
||||||
public class ConfigureForDosVisitorTest {
|
public class ConfigureForDosVisitorTest {
|
||||||
|
|
||||||
private final TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
|
private TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVisitForZoom() {
|
public void testVisitForZoom() {
|
||||||
|
@ -56,7 +56,7 @@ And captain expects an implementation of `RowingBoat` interface to be able to mo
|
|||||||
```java
|
```java
|
||||||
public class Captain {
|
public class Captain {
|
||||||
|
|
||||||
private final RowingBoat rowingBoat;
|
private RowingBoat rowingBoat;
|
||||||
// default constructor and setter for rowingBoat
|
// default constructor and setter for rowingBoat
|
||||||
public Captain(RowingBoat rowingBoat) {
|
public Captain(RowingBoat rowingBoat) {
|
||||||
this.rowingBoat = rowingBoat;
|
this.rowingBoat = rowingBoat;
|
||||||
@ -75,7 +75,7 @@ public class FishingBoatAdapter implements RowingBoat {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
|
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();
|
||||||
@ -129,7 +129,5 @@ An object adapter
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
|
||||||
* [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)
|
|
||||||
|
@ -29,7 +29,7 @@ package com.iluwatar.adapter;
|
|||||||
*/
|
*/
|
||||||
public class FishingBoatAdapter implements RowingBoat {
|
public class FishingBoatAdapter implements RowingBoat {
|
||||||
|
|
||||||
private final FishingBoat boat;
|
private FishingBoat boat;
|
||||||
|
|
||||||
public FishingBoatAdapter() {
|
public FishingBoatAdapter() {
|
||||||
boat = new FishingBoat();
|
boat = new FishingBoat();
|
||||||
|
@ -6,7 +6,6 @@ permalink: /patterns/ambassador/
|
|||||||
categories: Structural
|
categories: Structural
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
- Cloud distributed
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
@ -23,7 +22,8 @@ In plain words
|
|||||||
|
|
||||||
Microsoft documentation states
|
Microsoft documentation states
|
||||||
|
|
||||||
> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
|
> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client.
|
||||||
|
This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
|
||||||
|
|
||||||
**Programmatic Example**
|
**Programmatic Example**
|
||||||
|
|
||||||
|
@ -45,9 +45,11 @@ public class App {
|
|||||||
* Entry point.
|
* Entry point.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
var host1 = new Client();
|
var host1 = new Client();
|
||||||
var host2 = new Client();
|
var host2 = new Client();
|
||||||
host1.useService(12);
|
host1.useService(12);
|
||||||
host2.useService(73);
|
host2.useService(73);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class RemoteServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class StaticRandomProvider implements RandomProvider {
|
private static class StaticRandomProvider implements RandomProvider {
|
||||||
private final double value;
|
private double value;
|
||||||
|
|
||||||
StaticRandomProvider(double value) {
|
StaticRandomProvider(double value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -5,142 +5,14 @@ folder: api-gateway
|
|||||||
permalink: /patterns/api-gateway/
|
permalink: /patterns/api-gateway/
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
tags:
|
tags:
|
||||||
- Cloud distributed
|
- Cloud distributed
|
||||||
- Decoupling
|
- Decoupling
|
||||||
- Microservices
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
Aggregate calls to microservices in a single location: the API Gateway. The user makes a single call to the API Gateway,
|
Aggregate calls to microservices in a single location: the API Gateway. The user makes a single
|
||||||
and the API Gateway then calls each relevant microservice.
|
call to the API Gateway, and the API Gateway then calls each relevant microservice.
|
||||||
|
|
||||||
## Explanation
|
|
||||||
|
|
||||||
With the Microservices pattern, a client may need data from multiple different microservices. If the client called each
|
|
||||||
microservice directly, that could contribute to longer load times, since the client would have to make a network request
|
|
||||||
for each microservice called. Moreover, having the client call each microservice directly ties the client to that
|
|
||||||
microservice - if the internal implementations of the microservices change (for example, if two microservices are
|
|
||||||
combined sometime in the future) or if the location (host and port) of a microservice changes, then every client that
|
|
||||||
makes use of those microservices must be updated.
|
|
||||||
|
|
||||||
The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway pattern, an additional
|
|
||||||
entity (the API Gateway) is placed between the client and the microservices. The job of the API Gateway is to aggregate
|
|
||||||
the calls to the microservices. Rather than the client calling each microservice individually, the client calls the
|
|
||||||
API Gateway a single time. The API Gateway then calls each of the microservices that the client needs.
|
|
||||||
|
|
||||||
Real world example
|
|
||||||
|
|
||||||
> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system the API Gateway makes
|
|
||||||
calls to the Image and Price microservices.
|
|
||||||
|
|
||||||
In plain words
|
|
||||||
|
|
||||||
> For a system implemented using microservices architecture, API Gateway is the single entry point that aggregates the
|
|
||||||
calls to the individual microservices.
|
|
||||||
|
|
||||||
Wikipedia says
|
|
||||||
|
|
||||||
> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling and security
|
|
||||||
policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often
|
|
||||||
includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also
|
|
||||||
provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to
|
|
||||||
support authentication, authorization, security, audit and regulatory compliance.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
This implementation shows what the API Gateway pattern could look like for an e-commerce site. The `ApiGateway` makes
|
|
||||||
calls to the Image and Price microservices using the `ImageClientImpl` and `PriceClientImpl` respectively. Customers
|
|
||||||
viewing the site on a desktop device can see both price information and an image of a product, so the `ApiGateway` calls
|
|
||||||
both of the microservices and aggregates the data in the `DesktopProduct` model. However, mobile users only see price
|
|
||||||
information; they do not see a product image. For mobile users, the `ApiGateway` only retrieves price information, which
|
|
||||||
it uses to populate the `MobileProduct`.
|
|
||||||
|
|
||||||
Here's the Image microservice implementation.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public interface ImageClient {
|
|
||||||
String getImagePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ImageClientImpl implements ImageClient {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getImagePath() {
|
|
||||||
var httpClient = HttpClient.newHttpClient();
|
|
||||||
var httpGet = HttpRequest.newBuilder()
|
|
||||||
.GET()
|
|
||||||
.uri(URI.create("http://localhost:50005/image-path"))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
try {
|
|
||||||
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
|
|
||||||
return httpResponse.body();
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here's the Price microservice implementation.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public interface PriceClient {
|
|
||||||
String getPrice();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PriceClientImpl implements PriceClient {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPrice() {
|
|
||||||
var httpClient = HttpClient.newHttpClient();
|
|
||||||
var httpGet = HttpRequest.newBuilder()
|
|
||||||
.GET()
|
|
||||||
.uri(URI.create("http://localhost:50006/price"))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
try {
|
|
||||||
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
|
|
||||||
return httpResponse.body();
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And here we can see how API Gateway maps the requests to the microservices.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class ApiGateway {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private ImageClient imageClient;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PriceClient priceClient;
|
|
||||||
|
|
||||||
@RequestMapping(path = "/desktop", method = RequestMethod.GET)
|
|
||||||
public DesktopProduct getProductDesktop() {
|
|
||||||
var desktopProduct = new DesktopProduct();
|
|
||||||
desktopProduct.setImagePath(imageClient.getImagePath());
|
|
||||||
desktopProduct.setPrice(priceClient.getPrice());
|
|
||||||
return desktopProduct;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(path = "/mobile", method = RequestMethod.GET)
|
|
||||||
public MobileProduct getProductMobile() {
|
|
||||||
var mobileProduct = new MobileProduct();
|
|
||||||
mobileProduct.setPrice(priceClient.getPrice());
|
|
||||||
return mobileProduct;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
@ -149,11 +21,10 @@ public class ApiGateway {
|
|||||||
|
|
||||||
Use the API Gateway pattern when
|
Use the API Gateway pattern when
|
||||||
|
|
||||||
* You're using microservices architecture and need a single point of aggregation for your microservice calls.
|
* you're also using the Microservices pattern and need a single point of aggregation for your
|
||||||
|
microservice calls
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html)
|
* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html)
|
||||||
* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)
|
* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)
|
||||||
* [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=ac7b6a57f866ac006a309d9086e8cfbd)
|
|
||||||
* [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/gp/product/1491950358/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1491950358&linkId=4c95ca9831e05e3f0dadb08841d77bf1)
|
|
||||||
|
@ -60,7 +60,7 @@ public class CashAAATest {
|
|||||||
//Act
|
//Act
|
||||||
cash.plus(4);
|
cash.plus(4);
|
||||||
//Assert
|
//Assert
|
||||||
assertEquals(7, cash.count());
|
assertEquals(cash.count(), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -71,7 +71,7 @@ public class CashAAATest {
|
|||||||
var result = cash.minus(5);
|
var result = cash.minus(5);
|
||||||
//Assert
|
//Assert
|
||||||
assertTrue(result);
|
assertTrue(result);
|
||||||
assertEquals(3, cash.count());
|
assertEquals(cash.count(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -82,7 +82,7 @@ public class CashAAATest {
|
|||||||
var result = cash.minus(6);
|
var result = cash.minus(6);
|
||||||
//Assert
|
//Assert
|
||||||
assertFalse(result);
|
assertFalse(result);
|
||||||
assertEquals(1, cash.count());
|
assertEquals(cash.count(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -94,6 +94,6 @@ public class CashAAATest {
|
|||||||
var result = cash.minus(3);
|
var result = cash.minus(3);
|
||||||
//Assert
|
//Assert
|
||||||
assertTrue(result);
|
assertTrue(result);
|
||||||
assertEquals(8, cash.count());
|
assertEquals(cash.count(), 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,16 +44,16 @@ public class CashAntiAAATest {
|
|||||||
var cash = new Cash(3);
|
var cash = new Cash(3);
|
||||||
//test plus
|
//test plus
|
||||||
cash.plus(4);
|
cash.plus(4);
|
||||||
assertEquals(7, cash.count());
|
assertEquals(cash.count(), 7);
|
||||||
//test minus
|
//test minus
|
||||||
cash = new Cash(8);
|
cash = new Cash(8);
|
||||||
assertTrue(cash.minus(5));
|
assertTrue(cash.minus(5));
|
||||||
assertEquals(3, cash.count());
|
assertEquals(cash.count(), 3);
|
||||||
assertFalse(cash.minus(6));
|
assertFalse(cash.minus(6));
|
||||||
assertEquals(3, cash.count());
|
assertEquals(cash.count(), 3);
|
||||||
//test update
|
//test update
|
||||||
cash.plus(5);
|
cash.plus(5);
|
||||||
assertTrue(cash.minus(5));
|
assertTrue(cash.minus(5));
|
||||||
assertEquals(3, cash.count());
|
assertEquals(cash.count(), 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
|||||||
void setValue(T value) {
|
void setValue(T value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.state = COMPLETED;
|
this.state = COMPLETED;
|
||||||
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.empty()));
|
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.<Exception>empty()));
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
lock.notifyAll();
|
lock.notifyAll();
|
||||||
}
|
}
|
||||||
|
@ -194,5 +194,4 @@ Use the Bridge pattern when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [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)
|
|
||||||
|
@ -131,7 +131,5 @@ Use the Builder pattern when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb)
|
* [Effective Java (2nd Edition)](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683)
|
||||||
* [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)
|
|
||||||
|
@ -26,4 +26,4 @@ Use the Business Delegate pattern when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.business.delegate;
|
|||||||
*/
|
*/
|
||||||
public class Client {
|
public class Client {
|
||||||
|
|
||||||
private final BusinessDelegate businessDelegate;
|
private BusinessDelegate businessDelegate;
|
||||||
|
|
||||||
public Client(BusinessDelegate businessDelegate) {
|
public Client(BusinessDelegate businessDelegate) {
|
||||||
this.businessDelegate = businessDelegate;
|
this.businessDelegate = businessDelegate;
|
||||||
|
@ -28,5 +28,5 @@ package com.iluwatar.business.delegate;
|
|||||||
*/
|
*/
|
||||||
public enum ServiceType {
|
public enum ServiceType {
|
||||||
|
|
||||||
EJB, JMS
|
EJB, JMS;
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,9 @@ import java.util.Stack;
|
|||||||
*/
|
*/
|
||||||
public class VirtualMachine {
|
public class VirtualMachine {
|
||||||
|
|
||||||
private final Stack<Integer> stack = new Stack<>();
|
private Stack<Integer> stack = new Stack<>();
|
||||||
|
|
||||||
private final Wizard[] wizards = new Wizard[2];
|
private Wizard[] wizards = new Wizard[2];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -104,7 +104,7 @@ public class VirtualMachineTest {
|
|||||||
bytecode[2] = LITERAL.getIntValue();
|
bytecode[2] = LITERAL.getIntValue();
|
||||||
bytecode[3] = 50; // health amount
|
bytecode[3] = 50; // health amount
|
||||||
bytecode[4] = SET_HEALTH.getIntValue();
|
bytecode[4] = SET_HEALTH.getIntValue();
|
||||||
bytecode[5] = LITERAL.getIntValue();
|
bytecode[5] = LITERAL.getIntValue();;
|
||||||
bytecode[6] = wizardNumber;
|
bytecode[6] = wizardNumber;
|
||||||
bytecode[7] = GET_HEALTH.getIntValue();
|
bytecode[7] = GET_HEALTH.getIntValue();
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ permalink: /patterns/caching/
|
|||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
tags:
|
tags:
|
||||||
- Performance
|
- Performance
|
||||||
- Cloud distributed
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
@ -26,4 +25,4 @@ Use the Caching pattern(s) when
|
|||||||
|
|
||||||
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
|
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
|
||||||
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
|
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
|
||||||
* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
|
* [Cache-Aside](https://msdn.microsoft.com/en-us/library/dn589799.aspx)
|
||||||
|
@ -29,7 +29,7 @@ package com.iluwatar.caching;
|
|||||||
public enum CachingPolicy {
|
public enum CachingPolicy {
|
||||||
THROUGH("through"), AROUND("around"), BEHIND("behind"), ASIDE("aside");
|
THROUGH("through"), AROUND("around"), BEHIND("behind"), ASIDE("aside");
|
||||||
|
|
||||||
private final String policy;
|
private String policy;
|
||||||
|
|
||||||
CachingPolicy(String policy) {
|
CachingPolicy(String policy) {
|
||||||
this.policy = policy;
|
this.policy = policy;
|
||||||
|
@ -9,64 +9,9 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Callback is a piece of executable code that is passed as an argument to other code, which is expected to call back
|
Callback is a piece of executable code that is passed as an
|
||||||
(execute) the argument at some convenient time.
|
argument to other code, which is expected to call back (execute) the argument
|
||||||
|
at some convenient time.
|
||||||
## Explanation
|
|
||||||
|
|
||||||
Real world example
|
|
||||||
|
|
||||||
> We need to be notified after executing task has finished. We pass a callback method for the executor and wait for it to call back on us.
|
|
||||||
|
|
||||||
In plain words
|
|
||||||
|
|
||||||
> Callback is a method passed to the executor which will be called at defined moment.
|
|
||||||
|
|
||||||
Wikipedia says
|
|
||||||
|
|
||||||
> In computer programming, a callback, also known as a "call-after" function, is any executable code that is passed as an argument to other code; that other code is expected to call back (execute) the argument at a given time.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
Callback is a simple interface with single method.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public interface Callback {
|
|
||||||
|
|
||||||
void call();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Next we define a task that will execute the callback after the task execution has finished.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public abstract class Task {
|
|
||||||
|
|
||||||
final void executeWith(Callback callback) {
|
|
||||||
execute();
|
|
||||||
Optional.ofNullable(callback).ifPresent(Callback::call);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class SimpleTask extends Task {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = getLogger(SimpleTask.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
LOGGER.info("Perform some important activity and after call the callback method.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally here's how we execute a task and receive a callback when it's finished.
|
|
||||||
|
|
||||||
```java
|
|
||||||
var task = new SimpleTask();
|
|
||||||
task.executeWith(() -> LOGGER.info("I'm done now."));
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
|
@ -21,27 +21,28 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.strangler;
|
package com.iluwatar.callback;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test methods in HalfSource
|
* This example generates the exact same output as {@link App} however the callback has been defined
|
||||||
|
* as a Lambdas expression.
|
||||||
*/
|
*/
|
||||||
public class HalfSourceTest {
|
public final class LambdasApp {
|
||||||
private static final HalfSource source = new HalfSource();
|
|
||||||
|
|
||||||
@Test
|
private static final Logger LOGGER = getLogger(LambdasApp.class);
|
||||||
public void testAccumulateSum() {
|
|
||||||
assertEquals(0, source.accumulateSum(-1, 0, 1));
|
private LambdasApp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
/**
|
||||||
public void testIfNonZero() {
|
* Program entry point.
|
||||||
assertFalse(source.ifNonZero(-1, 0, 1));
|
*/
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
var task = new SimpleTask();
|
||||||
|
task.executeWith(() -> LOGGER.info("I'm done now."));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,7 +33,7 @@ public abstract class Task {
|
|||||||
/**
|
/**
|
||||||
* Execute with callback.
|
* Execute with callback.
|
||||||
*/
|
*/
|
||||||
final void executeWith(Callback callback) {
|
final void executeWith(final Callback callback) {
|
||||||
execute();
|
execute();
|
||||||
Optional.ofNullable(callback).ifPresent(Callback::call);
|
Optional.ofNullable(callback).ifPresent(Callback::call);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ Then the request handler hierarchy
|
|||||||
```java
|
```java
|
||||||
public abstract class RequestHandler {
|
public abstract class RequestHandler {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
|
||||||
private final RequestHandler next;
|
private RequestHandler next;
|
||||||
|
|
||||||
public RequestHandler(RequestHandler next) {
|
public RequestHandler(RequestHandler next) {
|
||||||
this.next = next;
|
this.next = next;
|
||||||
@ -157,5 +157,4 @@ Use Chain of Responsibility when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [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)
|
|
||||||
|
@ -33,7 +33,7 @@ public abstract class RequestHandler {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
|
||||||
|
|
||||||
private final RequestHandler next;
|
private RequestHandler next;
|
||||||
|
|
||||||
public RequestHandler(RequestHandler next) {
|
public RequestHandler(RequestHandler next) {
|
||||||
this.next = next;
|
this.next = next;
|
||||||
|
@ -7,7 +7,6 @@ categories: Behavioral
|
|||||||
tags:
|
tags:
|
||||||
- Performance
|
- Performance
|
||||||
- Decoupling
|
- Decoupling
|
||||||
- Cloud distributed
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
@ -188,4 +187,4 @@ Use the Circuit Breaker pattern when
|
|||||||
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
|
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
|
||||||
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
|
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
|
||||||
* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a)
|
* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a)
|
||||||
* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
|
* [Microsoft docs](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
|
||||||
|
@ -87,7 +87,10 @@ public class Car {
|
|||||||
} else if (!model.equals(other.model)) {
|
} else if (!model.equals(other.model)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return year == other.year;
|
if (year != other.year) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMake() {
|
public String getMake() {
|
||||||
|
@ -29,7 +29,7 @@ import java.util.List;
|
|||||||
* A Person class that has the list of cars that the person owns and use.
|
* A Person class that has the list of cars that the person owns and use.
|
||||||
*/
|
*/
|
||||||
public class Person {
|
public class Person {
|
||||||
private final List<Car> cars;
|
private List<Car> cars;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor to create an instance of person.
|
* Constructor to create an instance of person.
|
||||||
|
@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
public class AppTest {
|
public class AppTest {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(AppTest.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(AppTest.class);
|
||||||
|
|
||||||
private final List<Car> cars = CarFactory.createCars();
|
private List<Car> cars = CarFactory.createCars();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetModelsAfter2000UsingFor() {
|
public void testGetModelsAfter2000UsingFor() {
|
||||||
|
@ -12,214 +12,9 @@ tags:
|
|||||||
Action, Transaction
|
Action, Transaction
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
|
Encapsulate a request as an object, thereby letting you
|
||||||
|
parameterize clients with different requests, queue or log requests, and
|
||||||
## Explanation
|
support undoable operations.
|
||||||
Real world example
|
|
||||||
|
|
||||||
> There is a wizard casting spells on a goblin. The spells are executed on the goblin one by one. The first spell shrinks the goblin and the second makes him invisible. Then the wizard reverses the spells one by one. Each spell here is a command object that can be undone.
|
|
||||||
|
|
||||||
In plain words
|
|
||||||
|
|
||||||
> Storing requests as command objects allows performing an action or undoing it at a later time.
|
|
||||||
|
|
||||||
Wikipedia says
|
|
||||||
|
|
||||||
> In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
Here's the sample code with wizard and goblin. Let's start from the wizard class.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Wizard {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
|
|
||||||
|
|
||||||
private final Deque<Command> undoStack = new LinkedList<>();
|
|
||||||
private final Deque<Command> redoStack = new LinkedList<>();
|
|
||||||
|
|
||||||
public Wizard() {}
|
|
||||||
|
|
||||||
public void castSpell(Command command, Target target) {
|
|
||||||
LOGGER.info("{} casts {} at {}", this, command, target);
|
|
||||||
command.execute(target);
|
|
||||||
undoStack.offerLast(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void undoLastSpell() {
|
|
||||||
if (!undoStack.isEmpty()) {
|
|
||||||
var previousSpell = undoStack.pollLast();
|
|
||||||
redoStack.offerLast(previousSpell);
|
|
||||||
LOGGER.info("{} undoes {}", this, previousSpell);
|
|
||||||
previousSpell.undo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void redoLastSpell() {
|
|
||||||
if (!redoStack.isEmpty()) {
|
|
||||||
var previousSpell = redoStack.pollLast();
|
|
||||||
undoStack.offerLast(previousSpell);
|
|
||||||
LOGGER.info("{} redoes {}", this, previousSpell);
|
|
||||||
previousSpell.redo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Wizard";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Next we present the spell hierarchy.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public abstract class Command {
|
|
||||||
|
|
||||||
public abstract void execute(Target target);
|
|
||||||
|
|
||||||
public abstract void undo();
|
|
||||||
|
|
||||||
public abstract void redo();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract String toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InvisibilitySpell extends Command {
|
|
||||||
|
|
||||||
private Target target;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Target target) {
|
|
||||||
target.setVisibility(Visibility.INVISIBLE);
|
|
||||||
this.target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void undo() {
|
|
||||||
if (target != null) {
|
|
||||||
target.setVisibility(Visibility.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void redo() {
|
|
||||||
if (target != null) {
|
|
||||||
target.setVisibility(Visibility.INVISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Invisibility spell";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ShrinkSpell extends Command {
|
|
||||||
|
|
||||||
private Size oldSize;
|
|
||||||
private Target target;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Target target) {
|
|
||||||
oldSize = target.getSize();
|
|
||||||
target.setSize(Size.SMALL);
|
|
||||||
this.target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void undo() {
|
|
||||||
if (oldSize != null && target != null) {
|
|
||||||
var temp = target.getSize();
|
|
||||||
target.setSize(oldSize);
|
|
||||||
oldSize = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void redo() {
|
|
||||||
undo();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Shrink spell";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And last we have the goblin who's the target of the spells.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public abstract class Target {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Target.class);
|
|
||||||
|
|
||||||
private Size size;
|
|
||||||
|
|
||||||
private Visibility visibility;
|
|
||||||
|
|
||||||
public Size getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSize(Size size) {
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Visibility getVisibility() {
|
|
||||||
return visibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVisibility(Visibility visibility) {
|
|
||||||
this.visibility = visibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract String toString();
|
|
||||||
|
|
||||||
public void printStatus() {
|
|
||||||
LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Goblin extends Target {
|
|
||||||
|
|
||||||
public Goblin() {
|
|
||||||
setSize(Size.NORMAL);
|
|
||||||
setVisibility(Visibility.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Goblin";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally here's the whole example in action.
|
|
||||||
|
|
||||||
```java
|
|
||||||
var wizard = new Wizard();
|
|
||||||
var goblin = new Goblin();
|
|
||||||
goblin.printStatus();
|
|
||||||
// Goblin, [size=normal] [visibility=visible]
|
|
||||||
wizard.castSpell(new ShrinkSpell(), goblin);
|
|
||||||
// Wizard casts Shrink spell at Goblin
|
|
||||||
goblin.printStatus();
|
|
||||||
// Goblin, [size=small] [visibility=visible]
|
|
||||||
wizard.castSpell(new InvisibilitySpell(), goblin);
|
|
||||||
// Wizard casts Invisibility spell at Goblin
|
|
||||||
goblin.printStatus();
|
|
||||||
// Goblin, [size=small] [visibility=invisible]
|
|
||||||
wizard.undoLastSpell();
|
|
||||||
// Wizard undoes Invisibility spell
|
|
||||||
goblin.printStatus();
|
|
||||||
// Goblin, [size=small] [visibility=visible]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
@ -248,7 +43,4 @@ Use the Command pattern when you want to
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
|
||||||
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
|
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
|
|
||||||
|
@ -30,7 +30,7 @@ public enum Size {
|
|||||||
|
|
||||||
SMALL("small"), NORMAL("normal");
|
SMALL("small"), NORMAL("normal");
|
||||||
|
|
||||||
private final String title;
|
private String title;
|
||||||
|
|
||||||
Size(String title) {
|
Size(String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
@ -30,7 +30,7 @@ public enum Visibility {
|
|||||||
|
|
||||||
VISIBLE("visible"), INVISIBLE("invisible");
|
VISIBLE("visible"), INVISIBLE("invisible");
|
||||||
|
|
||||||
private final String title;
|
private String title;
|
||||||
|
|
||||||
Visibility(String title) {
|
Visibility(String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
@ -35,8 +35,8 @@ public class Wizard {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
|
||||||
|
|
||||||
private final Deque<Command> undoStack = new LinkedList<>();
|
private Deque<Command> undoStack = new LinkedList<>();
|
||||||
private final Deque<Command> redoStack = new LinkedList<>();
|
private Deque<Command> redoStack = new LinkedList<>();
|
||||||
|
|
||||||
public Wizard() {
|
public Wizard() {
|
||||||
// comment to ignore sonar issue: LEVEL critical
|
// comment to ignore sonar issue: LEVEL critical
|
||||||
|
@ -33,7 +33,7 @@ import java.util.Hashtable;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class EmployeeDatabase extends Database<Order> {
|
public class EmployeeDatabase extends Database<Order> {
|
||||||
private final Hashtable<String, Order> data;
|
private Hashtable<String, Order> data;
|
||||||
|
|
||||||
public EmployeeDatabase() {
|
public EmployeeDatabase() {
|
||||||
this.data = new Hashtable<>();
|
this.data = new Hashtable<>();
|
||||||
|
@ -33,7 +33,7 @@ import java.util.Hashtable;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class MessagingDatabase extends Database<MessageRequest> {
|
public class MessagingDatabase extends Database<MessageRequest> {
|
||||||
private final Hashtable<String, MessageRequest> data;
|
private Hashtable<String, MessageRequest> data;
|
||||||
|
|
||||||
public MessagingDatabase() {
|
public MessagingDatabase() {
|
||||||
this.data = new Hashtable<>();
|
this.data = new Hashtable<>();
|
||||||
|
@ -34,7 +34,7 @@ import java.util.Hashtable;
|
|||||||
|
|
||||||
public class PaymentDatabase extends Database<PaymentRequest> {
|
public class PaymentDatabase extends Database<PaymentRequest> {
|
||||||
|
|
||||||
private final Hashtable<String, PaymentRequest> data;
|
private Hashtable<String, PaymentRequest> data;
|
||||||
|
|
||||||
public PaymentDatabase() {
|
public PaymentDatabase() {
|
||||||
this.data = new Hashtable<>();
|
this.data = new Hashtable<>();
|
||||||
|
@ -35,7 +35,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class QueueDatabase extends Database<QueueTask> {
|
public class QueueDatabase extends Database<QueueTask> {
|
||||||
|
|
||||||
private final Queue<QueueTask> data;
|
private Queue<QueueTask> data;
|
||||||
public List<Exception> exceptionsList;
|
public List<Exception> exceptionsList;
|
||||||
|
|
||||||
public QueueDatabase(Exception... exc) {
|
public QueueDatabase(Exception... exc) {
|
||||||
|
@ -34,7 +34,7 @@ import java.util.Hashtable;
|
|||||||
|
|
||||||
public class ShippingDatabase extends Database<ShippingRequest> {
|
public class ShippingDatabase extends Database<ShippingRequest> {
|
||||||
|
|
||||||
private final Hashtable<String, ShippingRequest> data;
|
private Hashtable<String, ShippingRequest> data;
|
||||||
|
|
||||||
public ShippingDatabase() {
|
public ShippingDatabase() {
|
||||||
this.data = new Hashtable<>();
|
this.data = new Hashtable<>();
|
||||||
|
@ -34,7 +34,7 @@ Taking our sentence example from above. Here we have the base class and differen
|
|||||||
```java
|
```java
|
||||||
public abstract class LetterComposite {
|
public abstract class LetterComposite {
|
||||||
|
|
||||||
private final List<LetterComposite> children = new ArrayList<>();
|
private List<LetterComposite> children = new ArrayList<>();
|
||||||
|
|
||||||
public void add(LetterComposite letter) {
|
public void add(LetterComposite letter) {
|
||||||
children.add(letter);
|
children.add(letter);
|
||||||
@ -59,7 +59,7 @@ public abstract class LetterComposite {
|
|||||||
|
|
||||||
public class Letter extends LetterComposite {
|
public class Letter extends LetterComposite {
|
||||||
|
|
||||||
private final char character;
|
private char character;
|
||||||
|
|
||||||
public Letter(char c) {
|
public Letter(char c) {
|
||||||
this.character = c;
|
this.character = c;
|
||||||
@ -168,6 +168,4 @@ Use the Composite pattern when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [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)
|
|
||||||
|
@ -28,7 +28,7 @@ package com.iluwatar.composite;
|
|||||||
*/
|
*/
|
||||||
public class Letter extends LetterComposite {
|
public class Letter extends LetterComposite {
|
||||||
|
|
||||||
private final char character;
|
private char character;
|
||||||
|
|
||||||
public Letter(char c) {
|
public Letter(char c) {
|
||||||
this.character = c;
|
this.character = c;
|
||||||
|
@ -31,7 +31,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class LetterComposite {
|
public abstract class LetterComposite {
|
||||||
|
|
||||||
private final List<LetterComposite> children = new ArrayList<>();
|
private List<LetterComposite> children = new ArrayList<>();
|
||||||
|
|
||||||
public void add(LetterComposite letter) {
|
public void add(LetterComposite letter) {
|
||||||
children.add(letter);
|
children.add(letter);
|
||||||
|
@ -29,10 +29,10 @@ import java.util.Objects;
|
|||||||
* User class.
|
* User class.
|
||||||
*/
|
*/
|
||||||
public class User {
|
public class User {
|
||||||
private final String firstName;
|
private String firstName;
|
||||||
private final String lastName;
|
private String lastName;
|
||||||
private final boolean isActive;
|
private boolean isActive;
|
||||||
private final String userId;
|
private String userId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -30,10 +30,10 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public class UserDto {
|
public class UserDto {
|
||||||
|
|
||||||
private final String firstName;
|
private String firstName;
|
||||||
private final String lastName;
|
private String lastName;
|
||||||
private final boolean isActive;
|
private boolean isActive;
|
||||||
private final String email;
|
private String email;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
*/
|
*/
|
||||||
public class ConverterTest {
|
public class ConverterTest {
|
||||||
|
|
||||||
private final UserConverter userConverter = new UserConverter();
|
private UserConverter userConverter = new UserConverter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether a converter created of opposite functions holds equality as a bijection.
|
* Tests whether a converter created of opposite functions holds equality as a bijection.
|
||||||
|
@ -18,13 +18,12 @@ CQRS Command Query Responsibility Segregation - Separate the query side from the
|
|||||||
## Applicability
|
## Applicability
|
||||||
Use the CQRS pattern when
|
Use the CQRS pattern when
|
||||||
|
|
||||||
* You want to scale the queries and commands independently.
|
* you want to scale the queries and commands independently.
|
||||||
* You want to use different data models for queries and commands. Useful when dealing with complex domains.
|
* you want to use different data models for queries and commands. Useful when dealing with complex domains.
|
||||||
* You want to use architectures like event sourcing or task based UI.
|
* you want to use architectures like event sourcing or task based UI.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/)
|
* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/)
|
||||||
* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html)
|
* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html)
|
||||||
* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw)
|
* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw)
|
||||||
* [Command and Query Responsibility Segregation (CQRS) pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)
|
|
||||||
|
@ -34,7 +34,7 @@ import org.hibernate.SessionFactory;
|
|||||||
*/
|
*/
|
||||||
public class CommandServiceImpl implements ICommandService {
|
public class CommandServiceImpl implements ICommandService {
|
||||||
|
|
||||||
private final SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
|
||||||
private Author getAuthorByUsername(String username) {
|
private Author getAuthorByUsername(String username) {
|
||||||
Author author;
|
Author author;
|
||||||
|
@ -38,7 +38,7 @@ import org.hibernate.transform.Transformers;
|
|||||||
*/
|
*/
|
||||||
public class QueryServiceImpl implements IQueryService {
|
public class QueryServiceImpl implements IQueryService {
|
||||||
|
|
||||||
private final SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Author getAuthorByUsername(String username) {
|
public Author getAuthorByUsername(String username) {
|
||||||
|
296
dao/README.md
296
dao/README.md
@ -9,298 +9,8 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Object provides an abstract interface to some type of database or other persistence mechanism.
|
Object provides an abstract interface to some type of database or
|
||||||
|
other persistence mechanism.
|
||||||
## Explanation
|
|
||||||
|
|
||||||
Real world example
|
|
||||||
|
|
||||||
> There's a set of customers that need to be persisted to database. Additionally we need the whole set of CRUD (create/read/update/delete) operations so we can operate on customers easily.
|
|
||||||
|
|
||||||
In plain words
|
|
||||||
|
|
||||||
> DAO is an interface we provide over the base persistence mechanism.
|
|
||||||
|
|
||||||
Wikipedia says
|
|
||||||
|
|
||||||
> In computer software, a data access object (DAO) is a pattern that provides an abstract interface to some type of database or other persistence mechanism.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
Walking through our customers example, here's the basic Customer entity.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Customer {
|
|
||||||
|
|
||||||
private int id;
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
|
|
||||||
public Customer(int id, String firstName, String lastName) {
|
|
||||||
this.id = id;
|
|
||||||
this.firstName = firstName;
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(final int id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstName() {
|
|
||||||
return firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstName(final String firstName) {
|
|
||||||
this.firstName = firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastName() {
|
|
||||||
return lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastName(final String lastName) {
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Customer{" + "id=" + getId() + ", firstName='" + getFirstName() + '\'' + ", lastName='"
|
|
||||||
+ getLastName() + '\'' + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object that) {
|
|
||||||
var isEqual = false;
|
|
||||||
if (this == that) {
|
|
||||||
isEqual = true;
|
|
||||||
} else if (that != null && getClass() == that.getClass()) {
|
|
||||||
final var customer = (Customer) that;
|
|
||||||
if (getId() == customer.getId()) {
|
|
||||||
isEqual = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isEqual;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here's the DAO interface and two different implementations for it. InMemoryCustomerDao keeps a simple map of customers
|
|
||||||
in memory while DBCustomerDao is the real RDBMS implementation.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public interface CustomerDao {
|
|
||||||
|
|
||||||
Stream<Customer> getAll() throws Exception;
|
|
||||||
|
|
||||||
Optional<Customer> getById(int id) throws Exception;
|
|
||||||
|
|
||||||
boolean add(Customer customer) throws Exception;
|
|
||||||
|
|
||||||
boolean update(Customer customer) throws Exception;
|
|
||||||
|
|
||||||
boolean delete(Customer customer) throws Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InMemoryCustomerDao implements CustomerDao {
|
|
||||||
|
|
||||||
private final Map<Integer, Customer> idToCustomer = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<Customer> getAll() {
|
|
||||||
return idToCustomer.values().stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Customer> getById(final int id) {
|
|
||||||
return Optional.ofNullable(idToCustomer.get(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(final Customer customer) {
|
|
||||||
if (getById(customer.getId()).isPresent()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
idToCustomer.put(customer.getId(), customer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean update(final Customer customer) {
|
|
||||||
return idToCustomer.replace(customer.getId(), customer) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean delete(final Customer customer) {
|
|
||||||
return idToCustomer.remove(customer.getId()) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DbCustomerDao implements CustomerDao {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(DbCustomerDao.class);
|
|
||||||
|
|
||||||
private final DataSource dataSource;
|
|
||||||
|
|
||||||
public DbCustomerDao(DataSource dataSource) {
|
|
||||||
this.dataSource = dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<Customer> getAll() throws Exception {
|
|
||||||
try {
|
|
||||||
var connection = getConnection();
|
|
||||||
var statement = connection.prepareStatement("SELECT * FROM CUSTOMERS");
|
|
||||||
var resultSet = statement.executeQuery();
|
|
||||||
return StreamSupport.stream(new Spliterators.AbstractSpliterator<Customer>(Long.MAX_VALUE,
|
|
||||||
Spliterator.ORDERED) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean tryAdvance(Consumer<? super Customer> action) {
|
|
||||||
try {
|
|
||||||
if (!resultSet.next()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
action.accept(createCustomer(resultSet));
|
|
||||||
return true;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, false).onClose(() -> mutedClose(connection, statement, resultSet));
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new CustomException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Connection getConnection() throws SQLException {
|
|
||||||
return dataSource.getConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mutedClose(Connection connection, PreparedStatement statement, ResultSet resultSet) {
|
|
||||||
try {
|
|
||||||
resultSet.close();
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
LOGGER.info("Exception thrown " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Customer createCustomer(ResultSet resultSet) throws SQLException {
|
|
||||||
return new Customer(resultSet.getInt("ID"),
|
|
||||||
resultSet.getString("FNAME"),
|
|
||||||
resultSet.getString("LNAME"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Customer> getById(int id) throws Exception {
|
|
||||||
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
|
|
||||||
try (var connection = getConnection();
|
|
||||||
var statement = connection.prepareStatement("SELECT * FROM CUSTOMERS WHERE ID = ?")) {
|
|
||||||
|
|
||||||
statement.setInt(1, id);
|
|
||||||
resultSet = statement.executeQuery();
|
|
||||||
if (resultSet.next()) {
|
|
||||||
return Optional.of(createCustomer(resultSet));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
throw new CustomException(ex.getMessage(), ex);
|
|
||||||
} finally {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Customer customer) throws Exception {
|
|
||||||
if (getById(customer.getId()).isPresent()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (var connection = getConnection();
|
|
||||||
var statement = connection.prepareStatement("INSERT INTO CUSTOMERS VALUES (?,?,?)")) {
|
|
||||||
statement.setInt(1, customer.getId());
|
|
||||||
statement.setString(2, customer.getFirstName());
|
|
||||||
statement.setString(3, customer.getLastName());
|
|
||||||
statement.execute();
|
|
||||||
return true;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
throw new CustomException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean update(Customer customer) throws Exception {
|
|
||||||
try (var connection = getConnection();
|
|
||||||
var statement =
|
|
||||||
connection
|
|
||||||
.prepareStatement("UPDATE CUSTOMERS SET FNAME = ?, LNAME = ? WHERE ID = ?")) {
|
|
||||||
statement.setString(1, customer.getFirstName());
|
|
||||||
statement.setString(2, customer.getLastName());
|
|
||||||
statement.setInt(3, customer.getId());
|
|
||||||
return statement.executeUpdate() > 0;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
throw new CustomException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean delete(Customer customer) throws Exception {
|
|
||||||
try (var connection = getConnection();
|
|
||||||
var statement = connection.prepareStatement("DELETE FROM CUSTOMERS WHERE ID = ?")) {
|
|
||||||
statement.setInt(1, customer.getId());
|
|
||||||
return statement.executeUpdate() > 0;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
throw new CustomException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally here's how we use our DAO to manage customers.
|
|
||||||
|
|
||||||
```java
|
|
||||||
final var dataSource = createDataSource();
|
|
||||||
createSchema(dataSource);
|
|
||||||
final var customerDao = new DbCustomerDao(dataSource);
|
|
||||||
|
|
||||||
addCustomers(customerDao);
|
|
||||||
log.info(ALL_CUSTOMERS);
|
|
||||||
try (var customerStream = customerDao.getAll()) {
|
|
||||||
customerStream.forEach((customer) -> log.info(customer.toString()));
|
|
||||||
}
|
|
||||||
log.info("customerDao.getCustomerById(2): " + customerDao.getById(2));
|
|
||||||
final var customer = new Customer(4, "Dan", "Danson");
|
|
||||||
customerDao.add(customer);
|
|
||||||
log.info(ALL_CUSTOMERS + customerDao.getAll());
|
|
||||||
customer.setFirstName("Daniel");
|
|
||||||
customer.setLastName("Danielson");
|
|
||||||
customerDao.update(customer);
|
|
||||||
log.info(ALL_CUSTOMERS);
|
|
||||||
try (var customerStream = customerDao.getAll()) {
|
|
||||||
customerStream.forEach((cust) -> log.info(cust.toString()));
|
|
||||||
}
|
|
||||||
customerDao.delete(customer);
|
|
||||||
log.info(ALL_CUSTOMERS + customerDao.getAll());
|
|
||||||
|
|
||||||
deleteSchema(dataSource);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
@ -313,4 +23,4 @@ Use the Data Access Object in any of the following situations
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
|
||||||
|
@ -44,7 +44,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
private static final String DB_URL = "jdbc:h2:~/dao";
|
private static final String DB_URL = "jdbc:h2:~/dao";
|
||||||
private static final Logger log = LoggerFactory.getLogger(App.class);
|
private static Logger log = LoggerFactory.getLogger(App.class);
|
||||||
private static final String ALL_CUSTOMERS = "customerDao.getAllCustomers(): ";
|
private static final String ALL_CUSTOMERS = "customerDao.getAllCustomers(): ";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,7 +35,7 @@ public class Customer {
|
|||||||
/**
|
/**
|
||||||
* Creates an instance of customer.
|
* Creates an instance of customer.
|
||||||
*/
|
*/
|
||||||
public Customer(int id, String firstName, String lastName) {
|
public Customer(final int id, final String firstName, final String lastName) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.firstName = firstName;
|
this.firstName = firstName;
|
||||||
this.lastName = lastName;
|
this.lastName = lastName;
|
||||||
|
@ -36,7 +36,7 @@ import java.util.stream.Stream;
|
|||||||
*/
|
*/
|
||||||
public class InMemoryCustomerDao implements CustomerDao {
|
public class InMemoryCustomerDao implements CustomerDao {
|
||||||
|
|
||||||
private final Map<Integer, Customer> idToCustomer = new HashMap<>();
|
private Map<Integer, Customer> idToCustomer = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An eagerly evaluated stream of customers stored in memory.
|
* An eagerly evaluated stream of customers stored in memory.
|
||||||
|
@ -50,7 +50,7 @@ public class DbCustomerDaoTest {
|
|||||||
|
|
||||||
private static final String DB_URL = "jdbc:h2:~/dao";
|
private static final String DB_URL = "jdbc:h2:~/dao";
|
||||||
private DbCustomerDao dao;
|
private DbCustomerDao dao;
|
||||||
private final Customer existingCustomer = new Customer(1, "Freddy", "Krueger");
|
private Customer existingCustomer = new Customer(1, "Freddy", "Krueger");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates customers schema.
|
* Creates customers schema.
|
||||||
|
@ -41,7 +41,7 @@ public class MessageCollectorMember implements Member {
|
|||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final List<String> messages = new ArrayList<>();
|
private List<String> messages = new ArrayList<>();
|
||||||
|
|
||||||
public MessageCollectorMember(String name) {
|
public MessageCollectorMember(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
public final class App {
|
public final class App {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(App.class);
|
private static Logger log = LoggerFactory.getLogger(App.class);
|
||||||
private static final String STUDENT_STRING = "App.main(), student : ";
|
private static final String STUDENT_STRING = "App.main(), student : ";
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import java.util.Optional;
|
|||||||
public final class StudentDataMapperImpl implements StudentDataMapper {
|
public final class StudentDataMapperImpl implements StudentDataMapper {
|
||||||
|
|
||||||
/* Note: Normally this would be in the form of an actual database */
|
/* Note: Normally this would be in the form of an actual database */
|
||||||
private final List<Student> students = new ArrayList<>();
|
private List<Student> students = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Student> find(int studentId) {
|
public Optional<Student> find(int studentId) {
|
||||||
|
@ -9,89 +9,8 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to remote server.
|
Pass data with multiple attributes in one shot from client to server,
|
||||||
|
to avoid multiple calls to remote server.
|
||||||
## Explanation
|
|
||||||
|
|
||||||
Real world example
|
|
||||||
|
|
||||||
> We need to fetch information about customers from remote database. Instead of querying the attributes one at a time, we use DTOs to transfer all the relevant attributes in a single shot.
|
|
||||||
|
|
||||||
In plain words
|
|
||||||
|
|
||||||
> Using DTO relevant information can be fetched with a single backend query.
|
|
||||||
|
|
||||||
Wikipedia says
|
|
||||||
|
|
||||||
> In the field of programming a data transfer object (DTO) is an object that carries data between processes. The
|
|
||||||
motivation for its use is that communication between processes is usually done resorting to remote interfaces
|
|
||||||
(e.g., web services), where each call is an expensive operation. Because the majority of the cost of each call is
|
|
||||||
related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an
|
|
||||||
object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by
|
|
||||||
one call only.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
Let's first introduce our simple customer DTO class.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class CustomerDto {
|
|
||||||
private final String id;
|
|
||||||
private final String firstName;
|
|
||||||
private final String lastName;
|
|
||||||
|
|
||||||
public CustomerDto(String id, String firstName, String lastName) {
|
|
||||||
this.id = id;
|
|
||||||
this.firstName = firstName;
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstName() {
|
|
||||||
return firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastName() {
|
|
||||||
return lastName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Customer resource class acts as the server for customer information.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class CustomerResource {
|
|
||||||
private final List<CustomerDto> customers;
|
|
||||||
|
|
||||||
public CustomerResource(List<CustomerDto> customers) {
|
|
||||||
this.customers = customers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CustomerDto> getAllCustomers() {
|
|
||||||
return customers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(CustomerDto customer) {
|
|
||||||
customers.add(customer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(String customerId) {
|
|
||||||
customers.removeIf(customer -> customer.getId().equals(customerId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Now fetching customer information is easy since we have the DTOs.
|
|
||||||
|
|
||||||
```java
|
|
||||||
var allCustomers = customerResource.getAllCustomers();
|
|
||||||
allCustomers.forEach(customer -> LOGGER.info(customer.getFirstName()));
|
|
||||||
// Kelly
|
|
||||||
// Alfonso
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
@ -107,5 +26,3 @@ Use the Data Transfer Object pattern when
|
|||||||
|
|
||||||
* [Design Pattern - Transfer Object Pattern](https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm)
|
* [Design Pattern - Transfer Object Pattern](https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm)
|
||||||
* [Data Transfer Object](https://msdn.microsoft.com/en-us/library/ff649585.aspx)
|
* [Data Transfer Object](https://msdn.microsoft.com/en-us/library/ff649585.aspx)
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
|
|
||||||
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=014237a67c9d46f384b35e10151956bd)
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<class-diagram version="1.2.0" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
<class-diagram version="1.2.0" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
||||||
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
||||||
<class id="1" language="java" name="com.iluwatar.datatransfer.App" project="data-transfer-object"
|
<class id="1" language="java" name="com.iluwatar.datatransfer.CustomerClientApp" project="data-transfer-object"
|
||||||
file="/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java" binary="false"
|
file="/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java" binary="false"
|
||||||
corner="BOTTOM_RIGHT">
|
corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="145" y="93"/>
|
<position height="-1" width="-1" x="145" y="93"/>
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>com.iluwatar.datatransfer.App</mainClass>
|
<mainClass>com.iluwatar.datatransfer.CustomerClientApp</mainClass>
|
||||||
</manifest>
|
</manifest>
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -32,15 +32,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
* The Data Transfer Object pattern is a design pattern in which an data transfer object is used to
|
* The Data Transfer Object pattern is a design pattern in which an data transfer object is used to
|
||||||
* serve related information together to avoid multiple call for each piece of information.
|
* serve related information together to avoid multiple call for each piece of information.
|
||||||
*
|
*
|
||||||
* <p>In this example, ({@link App}) as as customer details consumer i.e. client to
|
* <p>In this example, ({@link CustomerClientApp}) as as customer details consumer i.e. client to
|
||||||
* request for customer details to server.
|
* request for customer details to server.
|
||||||
*
|
*
|
||||||
* <p>CustomerResource ({@link CustomerResource}) act as server to serve customer information. And
|
* <p>CustomerResource ({@link CustomerResource}) act as server to serve customer information. And
|
||||||
* The CustomerDto ({@link CustomerDto} is data transfer object to share customer information.
|
* The CustomerDto ({@link CustomerDto} is data transfer object to share customer information.
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class CustomerClientApp {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(CustomerClientApp.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method as act client and request to server for details.
|
* Method as act client and request to server for details.
|
@ -30,7 +30,7 @@ import java.util.List;
|
|||||||
* has all customer details.
|
* has all customer details.
|
||||||
*/
|
*/
|
||||||
public class CustomerResource {
|
public class CustomerResource {
|
||||||
private final List<CustomerDto> customers;
|
private List<CustomerDto> customers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise resource with existing customers.
|
* Initialise resource with existing customers.
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
* Copyright © 2014-2019 Ilkka Seppälä
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.iluwatar.datatransfer;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public class AppTest {
|
|
||||||
@Test
|
|
||||||
public void test() throws Exception {
|
|
||||||
App.main(new String[]{});
|
|
||||||
}
|
|
||||||
}
|
|
@ -70,7 +70,7 @@ public class ClubbedTroll implements Troll {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
|
||||||
|
|
||||||
private final Troll decorated;
|
private Troll decorated;
|
||||||
|
|
||||||
public ClubbedTroll(Troll decorated) {
|
public ClubbedTroll(Troll decorated) {
|
||||||
this.decorated = decorated;
|
this.decorated = decorated;
|
||||||
@ -131,9 +131,6 @@ Use Decorator
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b)
|
* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1)
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
|
||||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
|
||||||
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
|
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
|
|
||||||
|
@ -33,7 +33,7 @@ public class ClubbedTroll implements Troll {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
|
||||||
|
|
||||||
private final Troll decorated;
|
private Troll decorated;
|
||||||
|
|
||||||
public ClubbedTroll(Troll decorated) {
|
public ClubbedTroll(Troll decorated) {
|
||||||
this.decorated = decorated;
|
this.decorated = decorated;
|
||||||
|
@ -68,7 +68,7 @@ public class SimpleTrollTest {
|
|||||||
|
|
||||||
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
private List<ILoggingEvent> log = new LinkedList<>();
|
||||||
|
|
||||||
public InMemoryAppender(Class clazz) {
|
public InMemoryAppender(Class clazz) {
|
||||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||||
|
@ -86,7 +86,7 @@ public class DelegateTest {
|
|||||||
*/
|
*/
|
||||||
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
private List<ILoggingEvent> log = new LinkedList<>();
|
||||||
|
|
||||||
public InMemoryAppender() {
|
public InMemoryAppender() {
|
||||||
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
|
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
|
||||||
|
@ -9,78 +9,12 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
Dependency Injection is a software design pattern in which one or more dependencies (or services) are injected, or
|
Dependency Injection is a software design pattern in which one or
|
||||||
passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates
|
more dependencies (or services) are injected, or passed by reference, into a
|
||||||
the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and
|
dependent object (or client) and are made part of the client's state. The
|
||||||
to follow the inversion of control and single responsibility principles.
|
pattern separates the creation of a client's dependencies from its own
|
||||||
|
behavior, which allows program designs to be loosely coupled and to follow the
|
||||||
## Explanation
|
inversion of control and single responsibility principles.
|
||||||
Real world example
|
|
||||||
|
|
||||||
> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably.
|
|
||||||
|
|
||||||
In plain words
|
|
||||||
|
|
||||||
> Dependency Injection separates creation of client's dependencies from its own behavior.
|
|
||||||
|
|
||||||
Wikipedia says
|
|
||||||
|
|
||||||
> In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
Let's first introduce the tobacco brands.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public abstract class Tobacco {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class);
|
|
||||||
|
|
||||||
public void smoke(Wizard wizard) {
|
|
||||||
LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
|
|
||||||
this.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SecondBreakfastTobacco extends Tobacco {
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RivendellTobacco extends Tobacco {
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OldTobyTobacco extends Tobacco {
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Next here's the wizard class hierarchy.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public interface Wizard {
|
|
||||||
|
|
||||||
void smoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AdvancedWizard implements Wizard {
|
|
||||||
|
|
||||||
private final Tobacco tobacco;
|
|
||||||
|
|
||||||
public AdvancedWizard(Tobacco tobacco) {
|
|
||||||
this.tobacco = tobacco;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void smoke() {
|
|
||||||
tobacco.smoke(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And lastly we can show how easy it is to give the old wizard any brand of tobacco.
|
|
||||||
|
|
||||||
```java
|
|
||||||
var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
|
|
||||||
advancedWizard.smoke();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
@ -88,12 +22,5 @@ And lastly we can show how easy it is to give the old wizard any brand of tobacc
|
|||||||
## Applicability
|
## Applicability
|
||||||
Use the Dependency Injection pattern when
|
Use the Dependency Injection pattern when
|
||||||
|
|
||||||
* When you need to remove knowledge of concrete implementation from object
|
* when you need to remove knowledge of concrete implementation from object
|
||||||
* To enable unit testing of classes in isolation using mock objects or stubs
|
* to enable unit testing of classes in isolation using mock objects or stubs
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd)
|
|
||||||
* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871)
|
|
||||||
* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1)
|
|
||||||
* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe)
|
|
||||||
|
@ -29,7 +29,7 @@ package com.iluwatar.dependency.injection;
|
|||||||
*/
|
*/
|
||||||
public class AdvancedWizard implements Wizard {
|
public class AdvancedWizard implements Wizard {
|
||||||
|
|
||||||
private final Tobacco tobacco;
|
private Tobacco tobacco;
|
||||||
|
|
||||||
public AdvancedWizard(Tobacco tobacco) {
|
public AdvancedWizard(Tobacco tobacco) {
|
||||||
this.tobacco = tobacco;
|
this.tobacco = tobacco;
|
||||||
|
@ -31,7 +31,7 @@ import javax.inject.Inject;
|
|||||||
*/
|
*/
|
||||||
public class GuiceWizard implements Wizard {
|
public class GuiceWizard implements Wizard {
|
||||||
|
|
||||||
private final Tobacco tobacco;
|
private Tobacco tobacco;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public GuiceWizard(Tobacco tobacco) {
|
public GuiceWizard(Tobacco tobacco) {
|
||||||
|
@ -29,7 +29,7 @@ package com.iluwatar.dependency.injection;
|
|||||||
*/
|
*/
|
||||||
public class SimpleWizard implements Wizard {
|
public class SimpleWizard implements Wizard {
|
||||||
|
|
||||||
private final OldTobyTobacco tobacco = new OldTobyTobacco();
|
private OldTobyTobacco tobacco = new OldTobyTobacco();
|
||||||
|
|
||||||
public void smoke() {
|
public void smoke() {
|
||||||
tobacco.smoke(this);
|
tobacco.smoke(this);
|
||||||
|
@ -37,7 +37,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
public class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
private List<ILoggingEvent> log = new LinkedList<>();
|
||||||
|
|
||||||
public InMemoryAppender(Class clazz) {
|
public InMemoryAppender(Class clazz) {
|
||||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||||
|
@ -9,9 +9,6 @@ tags:
|
|||||||
- Performance
|
- Performance
|
||||||
---
|
---
|
||||||
|
|
||||||
## Also known as
|
|
||||||
* IsDirty pattern
|
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
To avoid expensive re-acquisition of resources. The resources retain their identity, are kept in some
|
To avoid expensive re-acquisition of resources. The resources retain their identity, are kept in some
|
||||||
fast-access storage, and are re-used to avoid having to acquire them again.
|
fast-access storage, and are re-used to avoid having to acquire them again.
|
||||||
@ -27,4 +24,3 @@ Use the Dirty Flag pattern when
|
|||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Design Patterns: Dirty Flag](https://www.takeupcode.com/podcast/89-design-patterns-dirty-flag/)
|
* [Design Patterns: Dirty Flag](https://www.takeupcode.com/podcast/89-design-patterns-dirty-flag/)
|
||||||
* [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)
|
|
||||||
|
@ -34,7 +34,7 @@ import java.util.List;
|
|||||||
public class World {
|
public class World {
|
||||||
|
|
||||||
private List<String> countries;
|
private List<String> countries;
|
||||||
private final DataFetcher df;
|
private DataFetcher df;
|
||||||
|
|
||||||
public World() {
|
public World() {
|
||||||
this.countries = new ArrayList<String>();
|
this.countries = new ArrayList<String>();
|
||||||
|
@ -33,7 +33,7 @@ public class FrameBuffer implements Buffer {
|
|||||||
public static final int WIDTH = 10;
|
public static final int WIDTH = 10;
|
||||||
public static final int HEIGHT = 8;
|
public static final int HEIGHT = 8;
|
||||||
|
|
||||||
private final Pixel[] pixels = new Pixel[WIDTH * HEIGHT];
|
private Pixel[] pixels = new Pixel[WIDTH * HEIGHT];
|
||||||
|
|
||||||
public FrameBuffer() {
|
public FrameBuffer() {
|
||||||
clearAll();
|
clearAll();
|
||||||
|
@ -31,7 +31,7 @@ public enum Pixel {
|
|||||||
WHITE(0),
|
WHITE(0),
|
||||||
BLACK(1);
|
BLACK(1);
|
||||||
|
|
||||||
private final int color;
|
private int color;
|
||||||
|
|
||||||
Pixel(int color) {
|
Pixel(int color) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
|
@ -35,7 +35,7 @@ public class Scene {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Scene.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(Scene.class);
|
||||||
|
|
||||||
private final Buffer[] frameBuffers;
|
private Buffer[] frameBuffers;
|
||||||
|
|
||||||
private int current;
|
private int current;
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ public class InventoryTest {
|
|||||||
|
|
||||||
|
|
||||||
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
private List<ILoggingEvent> log = new LinkedList<>();
|
||||||
|
|
||||||
public InMemoryAppender(Class clazz) {
|
public InMemoryAppender(Class clazz) {
|
||||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||||
|
@ -28,10 +28,10 @@ package com.iluwatar.doubledispatch;
|
|||||||
*/
|
*/
|
||||||
public class Rectangle {
|
public class Rectangle {
|
||||||
|
|
||||||
private final int left;
|
private int left;
|
||||||
private final int top;
|
private int top;
|
||||||
private final int right;
|
private int right;
|
||||||
private final int bottom;
|
private int bottom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -29,4 +29,3 @@ Use the Aggregator pattern when
|
|||||||
|
|
||||||
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html)
|
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html)
|
||||||
* [Apache Camel - Documentation](http://camel.apache.org/aggregator2.html)
|
* [Apache Camel - Documentation](http://camel.apache.org/aggregator2.html)
|
||||||
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
|
|
||||||
|
@ -23,4 +23,3 @@ Use the Message Channel pattern when
|
|||||||
## Real world examples
|
## Real world examples
|
||||||
|
|
||||||
* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html)
|
* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html)
|
||||||
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
|
|
||||||
|
@ -21,5 +21,4 @@ Use the Publish Subscribe Channel pattern when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
|
||||||
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
|
|
||||||
|
@ -28,4 +28,3 @@ Use the Splitter pattern when
|
|||||||
|
|
||||||
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Sequencer.html)
|
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Sequencer.html)
|
||||||
* [Apache Camel - Documentation](http://camel.apache.org/splitter.html)
|
* [Apache Camel - Documentation](http://camel.apache.org/splitter.html)
|
||||||
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
|
|
||||||
|
@ -26,4 +26,3 @@ Use the Wire Tap pattern when
|
|||||||
|
|
||||||
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/WireTap.html)
|
* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/WireTap.html)
|
||||||
* [Apache Camel - Documentation](http://camel.apache.org/wire-tap.html)
|
* [Apache Camel - Documentation](http://camel.apache.org/wire-tap.html)
|
||||||
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf)
|
|
||||||
|
@ -31,7 +31,7 @@ public enum Event {
|
|||||||
STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED(
|
STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED(
|
||||||
"Traitor detected");
|
"Traitor detected");
|
||||||
|
|
||||||
private final String description;
|
private String description;
|
||||||
|
|
||||||
Event(String description) {
|
Event(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
@ -31,7 +31,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class EventEmitter {
|
public abstract class EventEmitter {
|
||||||
|
|
||||||
private final List<EventObserver> observers;
|
private List<EventObserver> observers;
|
||||||
|
|
||||||
public EventEmitter() {
|
public EventEmitter() {
|
||||||
observers = new LinkedList<>();
|
observers = new LinkedList<>();
|
||||||
|
@ -36,7 +36,7 @@ public enum Weekday {
|
|||||||
SATURDAY("Saturday"),
|
SATURDAY("Saturday"),
|
||||||
SUNDAY("Sunday");
|
SUNDAY("Sunday");
|
||||||
|
|
||||||
private final String description;
|
private String description;
|
||||||
|
|
||||||
Weekday(String description) {
|
Weekday(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
@ -74,7 +74,7 @@ public class KingJoffreyTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
private List<ILoggingEvent> log = new LinkedList<>();
|
||||||
|
|
||||||
public InMemoryAppender(Class<?> clazz) {
|
public InMemoryAppender(Class<?> clazz) {
|
||||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||||
|
@ -33,9 +33,9 @@ public class Event implements IEvent, Runnable {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Event.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(Event.class);
|
||||||
|
|
||||||
private final int eventId;
|
private int eventId;
|
||||||
private final int eventTime;
|
private int eventTime;
|
||||||
private final boolean isSynchronous;
|
private boolean isSynchronous;
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
private boolean isComplete = false;
|
private boolean isComplete = false;
|
||||||
private ThreadCompleteListener eventListener;
|
private ThreadCompleteListener eventListener;
|
||||||
|
@ -43,8 +43,8 @@ public class EventManager implements ThreadCompleteListener {
|
|||||||
public static final int MAX_ID = MAX_RUNNING_EVENTS;
|
public static final int MAX_ID = MAX_RUNNING_EVENTS;
|
||||||
public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes.
|
public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes.
|
||||||
private int currentlyRunningSyncEvent = -1;
|
private int currentlyRunningSyncEvent = -1;
|
||||||
private final Random rand;
|
private Random rand;
|
||||||
private final Map<Integer, Event> eventPool;
|
private Map<Integer, Event> eventPool;
|
||||||
|
|
||||||
private static final String DOES_NOT_EXIST = " does not exist.";
|
private static final String DOES_NOT_EXIST = " does not exist.";
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ import com.iluwatar.eda.model.User;
|
|||||||
*/
|
*/
|
||||||
public class UserCreatedEvent extends AbstractEvent {
|
public class UserCreatedEvent extends AbstractEvent {
|
||||||
|
|
||||||
private final User user;
|
private User user;
|
||||||
|
|
||||||
public UserCreatedEvent(User user) {
|
public UserCreatedEvent(User user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -32,7 +32,7 @@ import com.iluwatar.eda.model.User;
|
|||||||
*/
|
*/
|
||||||
public class UserUpdatedEvent extends AbstractEvent {
|
public class UserUpdatedEvent extends AbstractEvent {
|
||||||
|
|
||||||
private final User user;
|
private User user;
|
||||||
|
|
||||||
public UserUpdatedEvent(User user) {
|
public UserUpdatedEvent(User user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -32,7 +32,7 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class EventDispatcher {
|
public class EventDispatcher {
|
||||||
|
|
||||||
private final Map<Class<? extends Event>, Handler<? extends Event>> handlers;
|
private Map<Class<? extends Event>, Handler<? extends Event>> handlers;
|
||||||
|
|
||||||
public EventDispatcher() {
|
public EventDispatcher() {
|
||||||
handlers = new HashMap<>();
|
handlers = new HashMap<>();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user