Merge branch 'master' into #1510-Circuit-Breaker-Refactoring

This commit is contained in:
swarajsaaj 2020-10-10 22:19:46 +05:30
commit ea49cbfe94
56 changed files with 1385 additions and 672 deletions

View File

@ -1195,6 +1195,33 @@
"contributions": [
"code"
]
},
{
"login": "vdlald",
"name": "Vladislav Golubinov",
"avatar_url": "https://avatars0.githubusercontent.com/u/29997701?v=4",
"profile": "https://github.com/vdlald",
"contributions": [
"code"
]
},
{
"login": "swarajsaaj",
"name": "Swaraj",
"avatar_url": "https://avatars2.githubusercontent.com/u/6285049?v=4",
"profile": "https://github.com/swarajsaaj",
"contributions": [
"code"
]
},
{
"login": "ChFlick",
"name": "Christoph Flick",
"avatar_url": "https://avatars0.githubusercontent.com/u/4465376?v=4",
"profile": "http://christophflick.de",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 4,

View File

@ -30,29 +30,43 @@ on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
# Disabling shallow clone for improving relevancy of SonarQube reporting
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v2
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# Some tests need screen access
- name: Install xvfb
run: sudo apt-get install -y xvfb
# The SonarQube analysis is only for the master branch of the main repository.
# SonarQube scan does not work for forked repositories try changing it to xvfb-run mvn clean verify
# See https://jira.sonarsource.com/browse/MMF-1371

View File

@ -10,7 +10,7 @@
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-131-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-134-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
# Introduction
@ -246,7 +246,7 @@ This project is licensed under the terms of the MIT license.
<tr>
<td align="center"><a href="https://github.com/nishant"><img src="https://avatars2.githubusercontent.com/u/15331971?v=4" width="100px;" alt=""/><br /><sub><b>Nishant Arora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nishant" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/raja-peeyush-kumar-singh"><img src="https://avatars0.githubusercontent.com/u/5496024?v=4" width="100px;" alt=""/><br /><sub><b>Peeyush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=raja-peeyush-kumar-singh" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aravening" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/vINCENT8888801"><img src="https://avatars0.githubusercontent.com/u/8037883?v=4" width="100px;" alt=""/><br /><sub><b>Wei Seng</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vINCENT8888801" title="Code">💻</a></td>
</tr>
<tr>
@ -262,10 +262,14 @@ This project is licensed under the terms of the MIT license.
<td align="center"><a href="https://github.com/mkrzywanski"><img src="https://avatars0.githubusercontent.com/u/15279585?v=4" width="100px;" alt=""/><br /><sub><b>Michał Krzywański</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mkrzywanski" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aravening" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://www.stefan-birkner.de"><img src="https://avatars1.githubusercontent.com/u/711349?v=4" width="100px;" alt=""/><br /><sub><b>Stefan Birkner</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=stefanbirkner" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/fedorskvorcov"><img src="https://avatars3.githubusercontent.com/u/43882212?v=4" width="100px;" alt=""/><br /><sub><b>Fedor Skvorcov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fedorskvorcov" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/samilAyoub"><img src="https://avatars0.githubusercontent.com/u/61546990?v=4" width="100px;" alt=""/><br /><sub><b>samilAyoub</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samilAyoub" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vdlald"><img src="https://avatars0.githubusercontent.com/u/29997701?v=4" width="100px;" alt=""/><br /><sub><b>Vladislav Golubinov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vdlald" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/swarajsaaj"><img src="https://avatars2.githubusercontent.com/u/6285049?v=4" width="100px;" alt=""/><br /><sub><b>Swaraj</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=swarajsaaj" title="Code">💻</a></td>
<td align="center"><a href="http://christophflick.de"><img src="https://avatars0.githubusercontent.com/u/4465376?v=4" width="100px;" alt=""/><br /><sub><b>Christoph Flick</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ChFlick" title="Documentation">📖</a></td>
</tr>
</table>

View File

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

View File

@ -0,0 +1,82 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.abstractfactory;
public class Kingdom {
private King king;
private Castle castle;
private Army army;
public King getKing() {
return king;
}
public Castle getCastle() {
return castle;
}
public Army getArmy() {
return army;
}
public void setKing(King king) {
this.king = king;
}
public void setCastle(Castle castle) {
this.castle = castle;
}
public void setArmy(Army army) {
this.army = army;
}
/**
* The factory of kingdom factories.
*/
public static class FactoryMaker {
/**
* Enumeration for the different types of Kingdoms.
*/
public enum KingdomType {
ELF, ORC
}
/**
* The factory method to create KingdomFactory concrete objects.
*/
public static KingdomFactory makeFactory(KingdomType type) {
switch (type) {
case ELF:
return new ElfKingdomFactory();
case ORC:
return new OrcKingdomFactory();
default:
throw new IllegalArgumentException("KingdomType not supported.");
}
}
}
}

View File

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

View File

@ -45,7 +45,7 @@ public class SpaceStationMir extends GameObject {
@Override
public void collisionResolve(FlamingAsteroid asteroid) {
LOGGER.info(AppConstants.HITS, " {} is damaged! {} is set on fire!", asteroid.getClass()
LOGGER.info(AppConstants.HITS + " {} is damaged! {} is set on fire!", asteroid.getClass()
.getSimpleName(),
this.getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass()
.getSimpleName());
@ -55,14 +55,14 @@ public class SpaceStationMir extends GameObject {
@Override
public void collisionResolve(Meteoroid meteoroid) {
LOGGER.info(AppConstants.HITS, " {} is damaged!", meteoroid.getClass().getSimpleName(),
LOGGER.info(AppConstants.HITS + " {} is damaged!", meteoroid.getClass().getSimpleName(),
this.getClass().getSimpleName(), this.getClass().getSimpleName());
setDamaged(true);
}
@Override
public void collisionResolve(SpaceStationMir mir) {
LOGGER.info(AppConstants.HITS, " {} is damaged!", mir.getClass().getSimpleName(),
LOGGER.info(AppConstants.HITS + " {} is damaged!", mir.getClass().getSimpleName(),
this.getClass().getSimpleName(), this.getClass().getSimpleName());
setDamaged(true);
}

View File

@ -24,11 +24,11 @@ Use the Event Sourcing pattern when
## Real world examples
* [The Lmax Architecture] (https://martinfowler.com/articles/lmax.html)
* [The Lmax Architecture](https://martinfowler.com/articles/lmax.html)
## Credits
* [Martin Fowler - Event Sourcing] (https://martinfowler.com/eaaDev/EventSourcing.html)
* [Event Sourcing | Microsoft Docs] (https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
* [Reference 3: Introducing Event Sourcing] (https://msdn.microsoft.com/en-us/library/jj591559.aspx)
* [Martin Fowler - Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html)
* [Event Sourcing in Microsoft's documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
* [Reference 3: Introducing Event Sourcing](https://msdn.microsoft.com/en-us/library/jj591559.aspx)
* [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)

View File

@ -1,3 +1,27 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,10 @@ tags:
- Performance
---
## Also known as
Resource Pool
## Intent
When objects are expensive to create and they are needed only for short periods of time it is

View File

@ -10,23 +10,35 @@ tags:
## Intent
Separate the interface definition and implementation in different packages. This allows the client to be completely unaware of the implementation.
Separate the interface definition and implementation in different packages. This allows the client
to be completely unaware of the implementation.
## Explanation
Real world example
> An Invoice generator may be created with ability to use different Tax calculators that may be added in the invoice depending upon type of purchase, region etc.
> An Invoice generator may be created with ability to use different Tax calculators that may be
> added in the invoice depending upon type of purchase, region etc.
In plain words
> Separated interface pattern encourages to keep the implementations of an interface decoupled from the client and its definition, so the client is not dependent on the implementation.
> Separated interface pattern encourages to keep the implementations of an interface decoupled from
> the client and its definition, so the client is not dependent on the implementation.
A client code may abstract some specific functionality to an interface, and define the definition of the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface) is an API intended and open to be implemented or extended by a third party). Another package may implement this interface definition with a concrete logic, which will be injected into the client code at runtime (with a third class, injecting the implementation in the client) or at compile time (using Plugin pattern with some configurable file).
A client code may abstract some specific functionality to an interface, and define the definition of
the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface)
is an API intended and open to be implemented or extended by a third party). Another package may
implement this interface definition with a concrete logic, which will be injected into the client
code at runtime (with a third class, injecting the implementation in the client) or at compile time
(using Plugin pattern with some configurable file).
**Programmatic Example**
**Client** An Invoice generator class accepts the cost of the product and calculates the total amount payable inclusive of tax
**Client**
`InvoiceGenerator` class accepts the cost of the product and calculates the total
amount payable inclusive of tax.
```java
public class InvoiceGenerator {
@ -46,21 +58,23 @@ public class InvoiceGenerator {
}
```
The tax calculation logic is delegated to the ```TaxCalculator``` interface
The tax calculation logic is delegated to the `TaxCalculator` interface.
```java
public interface TaxCalculator {
double calculate(double amount);
}
```
**Implementation package**
In another package (which the client is completely unaware of) there exist multiple implementations of the ```TaxCalculator``` interface
```ForeignTaxCalculator``` which levies 60% tax for international products.
In another package (which the client is completely unaware of) there exist multiple implementations
of the `TaxCalculator` interface. `ForeignTaxCalculator` is one of them which levies 60% tax
for international products.
```java
public class ForeignTaxCalculator implements TaxCalculator {
@ -74,7 +88,8 @@ public class ForeignTaxCalculator implements TaxCalculator {
}
```
```DomesticTaxCalculator``` which levies 20% tax for international products.
Another is `DomesticTaxCalculator` which levies 20% tax for international products.
```java
public class DomesticTaxCalculator implements TaxCalculator {
@ -88,7 +103,8 @@ public class DomesticTaxCalculator implements TaxCalculator {
}
```
These both implementations are instantiated and injected in the client class by the ```App.java``` class
These both implementations are instantiated and injected in the client class by the ```App.java```
class.
```java
var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTaxCalculator());
@ -101,9 +117,11 @@ These both implementations are instantiated and injected in the client class by
```
## Class diagram
![alt text](./etc/class_diagram.png "Separated Interface")
## Applicability
Use the Separated interface pattern when
* You are developing a framework package, and your framework needs to call some application code through interfaces.
@ -117,3 +135,4 @@ Use the Separated interface pattern when
## Credits
* [Martin Fowler](https://www.martinfowler.com/eaaCatalog/separatedInterface.html)
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=e08dfb7f2cf6153542ef1b5a00b10abc)

View File

@ -9,14 +9,16 @@ tags:
---
## Intent
Ensure a class only has one instance, and provide a global point of
access to it.
Ensure a class only has one instance, and provide a global point of access to it.
## Explanation
Real world example
> There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. Ivory tower here is singleton.
> There can only be one ivory tower where the wizards study their magic. The same enchanted ivory
> tower is always used by the wizards. Ivory tower here is singleton.
In plain words
@ -24,7 +26,9 @@ In plain words
Wikipedia says
> In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
> In software engineering, the singleton pattern is a software design pattern that restricts the
> instantiation of a class to one object. This is useful when exactly one object is needed to
> coordinate actions across the system.
**Programmatic Example**
@ -38,7 +42,7 @@ public enum EnumIvoryTower {
}
```
Then in order to use
Then in order to use:
```java
var enumIvoryTower1 = EnumIvoryTower.INSTANCE;
@ -47,9 +51,11 @@ assertEquals(enumIvoryTower1, enumIvoryTower2); // true
```
## Class diagram
![alt text](./etc/singleton.urm.png "Singleton pattern class diagram")
## Applicability
Use the Singleton pattern when
* There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point

View File

@ -10,12 +10,17 @@ tags:
---
## Intent
As explained in the book [Game Programming Patterns](http://gameprogrammingpatterns.com/spatial-partition.html) by Bob Nystrom, spatial partition pattern helps to
> efficiently locate objects by storing them in a data structure organized by their positions.
As explained in the book [Game Programming Patterns](http://gameprogrammingpatterns.com/spatial-partition.html)
by Bob Nystrom, spatial partition pattern helps to efficiently locate objects by storing them in a
data structure organized by their positions.
## Explanation
Say, you are building a war game with hundreds, or maybe even thousands of players, who are clashing on the battle field. Each player's position is getting updated every frame. The simple way to handle all interactions taking place on the field is to check each player's position against every other player's position:
Say, you are building a war game with hundreds, or maybe even thousands of players, who are clashing
on the battle field. Each player's position is getting updated every frame. The simple way to handle
all interactions taking place on the field is to check each player's position against every other
player's position:
```java
public void handleMeLee(Unit units[], int numUnits) {
@ -32,21 +37,33 @@ public void handleMeLee(Unit units[], int numUnits) {
}
```
This will include a lot of unnecessary checks between players which are too far apart to have any influence on each other. The nested loops gives this operation an O(n^2) complexity, which has to be performed every frame since many of the objects on the field may be moving each frame.
The idea behind the Spatial Partition design pattern is to enable quick location of objects using a data structure that is organised by their positions, so when performing an operation like the one above, every object's position need not be checked against all other objects' positions. The data structure can be used to store moving and static objects, though in order to keep track of the moving objects, their positions will have to be reset each time they move. This would mean having to create a new instance of the data structure each time an object moves, which would use up additional memory. The common data structures used for this design pattern are:
This will include a lot of unnecessary checks between players which are too far apart to have any
influence on each other. The nested loops gives this operation an O(n^2) complexity, which has to be
performed every frame since many of the objects on the field may be moving each frame. The idea
behind the Spatial Partition design pattern is to enable quick location of objects using a data
structure that is organised by their positions, so when performing an operation like the one above,
every object's position need not be checked against all other objects' positions. The data structure
can be used to store moving and static objects, though in order to keep track of the moving objects,
their positions will have to be reset each time they move. This would mean having to create a new
instance of the data structure each time an object moves, which would use up additional memory. The
common data structures used for this design pattern are:
* Grid
* Quad tree
* k-d tree
* K-d tree
* BSP
* Boundary volume hierarchy
In our implementation, we use the Quadtree data structure which will reduce the time complexity of finding the objects within a certain range from O(n^2) to O(nlogn), decreasing the computations required significantly in case of large number of objects.
In our implementation, we use the Quadtree data structure which will reduce the time complexity of
finding the objects within a certain range from O(n^2) to O(nlogn), decreasing the computations
required significantly in case of large number of objects.
## Class diagram
![alt text](./etc/spatial-partition.urm.png "Spatial Partition pattern class diagram")
## Applicability
This pattern can be used:
* When you need to keep track of a large number of objects' positions, which are getting updated every frame.

View File

@ -24,7 +24,6 @@
package com.iluwatar.spatialpartition;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
/**

View File

@ -9,36 +9,46 @@ tags:
---
## Also known as
Filter, Criteria
## Intent
Specification pattern separates the statement of how to match a
candidate, from the candidate object that it is matched against. As well as its
usefulness in selection, it is also valuable for validation and for building to
order.
Specification pattern separates the statement of how to match a candidate, from the candidate object
that it is matched against. As well as its usefulness in selection, it is also valuable for
validation and for building to order.
## Explanation
Real world example
> There is a pool of different creatures and we often need to select some subset of them.
> We can write our search specification such as "creatures that can fly", "creatures heavier than 500 kilograms", or as a combination of other search specifications, and then give it to the party that will perform the filtering.
> There is a pool of different creatures and we often need to select some subset of them. We can
> write our search specification such as "creatures that can fly", "creatures heavier than 500
> kilograms", or as a combination of other search specifications, and then give it to the party that
> will perform the filtering.
In Plain Words
> Specification pattern allows us to separate the search criteria from the object that performs the search.
> Specification pattern allows us to separate the search criteria from the object that performs the
> search.
Wikipedia says
> In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic.
> In computer programming, the specification pattern is a particular software design pattern,
> whereby business rules can be recombined by chaining the business rules together using boolean
> logic.
**Programmatic Example**
If we look at our creature pool example from above, we have a set of creatures with certain properties.
Those properties can be part of a pre-defined, limited set (represented here by the enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a Creature).
In this case, it is more appropriate to use what we call "parameterized specification", where the property value can be given as an argument when the Creature is instantiated, allowing for more flexibility.
A third option is to combine pre-defined and/or parameterized properties using boolean logic, allowing for near-endless selection possibilities (this is called "composite specification", see below).
The pros and cons of each approach are detailed in the table at the end of this document.
If we look at our creature pool example from above, we have a set of creatures with certain
properties. Those properties can be part of a pre-defined, limited set (represented here by the
enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a
Creature). In this case, it is more appropriate to use what we call "parameterized specification",
where the property value can be given as an argument when the Creature is instantiated, allowing for
more flexibility. A third option is to combine pre-defined and/or parameterized properties using
boolean logic, allowing for near-endless selection possibilities (this is called "composite
specification", see below). The pros and cons of each approach are detailed in the table at the end
of this document.
```java
public interface Creature {
@ -50,7 +60,7 @@ public interface Creature {
}
```
And ``Dragon`` implementation looks like this.
And `Dragon` implementation looks like this.
```java
public class Dragon extends AbstractCreature {
@ -61,7 +71,8 @@ public class Dragon extends AbstractCreature {
}
```
Now that we want to select some subset of them, we use selectors. To select creatures that fly, we should use ``MovementSelector``.
Now that we want to select some subset of them, we use selectors. To select creatures that fly, we
should use `MovementSelector`.
```java
public class MovementSelector extends AbstractSelector<Creature> {
@ -79,7 +90,8 @@ public class MovementSelector extends AbstractSelector<Creature> {
}
```
On the other hand, when selecting creatures heavier than a chosen amount, we use ``MassGreaterThanSelector``.
On the other hand, when selecting creatures heavier than a chosen amount, we use
`MassGreaterThanSelector`.
```java
public class MassGreaterThanSelector extends AbstractSelector<Creature> {
@ -111,7 +123,8 @@ But we could also use our parameterized selector like this:
.collect(Collectors.toList());
```
Our third option is to combine multiple selectors together. Performing a search for special creatures (defined as red, flying, and not small) could be done as follows:
Our third option is to combine multiple selectors together. Performing a search for special
creatures (defined as red, flying, and not small) could be done as follows:
```java
var specialCreaturesSelector =
@ -123,8 +136,9 @@ Our third option is to combine multiple selectors together. Performing a search
**More on Composite Specification**
In Composite Specification, we will create custom instances of ``AbstractSelector`` by combining other selectors (called "leaves") using the three basic logical operators.
These are implemented in ``ConjunctionSelector``, ``DisjunctionSelector`` and ``NegationSelector``.
In Composite Specification, we will create custom instances of `AbstractSelector` by combining
other selectors (called "leaves") using the three basic logical operators. These are implemented in
`ConjunctionSelector`, `DisjunctionSelector` and `NegationSelector`.
```java
public abstract class AbstractSelector<T> implements Predicate<T> {
@ -163,12 +177,14 @@ public class ConjunctionSelector<T> extends AbstractSelector<T> {
}
```
All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that are as generic as possible,
and we will be able to instantiate the ``AbstractSelector`` class by combining any amount of selectors, as exemplified above.
We should be careful though, as it is easy to make a mistake when combining many logical operators; in particular, we should pay attention to the priority of the operations.\
In general, Composite Specification is a great way to write more reusable code, as there is no need to create a Selector class for each filtering operation.
Instead, we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf" selectors and some basic boolean logic.
All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that
are as generic as possible, and we will be able to instantiate the ``AbstractSelector`` class by
combining any amount of selectors, as exemplified above. We should be careful though, as it is easy
to make a mistake when combining many logical operators; in particular, we should pay attention to
the priority of the operations. In general, Composite Specification is a great way to write more
reusable code, as there is no need to create a Selector class for each filtering operation. Instead,
we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf"
selectors and some basic boolean logic.
**Comparison of the different approaches**
@ -181,9 +197,11 @@ Instead, we just create an instance of ``AbstractSelector`` "on the spot", using
| | | + Supports logical operations | - You still need to create the base classes used as leaves |
## Class diagram
![alt text](./etc/specification.png "Specification")
## Applicability
Use the Specification pattern when
* You need to select a subset of objects based on some criteria, and to refresh the selection at various times.

View File

@ -9,15 +9,21 @@ tags:
---
## Also known as
Objects for States
## Intent
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
Allow an object to alter its behavior when its internal state changes. The object will appear to
change its class.
## Explanation
Real world example
> When observing a mammoth in its natural habitat it seems to change its behavior based on the situation. It may first appear calm but over time when it detects a threat it gets angry and dangerous to its surroundings.
> When observing a mammoth in its natural habitat it seems to change its behavior based on the
> situation. It may first appear calm but over time when it detects a threat it gets angry and
> dangerous to its surroundings.
In plain words
@ -25,7 +31,10 @@ In plain words
Wikipedia says
> The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface.
> The state pattern is a behavioral software design pattern that allows an object to alter its
> behavior when its internal state changes. This pattern is close to the concept of finite-state
> machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a
> strategy through invocations of methods defined in the pattern's interface.
**Programmatic Example**
@ -126,17 +135,23 @@ And here is the full example how the mammoth behaves over time.
mammoth.observe();
mammoth.timePasses();
mammoth.observe();
// The mammoth gets angry!
// The mammoth is furious!
// The mammoth calms down.
// The mammoth is calm and peaceful.
```
Program output:
```java
The mammoth gets angry!
The mammoth is furious!
The mammoth calms down.
The mammoth is calm and peaceful.
```
## Class diagram
![alt text](./etc/state_1.png "State")
![alt text](./etc/state_urm.png "State")
## Applicability
Use the State pattern in either of the following cases
* An object's behavior depends on its state, and it must change its behavior at run-time depending on that state

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.state.AngryState" project="state"
file="/state/src/main/java/com/iluwatar/state/AngryState.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="157" x="98" y="310"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.state.PeacefulState" project="state"
file="/state/src/main/java/com/iluwatar/state/PeacefulState.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="173" x="295" y="310"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="3" language="java" name="com.iluwatar.state.State" project="state"
file="/state/src/main/java/com/iluwatar/state/State.java" binary="false" corner="BOTTOM_RIGHT">
<position height="106" width="136" x="138" y="674"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="4" language="java" name="com.iluwatar.state.Mammoth" project="state"
file="/state/src/main/java/com/iluwatar/state/Mammoth.java" binary="false" corner="BOTTOM_RIGHT">
<position height="160" width="177" x="138" y="474"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<realization id="5">
<bendpoint x="107" y="474"/>
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</realization>
<association id="6">
<end type="SOURCE" refId="4" navigable="false">
<attribute id="7" name="state"/>
<multiplicity id="8" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="3" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<realization id="9">
<bendpoint x="345" y="474"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="3"/>
</realization>
<association id="10">
<end type="SOURCE" refId="1" navigable="false">
<attribute id="11" name="mammoth"/>
<multiplicity id="12" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="4" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="13">
<end type="SOURCE" refId="2" navigable="false">
<attribute id="14" name="mammoth"/>
<multiplicity id="15" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="4" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
state/etc/state_urm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -9,17 +9,20 @@ tags:
---
## Also known as
Policy
## Intent
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary
independently from clients that use it.
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets
the algorithm vary independently from clients that use it.
## Explanation
Real world example
> Slaying dragons is a dangerous profession. With experience it becomes easier. Veteran dragonslayers have developed different fighting strategies against different types of dragons.
> Slaying dragons is a dangerous job. With experience it becomes easier. Veteran
> dragonslayers have developed different fighting strategies against different types of dragons.
In plain words
@ -27,7 +30,8 @@ In plain words
Wikipedia says
> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime.
> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral
> software design pattern that enables selecting an algorithm at runtime.
**Programmatic Example**
@ -71,7 +75,8 @@ public class SpellStrategy implements DragonSlayingStrategy {
}
```
And here is the mighty dragonslayer who is able to pick his fighting strategy based on the opponent.
And here is the mighty dragonslayer, who is able to pick his fighting strategy based on the
opponent.
```java
public class DragonSlayer {
@ -92,7 +97,7 @@ public class DragonSlayer {
}
```
Finally here's dragonslayer in action.
Finally here's the dragonslayer in action.
```java
LOGGER.info("Green dragon spotted ahead!");
@ -104,19 +109,25 @@ Finally here's dragonslayer in action.
LOGGER.info("Black dragon lands before you.");
dragonSlayer.changeStrategy(new SpellStrategy());
dragonSlayer.goToBattle();
// Green dragon spotted ahead!
// With your Excalibur you sever the dragon's head!
// Red dragon emerges.
// You shoot the dragon with the magical crossbow and it falls dead on the ground!
// Black dragon lands before you.
// You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
```
Program output:
```
Green dragon spotted ahead!
With your Excalibur you sever the dragon's head!
Red dragon emerges.
You shoot the dragon with the magical crossbow and it falls dead on the ground!
Black dragon lands before you.
You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
```
## Class diagram
![alt text](./etc/strategy_1.png "Strategy")
![alt text](./etc/strategy_urm.png "Strategy")
## Applicability
Use the Strategy pattern when
* Many related classes differ only in their behavior. Strategies provide a way to configure a class either one of many behaviors

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<interface id="1" language="java" name="com.iluwatar.strategy.DragonSlayingStrategy" project="strategy"
file="/strategy/src/main/java/com/iluwatar/strategy/DragonSlayingStrategy.java" binary="false" corner="BOTTOM_RIGHT">
<position height="88" width="186" x="525" y="428"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="2" language="java" name="com.iluwatar.strategy.ProjectileStrategy" project="strategy"
file="/strategy/src/main/java/com/iluwatar/strategy/ProjectileStrategy.java" binary="false" corner="BOTTOM_RIGHT">
<position height="106" width="151" x="218" y="264"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.strategy.SpellStrategy" project="strategy"
file="/strategy/src/main/java/com/iluwatar/strategy/SpellStrategy.java" binary="false" corner="BOTTOM_RIGHT">
<position height="106" width="125" x="409" y="264"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="com.iluwatar.strategy.DragonSlayer" project="strategy"
file="/strategy/src/main/java/com/iluwatar/strategy/DragonSlayer.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="284" x="574" y="264"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="5" language="java" name="com.iluwatar.strategy.MeleeStrategy" project="strategy"
file="/strategy/src/main/java/com/iluwatar/strategy/MeleeStrategy.java" binary="false" corner="BOTTOM_RIGHT">
<position height="106" width="127" x="898" y="264"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<realization id="6">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="1"/>
</realization>
<realization id="7">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="1"/>
</realization>
<realization id="8">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="1"/>
</realization>
<association id="9">
<end type="SOURCE" refId="4" navigable="false">
<attribute id="10" name="strategy"/>
<multiplicity id="11" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -9,21 +9,30 @@ tags:
---
## Intent
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets
subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template
Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's
structure.
## Explanation
Real world example
> The general steps in stealing an item are the same. First you pick the target, next you confuse him somehow and finally you steal the item. However there are many ways to implement these steps.
> The general steps in stealing an item are the same. First you pick the target, next you confuse
> him somehow and finally you steal the item. However there are many ways to implement these steps.
In plain words
> Template Method pattern outlines the general steps in the parent class and lets the concrete child implementations define the details.
> Template Method pattern outlines the general steps in the parent class and lets the concrete child
> implementations define the details.
Wikipedia says
> In object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al. in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.
> In object-oriented programming, the template method is one of the behavioral design patterns
> identified by Gamma et al. in the book Design Patterns. The template method is a method in a
> superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of
> a number of high-level steps. These steps are themselves implemented by additional helper methods
> in the same class as the template method.
**Programmatic Example**
@ -120,9 +129,11 @@ And finally we show how the halfling thief utilizes the different stealing metho
```
## Class diagram
![alt text](./etc/template-method_1.png "Template Method")
![alt text](./etc/template_method_urm.png "Template Method")
## Applicability
The Template Method pattern should be used
* To implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.templatemethod.SubtleMethod" project="template-method"
file="/template-method/src/main/java/com/iluwatar/templatemethod/SubtleMethod.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="142" width="174" x="-90" y="683"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.templatemethod.StealingMethod" project="template-method"
file="/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="159" width="177" x="17" y="484"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.templatemethod.HalflingThief" project="template-method"
file="/template-method/src/main/java/com/iluwatar/templatemethod/HalflingThief.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="124" width="235" x="17" y="320"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="com.iluwatar.templatemethod.HitAndRunMethod" project="template-method"
file="/template-method/src/main/java/com/iluwatar/templatemethod/HitAndRunMethod.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="142" width="174" x="124" y="683"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<association id="5">
<end type="SOURCE" refId="3" navigable="false">
<attribute id="6" name="method"/>
<multiplicity id="7" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="2" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<generalization id="8">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="2"/>
</generalization>
<generalization id="9">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="2"/>
</generalization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -9,16 +9,19 @@ tags:
---
## Intent
It is often the case that tasks to be executed are short-lived and
the number of tasks is large. Creating a new thread for each task would make
the system spend more time creating and destroying the threads than executing
the actual tasks. Thread Pool solves this problem by reusing existing threads
and eliminating the latency of creating new threads.
It is often the case that tasks to be executed are short-lived and the number of tasks is large.
Creating a new thread for each task would make the system spend more time creating and destroying
the threads than executing the actual tasks. Thread Pool solves this problem by reusing existing
threads and eliminating the latency of creating new threads.
## Explanation
Real world example
> We have a large number of relatively short tasks at hand. We need to peel huge amounts of potatoes and serve mighty amount of coffee cups. Creating a new thread for each task would be a waste so we establish a thread pool.
> We have a large number of relatively short tasks at hand. We need to peel huge amounts of potatoes
> and serve mighty amount of coffee cups. Creating a new thread for each task would be a waste so we
> establish a thread pool.
In plain words
@ -26,11 +29,18 @@ In plain words
Wikipedia says
> In computer programming, a thread pool is a software design pattern for achieving concurrency of execution in a computer program. Often also called a replicated workers or worker-crew model, a thread pool maintains multiple threads waiting for tasks to be allocated for concurrent execution by the supervising program. By maintaining a pool of threads, the model increases performance and avoids latency in execution due to frequent creation and destruction of threads for short-lived tasks. The number of available threads is tuned to the computing resources available to the program, such as a parallel task queue after completion of execution.
> In computer programming, a thread pool is a software design pattern for achieving concurrency of
> execution in a computer program. Often also called a replicated workers or worker-crew model,
> a thread pool maintains multiple threads waiting for tasks to be allocated for concurrent
> execution by the supervising program. By maintaining a pool of threads, the model increases
> performance and avoids latency in execution due to frequent creation and destruction of threads
> for short-lived tasks. The number of available threads is tuned to the computing resources
> available to the program, such as a parallel task queue after completion of execution.
**Programmatic Example**
Let's first look at our task hierarchy. We have a base class and then concrete CoffeeMakingTask and PotatoPeelingTask.
Let's first look at our task hierarchy. We have a base class and then concrete `CoffeeMakingTask`
and `PotatoPeelingTask`.
```java
public abstract class Task {
@ -88,8 +98,8 @@ public class PotatoPeelingTask extends Task {
}
```
Next we present a runnable Worker class that the thread pool will utilize to handle all the potato peeling and coffee
making.
Next we present a runnable `Worker` class that the thread pool will utilize to handle all the potato
peeling and coffee making.
```java
public class Worker implements Runnable {
@ -156,9 +166,11 @@ Now we are ready to show the full example in action.
```
## Class diagram
![alt text](./etc/thread-pool.png "Thread Pool")
![alt text](./etc/thread_pool_urm.png "Thread Pool")
## Applicability
Use the Thread Pool pattern when
* You have a large number of short-lived tasks to be executed in parallel

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.Task" project="thread-pool"
file="/thread-pool/src/main/java/com/iluwatar/Task.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="343" y="579"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.Worker" project="thread-pool"
file="/thread-pool/src/main/java/com/iluwatar/Worker.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="344" y="389"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.CoffeeMakingTask" project="thread-pool"
file="/thread-pool/src/main/java/com/iluwatar/CoffeeMakingTask.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="156" x="194" y="717"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="com.iluwatar.PotatoPeelingTask" project="thread-pool"
file="/thread-pool/src/main/java/com/iluwatar/PotatoPeelingTask.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="169" x="390" y="717"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<association id="5">
<end type="SOURCE" refId="2" navigable="false">
<attribute id="6" name="task"/>
<multiplicity id="7" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<generalization id="8">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="1"/>
</generalization>
<generalization id="9">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="1"/>
</generalization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -10,12 +10,15 @@ tags:
---
## Intent
Ensure that a given client is not able to access service resources more than the assigned limit.
## Explanation
Real world example
> A large multinational corporation offers API to its customers. The API is rate-limited and each customer can only make certain amount of calls per second.
> A large multinational corporation offers API to its customers. The API is rate-limited and each
> customer can only make certain amount of calls per second.
In plain words
@ -23,7 +26,9 @@ In plain words
[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling) says
> Control the consumption of resources used by an instance of an application, an individual tenant, or an entire service. This can allow the system to continue to function and meet service level agreements, even when an increase in demand places an extreme load on resources.
> Control the consumption of resources used by an instance of an application, an individual tenant,
> or an entire service. This can allow the system to continue to function and meet service level
> agreements, even when an increase in demand places an extreme load on resources.
**Programmatic Example**
@ -77,7 +82,8 @@ public final class CallsCount {
}
```
Next we introduce the service that the tenants are calling. To track the call count we use the throttler timer.
Next we introduce the service that the tenants are calling. To track the call count we use the
throttler timer.
```java
public interface Throttler {
@ -134,7 +140,8 @@ class B2BService {
}
```
Now we are ready to see the full example in action. Tenant Adidas is rate-limited to 5 calls per second and Nike to 6.
Now we are ready to see the full example in action. Tenant Adidas is rate-limited to 5 calls per
second and Nike to 6.
```java
public static void main(String[] args) {
@ -171,9 +178,11 @@ Now we are ready to see the full example in action. Tenant Adidas is rate-limite
## Class diagram
![alt text](./etc/throttling-pattern.png "Throttling pattern class diagram")
![alt text](./etc/throttling_urm.png "Throttling pattern class diagram")
## Applicability
The Throttling pattern should be used:
* When a service access needs to be restricted to not have high impacts on the performance of the service.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

View File

@ -1,88 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
<class id="1" language="java" name="com.iluwatar.throttling.CallsCount" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java" binary="false" corner="BOTTOM_RIGHT">
<position height="211" width="256" x="656" y="228"/>
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.throttling.Tenant" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/Tenant.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="465" y="524"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.throttling.B2BService" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/B2BService.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="464" y="192"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="4" language="java" name="com.iluwatar.throttling.timer.Throttler" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/timer/Throttler.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="167" y="174"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="5" language="java" name="com.iluwatar.throttling.timer.ThrottleTimerImpl" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/timer/ThrottleTimerImpl.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="166" y="396"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<association id="6">
<end type="SOURCE" refId="3" navigable="false">
<attribute id="7" name="callsCount"/>
<multiplicity id="8" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<dependency id="9">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="4"/>
</dependency>
<dependency id="10">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="2"/>
</dependency>
<association id="11">
<end type="SOURCE" refId="5" navigable="false">
<attribute id="12" name="callsCount"/>
<multiplicity id="13" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<dependency id="14">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="1"/>
</dependency>
<realization id="15">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="4"/>
</realization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -24,7 +24,6 @@
package com.iluwatar.throttling;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;

View File

@ -9,14 +9,18 @@ tags:
---
## Intent
Tolerant Reader is an integration pattern that helps creating robust communication systems. The idea is to be as
tolerant as possible when reading data from another service. This way, when the communication schema changes, the
readers must not break.
Tolerant Reader is an integration pattern that helps creating robust communication systems. The idea
is to be as tolerant as possible when reading data from another service. This way, when the
communication schema changes, the readers must not break.
## Explanation
Real world example
> We are persisting rainbowfish objects to file and later on they need to be restored. What makes it problematic is that rainbowfish data structure is versioned and evolves over time. New version of rainbowfish needs to be able to restore old versions as well.
> We are persisting rainbowfish objects to file and later on they need to be restored. What makes it
> problematic is that rainbowfish data structure is versioned and evolves over time. New version of
> rainbowfish needs to be able to restore old versions as well.
In plain words
@ -24,11 +28,11 @@ In plain words
[Robustness Principle](https://java-design-patterns.com/principles/#robustness-principle) says
> Be conservative in what you do, be liberal in what you accept from others
> Be conservative in what you do, be liberal in what you accept from others.
**Programmatic Example**
Here's the versioned rainbowfish. Notice how the second version introduces additional properties.
Here's the versioned `RainbowFish`. Notice how the second version introduces additional properties.
```java
public class RainbowFish implements Serializable {
@ -104,7 +108,8 @@ public class RainbowFishV2 extends RainbowFish {
}
```
Next we introduce the rainbowfish serializer. This is the class that implements the Tolerant Reader pattern.
Next we introduce the `RainbowFishSerializer`. This is the class that implements the Tolerant Reader
pattern.
```java
public final class RainbowFishSerializer {
@ -185,18 +190,23 @@ And finally here's the full example in action.
LOGGER.info("deserializedFishV2 name={} age={} length={} weight={}",
deserializedFishV2.getName(), deserializedFishV2.getAge(),
deserializedFishV2.getLengthMeters(), deserializedFishV2.getWeightTons());
// fishV1 name=Zed age=10 length=11 weight=12
// deserializedFishV1 name=Zed age=10 length=11 weight=12
// fishV2 name=Scar age=5 length=12 weight=15 sleeping=true hungry=true angry=true
// deserializedFishV2 name=Scar age=5 length=12 weight=15
```
Program output:
```
fishV1 name=Zed age=10 length=11 weight=12
deserializedFishV1 name=Zed age=10 length=11 weight=12
fishV2 name=Scar age=5 length=12 weight=15 sleeping=true hungry=true angry=true
deserializedFishV2 name=Scar age=5 length=12 weight=15
```
## Class diagram
![alt text](./etc/tolerant-reader.png "Tolerant Reader")
![alt text](./etc/tolerant_reader_urm.png "Tolerant Reader")
## Applicability
Use the Tolerant Reader pattern when
* The communication schema can evolve and change and yet the receiving side should not break

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.tolerantreader.RainbowFishSerializer" project="tolerant-reader"
file="/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="123" y="415"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.tolerantreader.RainbowFishV2" project="tolerant-reader"
file="/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishV2.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="389" y="685"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.tolerantreader.RainbowFish" project="tolerant-reader"
file="/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="389" y="404"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<dependency id="4">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</dependency>
<dependency id="5">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="2"/>
</dependency>
<generalization id="6">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="3"/>
</generalization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -10,22 +10,23 @@ tags:
## Intent
Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack and to interleave
the execution of functions without hard coding them together.
Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack
and to interleave the execution of functions without hard coding them together.
## Explanation
Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer
style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems recursion is
more straightforward than their loop counterpart. Furthermore recursion may need less code and looks more concise.
There is a saying that every recursion problem can be solved using a loop with the cost of writing code that is more
difficult to understand.
style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems
recursion is more straightforward than their loop counterpart. Furthermore recursion may need less
code and looks more concise. There is a saying that every recursion problem can be solved using
a loop with the cost of writing code that is more difficult to understand.
However recursion type solutions have one big caveat. For each recursive call it typically needs an intermediate value
stored and there is a limited amount of stack memory available. Running out of stack memory creates a stack overflow
error and halts the program execution.
However recursion type solutions have one big caveat. For each recursive call it typically needs
an intermediate value stored and there is a limited amount of stack memory available. Running out of
stack memory creates a stack overflow error and halts the program execution.
Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the stack.
Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the
stack.
Real world example
@ -37,14 +38,18 @@ In plain words
Wikipedia says
> In Java, trampoline refers to using reflection to avoid using inner classes, for example in event listeners. The time overhead of a reflection call is traded for the space overhead of an inner class. Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class.
> In Java, trampoline refers to using reflection to avoid using inner classes, for example in event
> listeners. The time overhead of a reflection call is traded for the space overhead of an inner
> class. Trampolines in Java usually involve the creation of a GenericListener to pass events to
> an outer class.
**Programmatic Example**
Here's the `Trampoline` implementation in Java.
When `get` is called on the returned Trampoline, internally it will iterate calling `jump` on the returned `Trampoline`
as long as the concrete instance returned is `Trampoline`, stopping once the returned instance is `done`.
When `get` is called on the returned Trampoline, internally it will iterate calling `jump` on the
returned `Trampoline` as long as the concrete instance returned is `Trampoline`, stopping once the
returned instance is `done`.
```java
public interface Trampoline<T> {
@ -110,15 +115,21 @@ Using the `Trampoline` to get Fibonacci values.
log.info("start pattern");
var result = loop(10, 1).result();
log.info("result {}", result);
// start pattern
// result 3628800
```
Program output:
```
start pattern
result 3628800
```
## Class diagram
![alt text](./etc/trampoline.urm.png "Trampoline pattern class diagram")
## Applicability
Use the Trampoline pattern when
* For implementing tail recursive function. This pattern allows to switch on a stackless operation.

139
zh/builder/README.md Normal file
View File

@ -0,0 +1,139 @@
---
layout: pattern
title: Builder
folder: builder
permalink: /patterns/builder/
categories: Creational
tags:
- Gang of Four
---
## 目的
将复杂对象的构造与其表示分开,以便同一构造过程可以创建不同的表示。
## 解释
现实世界例子
> 想象一个角色扮演游戏的角色生成器。最简单的选择是让计算机为你创建角色。但是如果你想选择一些像专业,性别,发色等角色细节时,这个角色生成就变成了一个渐进的过程。当所有选择完成时,该过程也将完成。
用通俗的话说
> 允许你创建不同口味的对象同时避免构造器污染。当一个对象可能有几种口味,或者一个对象的创建涉及到很多步骤时会很有用。
维基百科说
> 建造者模式是一种对象创建的软件设计模式,旨在为伸缩构造器反模式寻找一个解决方案。
说了这么多,让我补充一下什么是伸缩构造函数反模式。我们肯定都见过像下面这样的构造器:
```java
public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) {
}
```
就像你看到的构造器参数的数量很快就会失控同时参数的排列方式可能变得难以理解。另外,如果您将来希望添加更多选项,则此参数列表可能会继续增长。这就被称伸缩构造器反模式。
**编程示例**
明智的选择是使用建造者模式。首先我们有一个英雄要创建。
```java
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
}
```
然后我们有创建者
```java
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
```
然后可以这样使用
```java
var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();
```
## 类图
![alt text](../../builder/etc/builder.urm.png "Builder class diagram")
## 适用性
使用建造者模式当
* 创建复杂对象的算法应独立于组成对象的零件及其组装方式
* 构造过程必须允许所构造的对象具有不同的表示形式
## Java世界例子
* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) as well as similar buffers such as FloatBuffer, IntBuffer and so on.
* [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-)
* All implementations of [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html)
* [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder)
* [Apache Commons Option.Builder](https://commons.apache.org/proper/commons-cli/apidocs/org/apache/commons/cli/Option.Builder.html)
## 鸣谢
* [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)
* [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)
* [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)

159
zh/chain/README.md Normal file
View File

@ -0,0 +1,159 @@
---
layout: pattern
title: Chain of responsibility
folder: chain
permalink: /patterns/chain/
categories: Behavioral
tags:
- Gang of Four
---
## 目的
通过给多个对象一个处理请求的机会,避免请求的发送者和它的接收者耦合。串联接收对象并在链条中传递请求直到一个对象处理它。
## 解释
真实世界例子
> 兽王大声命令他的军队。最近响应的是指挥官,然后是军官,然后是士兵。指挥官,军官,士兵这里就形成了一个责任链。
通俗的说
> 它帮助构建一串对象。请求从一个对象中进入并结束然后进入到一个个对象中直到找到合适的处理器。
维基百科说
> 在面向对象设计中,责任链模式是一种由源命令对象和一系列处理对象组成的设计模式。每个处理对象包含了其定义的可处理的命令对象类型的逻辑。剩下的会传递给链条中的下一个处理对象。
**程序示例**
用上面的兽人来翻译我们的示例。首先我们有请求类
```java
public class Request {
private final RequestType requestType;
private final String requestDescription;
private boolean handled;
public Request(final RequestType requestType, final String requestDescription) {
this.requestType = Objects.requireNonNull(requestType);
this.requestDescription = Objects.requireNonNull(requestDescription);
}
public String getRequestDescription() { return requestDescription; }
public RequestType getRequestType() { return requestType; }
public void markHandled() { this.handled = true; }
public boolean isHandled() { return this.handled; }
@Override
public String toString() { return getRequestDescription(); }
}
public enum RequestType {
DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
}
```
然后是请求处理器的层次结构
```java
public abstract class RequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
private final RequestHandler next;
public RequestHandler(RequestHandler next) {
this.next = next;
}
public void handleRequest(Request req) {
if (next != null) {
next.handleRequest(req);
}
}
protected void printHandling(Request req) {
LOGGER.info("{} handling request \"{}\"", this, req);
}
@Override
public abstract String toString();
}
public class OrcCommander extends RequestHandler {
public OrcCommander(RequestHandler handler) {
super(handler);
}
@Override
public void handleRequest(Request req) {
if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) {
printHandling(req);
req.markHandled();
} else {
super.handleRequest(req);
}
}
@Override
public String toString() {
return "Orc commander";
}
}
// OrcOfficer和OrcSoldier的定义与OrcCommander类似
```
然后我们有兽王下达命令并形成链条
```java
public class OrcKing {
RequestHandler chain;
public OrcKing() {
buildChain();
}
private void buildChain() {
chain = new OrcCommander(new OrcOfficer(new OrcSoldier(null)));
}
public void makeRequest(Request req) {
chain.handleRequest(req);
}
}
```
然后这样使用它
```java
var king = new OrcKing();
king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle")); // Orc commander handling request "defend castle"
king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner")); // Orc officer handling request "torture prisoner"
king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax")); // Orc soldier handling request "collect tax"
```
## 类图
![alt text](../../chain/etc/chain.urm.png "Chain of Responsibility class diagram")
## 适用性
使用责任链模式当
* 多于一个对象可能要处理请求,并且处理器并不知道一个优先级。处理器应自动确定。
* 你想对多个对象之一发出请求而无需明确指定接收者
* 处理请求的对象集合应该被动态指定时
## Java世界例子
* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)
## 鸣谢
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)

139
zh/decorator/README.md Normal file
View File

@ -0,0 +1,139 @@
---
layout: pattern
title: Decorator
folder: decorator
permalink: /patterns/decorator/
categories: Structural
tags:
- Gang Of Four
- Extensibility
---
## 或称
包装器
## 目的
动态的为对象附加额外的职责。装饰器为子类提供了灵活的替代方案,以扩展功能。
## 解释
真实世界例子
> 附近的山丘上住着一个愤怒的巨魔。通常它是徒手的,但有时它有武器。为了武装巨魔不必创建新的巨魔,而是用合适的武器动态的装饰它。
通俗的说
> 装饰者模式让你可以在运行时通过把对象包装进一个装饰类对象中来动态的改变一个对象的行为。
维基百科说
> 在面向对象的编程中,装饰器模式是一种设计模式,它允许将行为静态或动态地添加到单个对象中,而不会影响同一类中其他对象的行为。装饰器模式通常对于遵守单一责任原则很有用,因为它允许将功能划分到具有唯一关注领域的类之间。
**程序示例**
以巨魔的为例。首先我有有一个简单的巨魔,实现了巨魔接口。
程序mple. First of all we have a simple troll implementing the troll interface
```java
public interface Troll {
void attack();
int getAttackPower();
void fleeBattle();
}
public class SimpleTroll implements Troll {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleTroll.class);
@Override
public void attack() {
LOGGER.info("The troll tries to grab you!");
}
@Override
public int getAttackPower() {
return 10;
}
@Override
public void fleeBattle() {
LOGGER.info("The troll shrieks in horror and runs away!");
}
}
```
下面我们想为巨魔添加球棒。我们可以用装饰者来动态的实现。
```java
public class ClubbedTroll implements Troll {
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
private final Troll decorated;
public ClubbedTroll(Troll decorated) {
this.decorated = decorated;
}
@Override
public void attack() {
decorated.attack();
LOGGER.info("The troll swings at you with a club!");
}
@Override
public int getAttackPower() {
return decorated.getAttackPower() + 10;
}
@Override
public void fleeBattle() {
decorated.fleeBattle();
}
}
```
这里是巨魔的实战
```java
// simple troll
var troll = new SimpleTroll();
troll.attack(); // The troll tries to grab you!
troll.fleeBattle(); // The troll shrieks in horror and runs away!
// change the behavior of the simple troll by adding a decorator
var clubbedTroll = new ClubbedTroll(troll);
clubbedTroll.attack(); // The troll tries to grab you! The troll swings at you with a club!
clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away!
```
## 类图
![alt text](../../decorator/etc/decorator.urm.png "Decorator pattern class diagram")
## 适用性
使用装饰者
* 动态透明地向单个对象添加职责,即不影响其他对象
* 对于可以撤销的责任
* 当通过子类化进行扩展是不切实际的。有时可能会有大量的独立扩展,并且会产生大量的子类来支持每种组合。 否则类定义可能被隐藏或无法用于子类化。
## 教程
* [Decorator Pattern Tutorial](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example)
## Java世界的例子
* [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html),
[java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html)
* [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-)
* [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-)
* [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-)
## 鸣谢
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b)
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)

207
zh/facade/README.md Normal file
View File

@ -0,0 +1,207 @@
---
layout: pattern
title: Facade
folder: facade
permalink: /patterns/facade/
categories: Structural
tags:
- Gang Of Four
- Decoupling
---
## 目的
为一个子系统中的一系列接口提供一个统一的接口。外观定义了一个更高级别的接口以便子系统更容易使用。
## 解释
真实世界的例子
> 一个金矿是怎么工作的?“嗯,矿工下去然后挖金子!”你说。这是你所相信的因为你在使用一个金矿对外提供的一个简单接口,在内部它要却要做很多事情。这个简单的接口对复杂的子系统来说就是一个外观。
用通俗的话说
> 外观模式为一个复杂的子系统提供一个简单的接口。
维基百科说
> 外观是为很大体量的代码(比如类库)提供简单接口的一种对象。
**程序示例**
使用上面金矿的例子。这里我们有矮人的矿工等级制度。
```java
public abstract class DwarvenMineWorker {
private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenMineWorker.class);
public void goToSleep() {
LOGGER.info("{} goes to sleep.", name());
}
public void wakeUp() {
LOGGER.info("{} wakes up.", name());
}
public void goHome() {
LOGGER.info("{} goes home.", name());
}
public void goToMine() {
LOGGER.info("{} goes to the mine.", name());
}
private void action(Action action) {
switch (action) {
case GO_TO_SLEEP:
goToSleep();
break;
case WAKE_UP:
wakeUp();
break;
case GO_HOME:
goHome();
break;
case GO_TO_MINE:
goToMine();
break;
case WORK:
work();
break;
default:
LOGGER.info("Undefined action");
break;
}
}
public void action(Action... actions) {
Arrays.stream(actions).forEach(this::action);
}
public abstract void work();
public abstract String name();
enum Action {
GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
}
}
public class DwarvenTunnelDigger extends DwarvenMineWorker {
private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class);
@Override
public void work() {
LOGGER.info("{} creates another promising tunnel.", name());
}
@Override
public String name() {
return "Dwarven tunnel digger";
}
}
public class DwarvenGoldDigger extends DwarvenMineWorker {
private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenGoldDigger.class);
@Override
public void work() {
LOGGER.info("{} digs for gold.", name());
}
@Override
public String name() {
return "Dwarf gold digger";
}
}
public class DwarvenCartOperator extends DwarvenMineWorker {
private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenCartOperator.class);
@Override
public void work() {
LOGGER.info("{} moves gold chunks out of the mine.", name());
}
@Override
public String name() {
return "Dwarf cart operator";
}
}
```
为了操纵所有这些矿工我们有了这个外观
```java
public class DwarvenGoldmineFacade {
private final List<DwarvenMineWorker> workers;
public DwarvenGoldmineFacade() {
workers = List.of(
new DwarvenGoldDigger(),
new DwarvenCartOperator(),
new DwarvenTunnelDigger());
}
public void startNewDay() {
makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
}
public void digOutGold() {
makeActions(workers, DwarvenMineWorker.Action.WORK);
}
public void endDay() {
makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
}
private static void makeActions(Collection<DwarvenMineWorker> workers,
DwarvenMineWorker.Action... actions) {
workers.forEach(worker -> worker.action(actions));
}
}
```
现在来使用外观
```java
DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();
facade.startNewDay();
// Dwarf gold digger wakes up.
// Dwarf gold digger goes to the mine.
// Dwarf cart operator wakes up.
// Dwarf cart operator goes to the mine.
// Dwarven tunnel digger wakes up.
// Dwarven tunnel digger goes to the mine.
facade.digOutGold();
// Dwarf gold digger digs for gold.
// Dwarf cart operator moves gold chunks out of the mine.
// Dwarven tunnel digger creates another promising tunnel.
facade.endDay();
// Dwarf gold digger goes home.
// Dwarf gold digger goes to sleep.
// Dwarf cart operator goes home.
// Dwarf cart operator goes to sleep.
// Dwarven tunnel digger goes home.
// Dwarven tunnel digger goes to sleep.
```
## 类图
![alt text](../../facade/etc/facade.urm.png "Facade pattern class diagram")
## 适用性
使用外观模式当
* 你想为一个复杂的子系统提供一个简单的接口。随着子系统的发展,它们通常会变得更加复杂。多数模式在应用时会导致更多和更少的类。这使子系统更可重用,更易于自定义,但是对于不需要自定义它的客户来说,使用它也变得更加困难。 外观可以提供子系统的简单默认视图,足以满足大多数客户端的需求。只有需要更多可定制性的客户才需要查看外观外的东西(原子系统提供的接口)。
* 客户端与抽象的实现类之间存在许多依赖关系。 引入外观以使子系统与客户端和其他子系统分离,从而提高子系统的独立性和可移植性。
* 您想对子系统进行分层。 使用外观来定义每个子系统级别的入口点。 如果子系统是相关的,则可以通过使子系统仅通过其外观相互通信来简化它们之间的依赖性。
## 鸣谢
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)

View File

@ -0,0 +1,88 @@
---
layout: pattern
title: Factory Method
folder: factory-method
permalink: /patterns/factory-method/
categories: Creational
tags:
- Extensibility
- Gang Of Four
---
## Also known as
# 或称
虚拟构造器
## 目的
为创建一个对象定义一个接口,但是让子类决定实例化哪个类。工厂方法允许类将实例化延迟到子类。
## 解释
真实世界例子
> 铁匠生产武器。精灵需要精灵武器,而兽人需要兽人武器。根据客户来召唤正确类型的铁匠。
通俗的说
> 它为类提供了一种把实例化的逻辑委托给子类的方式。
维基百科上说
> 在基于类的编程中,工厂方法模式是一种创建型设计模式用来解决创建对象的问题,而不需要指定将要创建对象的确切类。这是通过调用工厂方法创建对象来完成的,而不是通过调用构造器。该工厂方法在接口中指定并由子类实现,或者在基类实现并可以选择由子类重写。
**程序示例**
以上面的铁匠为例,首先我们有铁匠的接口和一些它的实现。
```java
public interface Blacksmith {
Weapon manufactureWeapon(WeaponType weaponType);
}
public class ElfBlacksmith implements Blacksmith {
public Weapon manufactureWeapon(WeaponType weaponType) {
return ELFARSENAL.get(weaponType);
}
}
public class OrcBlacksmith implements Blacksmith {
public Weapon manufactureWeapon(WeaponType weaponType) {
return ORCARSENAL.get(weaponType);
}
}
```
现在随着客户的到来,会召唤出正确类型的铁匠并制造出要求的武器。
```java
var blacksmith = new ElfBlacksmith();
blacksmith.manufactureWeapon(WeaponType.SPEAR);
blacksmith.manufactureWeapon(WeaponType.AXE);
// Elvish weapons are created
```
## 类图
![alt text](../../factory-method/etc/factory-method.urm.png "Factory Method pattern class diagram")
## 适用性
使用工厂方法模式当
* 一个类无法预料它所要必须创建的对象的类
* 一个类想要它的子类来指定它要创建的对象
* 类将责任委派给几个帮助子类中的一个,而你想定位了解是具体之中的哪一个
## Java中的例子
* [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
* [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
* [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
* [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
* [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-)
* [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-)
* [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--)
## 鸣谢
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)