Merge branch 'master' into adapter-grammatical-fixes
This commit is contained in:
commit
d76715be82
@ -1541,6 +1541,33 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "samuelpsouza",
|
||||
"name": "Samuel Souza",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/17254162?v=4",
|
||||
"profile": "https://www.linkedin.com/in/souzasamuel/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "marlo2222",
|
||||
"name": "Marlo Henrique",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/40809563?v=4",
|
||||
"profile": "https://github.com/marlo2222",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AndriyPyzh",
|
||||
"name": "AndriyPyzh",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/57706635?v=4",
|
||||
"profile": "https://github.com/AndriyPyzh",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2021 Ilkka Seppälä
|
||||
Copyright © 2014-2021 Ilkka Seppälä
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -19,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Module Model-view-viewmodel is using ZK framework
|
||||
ZK framework is licensed under LGPL and the license can be found at lgpl-3.0.txt
|
||||
|
@ -10,12 +10,12 @@
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<br/>
|
||||
|
||||
Read in different language : [**zh**](/localization/zh/README.md), [**ko**](/localization/ko/README.md), [**fr**](/localization/fr/README.md), [**tr**](/localization/tr/README.md), [**ar**](/localization/ar/README.md), [**es**](/localization/es/README.md)
|
||||
Read in different language : [**zh**](/localization/zh/README.md), [**ko**](/localization/ko/README.md), [**fr**](/localization/fr/README.md), [**tr**](/localization/tr/README.md), [**ar**](/localization/ar/README.md), [**es**](/localization/es/README.md), [**pt**](/localization/pt/README.md)
|
||||
|
||||
<br/>
|
||||
|
||||
@ -329,6 +329,9 @@ This project is licensed under the terms of the MIT license.
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Xenilo137"><img src="https://avatars.githubusercontent.com/u/24865069?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xenilo137</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Xenilo137" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/souzasamuel/"><img src="https://avatars.githubusercontent.com/u/17254162?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samuel Souza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samuelpsouza" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/marlo2222"><img src="https://avatars.githubusercontent.com/u/40809563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marlo Henrique</b></sub></a><br /><a href="#translation-marlo2222" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/AndriyPyzh"><img src="https://avatars.githubusercontent.com/u/57706635?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AndriyPyzh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AndriyPyzh" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -20,9 +20,9 @@ objects without specifying their concrete classes.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> To create a kingdom we need objects with a common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
|
||||
> To create a kingdom we need objects with a common theme. The elven kingdom needs an elven king, elven castle, and elven army whereas the orcish kingdom needs an orcish king, orcish castle, and orcish army. There is a dependency between the objects in the kingdom.
|
||||
|
||||
In plain words
|
||||
|
||||
@ -34,7 +34,7 @@ Wikipedia says
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the
|
||||
Translating the kingdom example above. First of all, we have some interfaces and implementation for the objects in the
|
||||
kingdom.
|
||||
|
||||
```java
|
||||
@ -52,21 +52,21 @@ public interface Army {
|
||||
|
||||
// Elven implementations ->
|
||||
public class ElfCastle implements Castle {
|
||||
static final String DESCRIPTION = "This is the Elven castle!";
|
||||
static final String DESCRIPTION = "This is the elven castle!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
public class ElfKing implements King {
|
||||
static final String DESCRIPTION = "This is the Elven king!";
|
||||
static final String DESCRIPTION = "This is the elven king!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
public class ElfArmy implements Army {
|
||||
static final String DESCRIPTION = "This is the Elven Army!";
|
||||
static final String DESCRIPTION = "This is the elven Army!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
@ -77,7 +77,7 @@ public class ElfArmy implements Army {
|
||||
|
||||
```
|
||||
|
||||
Then we have the abstraction and implementations for the kingdom factory
|
||||
Then we have the abstraction and implementations for the kingdom factory.
|
||||
|
||||
```java
|
||||
public interface KingdomFactory {
|
||||
@ -111,7 +111,7 @@ public class OrcKingdomFactory implements KingdomFactory {
|
||||
}
|
||||
```
|
||||
|
||||
Now we have our abstract factory that lets us make family of related objects i.e. Elven kingdom factory creates Elven castle, king and army etc.
|
||||
Now we have the abstract factory that lets us make a family of related objects i.e. elven kingdom factory creates elven castle, king and army, etc.
|
||||
|
||||
```java
|
||||
var factory = new ElfKingdomFactory();
|
||||
@ -127,13 +127,13 @@ army.getDescription();
|
||||
Program output:
|
||||
|
||||
```java
|
||||
This is the Elven castle!
|
||||
This is the Elven king!
|
||||
This is the Elven Army!
|
||||
This is the elven castle!
|
||||
This is the elven king!
|
||||
This is the elven Army!
|
||||
```
|
||||
|
||||
Now, we can design a factory for our different kingdom factories. In this example, we created FactoryMaker, responsible for returning an instance of either ElfKingdomFactory or OrcKingdomFactory.
|
||||
The client can use FactoryMaker to create the desired concrete factory which, in turn, will produce different concrete objects (Army, King, Castle).
|
||||
Now, we can design a factory for our different kingdom factories. In this example, we created `FactoryMaker`, responsible for returning an instance of either `ElfKingdomFactory` or `OrcKingdomFactory`.
|
||||
The client can use `FactoryMaker` to create the desired concrete factory which, in turn, will produce different concrete objects (derived from `Army`, `King`, `Castle`).
|
||||
In this example, we also used an enum to parameterize which type of kingdom factory the client will ask for.
|
||||
|
||||
```java
|
||||
@ -179,8 +179,8 @@ public static void main(String[] args) {
|
||||
|
||||
Use the Abstract Factory pattern when
|
||||
|
||||
* The system should be independent of how its products are created, composed and represented
|
||||
* The system should be configured with one of multiple families of products
|
||||
* The system should be independent of how its products are created, composed, and represented
|
||||
* The system should be configured with one of the multiple families of products
|
||||
* The family of related product objects is designed to be used together, and you need to enforce this constraint
|
||||
* You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
|
||||
* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
|
||||
@ -196,13 +196,13 @@ Example use cases
|
||||
* Unit test case writing becomes much easier
|
||||
* UI tools for different OS
|
||||
|
||||
## Consequences:
|
||||
## Consequences
|
||||
|
||||
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
|
||||
* While the pattern is great when creating predefined objects, adding the new ones might be challenging.
|
||||
* The code becomes more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
|
||||
* The code becomes more complicated than it should be since a lot of new interfaces and classes are introduced along with the pattern.
|
||||
|
||||
## Tutorial
|
||||
## Tutorials
|
||||
|
||||
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
||||
|
||||
|
@ -37,7 +37,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
*
|
||||
* <p>The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory})
|
||||
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
|
||||
* both concrete implementations to create a king, a castle and an army.
|
||||
* both concrete implementations to create a king, a castle, and an army.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App implements Runnable {
|
||||
@ -60,13 +60,13 @@ public class App implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOGGER.info("Elf Kingdom");
|
||||
LOGGER.info("elf kingdom");
|
||||
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
LOGGER.info(kingdom.getArmy().getDescription());
|
||||
LOGGER.info(kingdom.getCastle().getDescription());
|
||||
LOGGER.info(kingdom.getKing().getDescription());
|
||||
|
||||
LOGGER.info("Orc Kingdom");
|
||||
LOGGER.info("orc kingdom");
|
||||
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||
LOGGER.info(kingdom.getArmy().getDescription());
|
||||
LOGGER.info(kingdom.getCastle().getDescription());
|
||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class ElfArmy implements Army {
|
||||
|
||||
static final String DESCRIPTION = "This is the Elven Army!";
|
||||
static final String DESCRIPTION = "This is the elven army!";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class ElfCastle implements Castle {
|
||||
|
||||
static final String DESCRIPTION = "This is the Elven castle!";
|
||||
static final String DESCRIPTION = "This is the elven castle!";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class ElfKing implements King {
|
||||
|
||||
static final String DESCRIPTION = "This is the Elven king!";
|
||||
static final String DESCRIPTION = "This is the elven king!";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class OrcArmy implements Army {
|
||||
|
||||
static final String DESCRIPTION = "This is the Orc Army!";
|
||||
static final String DESCRIPTION = "This is the orc army!";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class OrcCastle implements Castle {
|
||||
|
||||
static final String DESCRIPTION = "This is the Orc castle!";
|
||||
static final String DESCRIPTION = "This is the orc castle!";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
@ -28,7 +28,7 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class OrcKing implements King {
|
||||
|
||||
static final String DESCRIPTION = "This is the Orc king!";
|
||||
static final String DESCRIPTION = "This is the orc king!";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
@ -29,14 +29,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for abstract factory.
|
||||
* Tests for abstract factory.
|
||||
*/
|
||||
class AbstractFactoryTest {
|
||||
|
||||
private final App app = new App();
|
||||
|
||||
@Test
|
||||
void king() {
|
||||
void verifyKingCreation() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -51,7 +51,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void castle() {
|
||||
void verifyCastleCreation() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -66,7 +66,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void army() {
|
||||
void verifyArmyCreation() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -81,7 +81,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createElfKingdom() {
|
||||
void verifyElfKingdomCreation() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -97,7 +97,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createOrcKingdom() {
|
||||
void verifyOrcKingdomCreation() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
|
@ -28,10 +28,7 @@ import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
/**
|
||||
* Issue: Add at least one assertion to this test case.
|
||||
*
|
||||
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
|
||||
* throws an exception.
|
||||
* Check whether the execution of the main method in {@link App} throws an exception.
|
||||
*/
|
||||
class AppTest {
|
||||
|
||||
|
@ -105,7 +105,7 @@ Use the Adapter pattern when
|
||||
* You need to use several existing subclasses, but it's impractical to adapt their interface by subclassing everyone. An object adapter can adapt the interface of its parent class.
|
||||
* Most of the applications using third-party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
|
||||
|
||||
## Consequences:
|
||||
## Consequences
|
||||
Class and object adapters have different trade-offs. A class adapter
|
||||
|
||||
* Adapts Adaptee to Target by committing to a concrete Adaptee class. As a consequence, a class adapter won’t work when we want to adapt a class and all its subclasses.
|
||||
|
@ -19,7 +19,7 @@ Decouple an abstraction from its implementation so that the two can vary indepen
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Consider you have a weapon with different enchantments, and you are supposed to allow mixing
|
||||
> different weapons with different enchantments. What would you do? Create multiple copies of each
|
||||
@ -161,27 +161,36 @@ public class SoulEatingEnchantment implements Enchantment {
|
||||
Here are both hierarchies in action:
|
||||
|
||||
```java
|
||||
LOGGER.info("The knight receives an enchanted sword.");
|
||||
var enchantedSword = new Sword(new SoulEatingEnchantment());
|
||||
enchantedSword.wield();
|
||||
enchantedSword.swing();
|
||||
enchantedSword.unwield();
|
||||
// The sword is wielded.
|
||||
// The item spreads bloodlust.
|
||||
// The sword is swinged.
|
||||
// The item eats the soul of enemies.
|
||||
// The sword is unwielded.
|
||||
// Bloodlust slowly disappears.
|
||||
|
||||
LOGGER.info("The valkyrie receives an enchanted hammer.");
|
||||
var hammer = new Hammer(new FlyingEnchantment());
|
||||
hammer.wield();
|
||||
hammer.swing();
|
||||
hammer.unwield();
|
||||
// The hammer is wielded.
|
||||
// The item begins to glow faintly.
|
||||
// The hammer is swinged.
|
||||
// The item flies and strikes the enemies finally returning to owner's hand.
|
||||
// The hammer is unwielded.
|
||||
// The item's glow fades.
|
||||
```
|
||||
|
||||
Here's the console output.
|
||||
|
||||
```
|
||||
The knight receives an enchanted sword.
|
||||
The sword is wielded.
|
||||
The item spreads bloodlust.
|
||||
The sword is swung.
|
||||
The item eats the soul of enemies.
|
||||
The sword is unwielded.
|
||||
Bloodlust slowly disappears.
|
||||
The valkyrie receives an enchanted hammer.
|
||||
The hammer is wielded.
|
||||
The item begins to glow faintly.
|
||||
The hammer is swung.
|
||||
The item flies and strikes the enemies finally returning to owner's hand.
|
||||
The hammer is unwielded.
|
||||
The item's glow fades.
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
@ -16,11 +16,11 @@ process can create different representations.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Imagine a character generator for a role-playing game. The easiest option is to let the computer
|
||||
> create the character for you. If you want to manually select the character details like
|
||||
> profession, gender, hair color etc. the character generation becomes a step-by-step process that
|
||||
> profession, gender, hair color, etc. the character generation becomes a step-by-step process that
|
||||
> completes when all the selections are ready.
|
||||
|
||||
In plain words
|
||||
@ -49,7 +49,7 @@ anti-pattern.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
The sane alternative is to use the Builder pattern. First of all we have our hero that we want to
|
||||
The sane alternative is to use the Builder pattern. First of all, we have our hero that we want to
|
||||
create:
|
||||
|
||||
```java
|
||||
@ -134,7 +134,7 @@ Use the Builder pattern when
|
||||
* The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
|
||||
* The construction process must allow different representations for the object that's constructed
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [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.
|
||||
|
@ -1,8 +1,8 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Chain of responsibility
|
||||
folder: chain
|
||||
permalink: /patterns/chain/
|
||||
folder: chain-of-responsibility
|
||||
permalink: /patterns/chain-of-responsibility/
|
||||
categories: Behavioral
|
||||
language: en
|
||||
tags:
|
||||
@ -10,16 +10,17 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to
|
||||
handle the request. Chain the receiving objects and pass the request along the chain until an object
|
||||
handles it.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> The Orc King gives loud orders to his army. The closest one to react is the commander, then
|
||||
> officer and then soldier. The commander, officer and soldier here form a chain of responsibility.
|
||||
> an officer, and then a soldier. The commander, officer, and soldier form a chain of responsibility.
|
||||
|
||||
In plain words
|
||||
|
||||
@ -35,7 +36,7 @@ Wikipedia says
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Translating our example with the orcs from above. First we have the `Request` class:
|
||||
Translating our example with the orcs from above. First, we have the `Request` class:
|
||||
|
||||
```java
|
||||
public class Request {
|
||||
@ -66,7 +67,7 @@ public enum RequestType {
|
||||
}
|
||||
```
|
||||
|
||||
Then the request handler hierarchy
|
||||
Next, we show the request handler hierarchy.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@ -116,7 +117,7 @@ public class OrcCommander extends RequestHandler {
|
||||
|
||||
```
|
||||
|
||||
Then we have the Orc King who gives the orders and forms the chain
|
||||
The Orc King gives the orders and forms the chain.
|
||||
|
||||
```java
|
||||
public class OrcKing {
|
||||
@ -136,18 +137,26 @@ public class OrcKing {
|
||||
}
|
||||
```
|
||||
|
||||
Then it is used as follows
|
||||
The chain of responsibility in action.
|
||||
|
||||
```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"
|
||||
king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
|
||||
king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner"));
|
||||
king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));
|
||||
```
|
||||
|
||||
The console output.
|
||||
|
||||
```
|
||||
Orc commander handling request "defend castle"
|
||||
Orc officer handling request "torture prisoner"
|
||||
Orc soldier handling request "collect tax"
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
@ -157,7 +166,7 @@ Use Chain of Responsibility when
|
||||
* You want to issue a request to one of several objects without specifying the receiver explicitly.
|
||||
* The set of objects that can handle a request should be specified dynamically.
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [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)
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
@ -31,7 +31,7 @@
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>chain</artifactId>
|
||||
<artifactId>chain-of-responsibility</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
---
|
||||
layout: pattern
|
||||
title: Command
|
||||
folder: command
|
||||
@ -19,7 +19,7 @@ Encapsulate a request as an object, thereby letting you parameterize clients wit
|
||||
requests, queue or log requests, and support undoable operations.
|
||||
|
||||
## Explanation
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> There is a wizard casting spells on a goblin. The spells are executed on the goblin one by one.
|
||||
> The first spell shrinks the goblin and the second makes him invisible. Then the wizard reverses
|
||||
@ -135,7 +135,7 @@ public class Goblin extends Target {
|
||||
}
|
||||
```
|
||||
|
||||
Finally we have the wizard in main function who casts spell
|
||||
Finally, we have the wizard in the main function casting spells.
|
||||
|
||||
```java
|
||||
public static void main(String[] args) {
|
||||
@ -202,32 +202,29 @@ Use the Command pattern when you want to:
|
||||
* Parameterize objects by an action to perform. You can express such parameterization in a
|
||||
procedural language with a callback function, that is, a function that's registered somewhere to be
|
||||
called at a later point. Commands are an object-oriented replacement for callbacks.
|
||||
* Specify, queue, and execute requests at different times. A Command object can have a lifetime
|
||||
* Specify, queue, and execute requests at different times. A Command object can have a life
|
||||
independent of the original request. If the receiver of a request can be represented in an address
|
||||
space-independent way, then you can transfer a command object for the request to a different process
|
||||
and fulfill the request there.
|
||||
* Support undo. The Command's execute operation can store state for reversing its effects in the
|
||||
command itself. The Command interface must have an added un-execute operation that reverses the
|
||||
effects of a previous call to execute. The executed commands are stored in a history list.
|
||||
Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling
|
||||
un-execute and execute, respectively.
|
||||
Unlimited-level undo and redo functionality is achieved by traversing this list backward and forward
|
||||
calling un-execute and execute, respectively.
|
||||
* Support logging changes so that they can be reapplied in case of a system crash. By augmenting the
|
||||
Command interface with load and store operations, you can keep a persistent log of changes.
|
||||
Recovering from a crash involves reloading logged commands from disk and re-executing them with
|
||||
Recovering from a crash involves reloading logged commands from the disk and re-executing them with
|
||||
the execute operation.
|
||||
* Structure a system around high-level operations build on primitive operations. Such a structure is
|
||||
common in information systems that support transactions. A transaction encapsulates a set of changes
|
||||
to data. The Command pattern offers a way to model transactions. Commands have a common interface,
|
||||
common in information systems that support transactions. A transaction encapsulates a set of data
|
||||
changes. The Command pattern offers a way to model transactions. Commands have a common interface,
|
||||
letting you invoke all transactions the same way. The pattern also makes it easy to extend the
|
||||
system with new transactions.
|
||||
* Keep a history of requests.
|
||||
* Implement callback functionality.
|
||||
* Implement the undo functionality.
|
||||
|
||||
## Typical Use Case
|
||||
|
||||
* To keep a history of requests
|
||||
* Implement callback functionality
|
||||
* Implement the undo functionality
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
|
||||
* [org.junit.runners.model.Statement](https://github.com/junit-team/junit4/blob/master/src/main/java/org/junit/runners/model/Statement.java)
|
||||
|
@ -26,7 +26,7 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* The Command pattern is a behavioral design pattern in which an object is used to encapsulate all
|
||||
* information needed to perform an action or trigger an event at a later time. This information
|
||||
* includes the method name, the object that owns the method and values for the method parameters.
|
||||
* includes the method name, the object that owns the method, and values for the method parameters.
|
||||
*
|
||||
* <p>Four terms always associated with the command pattern are command, receiver, invoker and
|
||||
* client. A command object (spell) knows about the receiver (target) and invokes a method of the
|
||||
|
@ -16,15 +16,15 @@ treat individual objects and compositions of objects uniformly.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Every sentence is composed of words which are in turn composed of characters. Each of these
|
||||
> objects is printable and they can have something printed before or after them like sentence always
|
||||
> ends with full stop and word always has space before it.
|
||||
> objects are printable and they can have something printed before or after them like sentence
|
||||
> always ends with full stop and word always has space before it.
|
||||
|
||||
In plain words
|
||||
|
||||
> Composite pattern lets clients treat the individual objects in a uniform manner.
|
||||
> Composite pattern lets clients uniformly treat the individual objects.
|
||||
|
||||
Wikipedia says
|
||||
|
||||
@ -154,10 +154,22 @@ public class Messenger {
|
||||
And then it can be used as:
|
||||
|
||||
```java
|
||||
var orcMessage = new Messenger().messageFromOrcs();
|
||||
orcMessage.print(); // Where there is a whip there is a way.
|
||||
var elfMessage = new Messenger().messageFromElves();
|
||||
elfMessage.print(); // Much wind pours from your mouth.
|
||||
var messenger = new Messenger();
|
||||
|
||||
LOGGER.info("Message from the orcs: ");
|
||||
messenger.messageFromOrcs().print();
|
||||
|
||||
LOGGER.info("Message from the elves: ");
|
||||
messenger.messageFromElves().print();
|
||||
```
|
||||
|
||||
The console output:
|
||||
|
||||
```
|
||||
Message from the orcs:
|
||||
Where there is a whip there is a way.
|
||||
Message from the elves:
|
||||
Much wind pours from your mouth.
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
@ -172,7 +184,7 @@ Use the Composite pattern when
|
||||
* You want clients to be able to ignore the difference between compositions of objects and
|
||||
individual objects. Clients will treat all objects in the composite structure uniformly.
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html)
|
||||
* [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
|
||||
|
@ -45,14 +45,13 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
var messenger = new Messenger();
|
||||
|
||||
LOGGER.info("Message from the orcs: ");
|
||||
messenger.messageFromOrcs().print();
|
||||
|
||||
var orcMessage = new Messenger().messageFromOrcs();
|
||||
orcMessage.print();
|
||||
|
||||
LOGGER.info("\nMessage from the elves: ");
|
||||
|
||||
var elfMessage = new Messenger().messageFromElves();
|
||||
elfMessage.print();
|
||||
LOGGER.info("Message from the elves: ");
|
||||
messenger.messageFromElves().print();
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,6 @@ public class Sentence extends LetterComposite {
|
||||
|
||||
@Override
|
||||
protected void printThisAfter() {
|
||||
System.out.print(".");
|
||||
System.out.print(".\n");
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ permalink: /patterns/decorator/
|
||||
categories: Structural
|
||||
language: en
|
||||
tags:
|
||||
- Gang Of Four
|
||||
- Gang of Four
|
||||
- Extensibility
|
||||
---
|
||||
|
||||
@ -21,9 +21,9 @@ alternative to subclassing for extending functionality.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> There is an angry troll living in the nearby hills. Usually it goes bare handed but sometimes it
|
||||
> There is an angry troll living in the nearby hills. Usually, it goes bare-handed but sometimes it
|
||||
> has a weapon. To arm the troll it's not necessary to create a new troll but to decorate it
|
||||
> dynamically with a suitable weapon.
|
||||
|
||||
@ -72,7 +72,7 @@ public class SimpleTroll implements Troll {
|
||||
}
|
||||
```
|
||||
|
||||
Next we want to add club for the troll. We can do it dynamically by using a decorator:
|
||||
Next, we want to add a club for the troll. We can do it dynamically by using a decorator:
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@ -106,23 +106,33 @@ Here's the troll in action:
|
||||
|
||||
```java
|
||||
// simple troll
|
||||
LOGGER.info("A simple looking troll approaches.");
|
||||
var troll = new SimpleTroll();
|
||||
troll.attack(); // The troll tries to grab you!
|
||||
troll.fleeBattle(); // The troll shrieks in horror and runs away!
|
||||
troll.attack();
|
||||
troll.fleeBattle();
|
||||
LOGGER.info("Simple troll power: {}.\n", troll.getAttackPower());
|
||||
|
||||
// change the behavior of the simple troll by adding a decorator
|
||||
LOGGER.info("A troll with huge club surprises you.");
|
||||
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!
|
||||
clubbedTroll.attack();
|
||||
clubbedTroll.fleeBattle();
|
||||
LOGGER.info("Clubbed troll power: {}.\n", clubbedTroll.getAttackPower());
|
||||
```
|
||||
|
||||
Program output:
|
||||
|
||||
```java
|
||||
A simple looking troll approaches.
|
||||
The troll tries to grab you!
|
||||
The troll shrieks in horror and runs away!
|
||||
The troll tries to grab you! The troll swings at you with a club!
|
||||
Simple troll power: 10.
|
||||
|
||||
A troll with huge club surprises you.
|
||||
The troll tries to grab you!
|
||||
The troll swings at you with a club!
|
||||
The troll shrieks in horror and runs away!
|
||||
Clubbed troll power: 20.
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
@ -140,11 +150,11 @@ affecting other objects.
|
||||
are possible and would produce an explosion of subclasses to support every combination. Or a class
|
||||
definition may be hidden or otherwise unavailable for subclassing.
|
||||
|
||||
## Tutorial
|
||||
## Tutorials
|
||||
|
||||
* [Decorator Pattern Tutorial](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example)
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [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)
|
||||
|
@ -50,13 +50,13 @@ public class App {
|
||||
var troll = new SimpleTroll();
|
||||
troll.attack();
|
||||
troll.fleeBattle();
|
||||
LOGGER.info("Simple troll power {}.\n", troll.getAttackPower());
|
||||
LOGGER.info("Simple troll power: {}.\n", troll.getAttackPower());
|
||||
|
||||
// change the behavior of the simple troll by adding a decorator
|
||||
LOGGER.info("A troll with huge club surprises you.");
|
||||
var clubbedTroll = new ClubbedTroll(troll);
|
||||
clubbedTroll.attack();
|
||||
clubbedTroll.fleeBattle();
|
||||
LOGGER.info("Clubbed troll power {}.\n", clubbedTroll.getAttackPower());
|
||||
LOGGER.info("Clubbed troll power: {}.\n", clubbedTroll.getAttackPower());
|
||||
}
|
||||
}
|
||||
|
326
domain-model/README.md
Normal file
326
domain-model/README.md
Normal file
@ -0,0 +1,326 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Domain Model
|
||||
folder: domain-model
|
||||
permalink: /patterns/domain-model/
|
||||
categories: Architectural
|
||||
language: en
|
||||
tags:
|
||||
- Domain
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Domain model pattern provides an object-oriented way of dealing with complicated logic. Instead of having one procedure that handles all business logic for a user action there are multiple objects and each of them handles a slice of domain logic that is relevant to it.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> Let's assume that we need to build an e-commerce web application. While analyzing requirements you will notice that there are few nouns you talk about repeatedly. It’s your Customer, and a Product the customer looks for. These two are your domain-specific classes and each of that classes will include some business logic specific to its domain.
|
||||
|
||||
In plain words
|
||||
|
||||
> The Domain Model is an object model of the domain that incorporates both behavior and data.
|
||||
|
||||
Programmatic Example
|
||||
|
||||
In the example of the e-commerce app, we need to deal with the domain logic of customers who want to buy products and return them if they want. We can use the domain model pattern and create classes `Customer` and `Product` where every single instance of that class incorporates both behavior and data and represents only one record in the underlying table.
|
||||
|
||||
Here is the `Product` domain class with fields `name`, `price`, `expirationDate` which is specific for each product, `productDao` for working with DB, `save` method for saving product and `getSalePrice` method which return price for this product with discount.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class Product {
|
||||
|
||||
private static final int DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE = 4;
|
||||
private static final double DISCOUNT_RATE = 0.2;
|
||||
|
||||
@NonNull private final ProductDao productDao;
|
||||
@NonNull private String name;
|
||||
@NonNull private Money price;
|
||||
@NonNull private LocalDate expirationDate;
|
||||
|
||||
/**
|
||||
* Save product or update if product already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Product> product = productDao.findByName(name);
|
||||
if (product.isPresent()) {
|
||||
productDao.update(this);
|
||||
} else {
|
||||
productDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate sale price of product with discount.
|
||||
*/
|
||||
public Money getSalePrice() {
|
||||
return price.minus(calculateDiscount());
|
||||
}
|
||||
|
||||
private Money calculateDiscount() {
|
||||
if (ChronoUnit.DAYS.between(LocalDate.now(), expirationDate)
|
||||
< DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE) {
|
||||
|
||||
return price.multipliedBy(DISCOUNT_RATE, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
return Money.zero(USD);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here is the `Customer` domain class with fields `name`, `money` which is specific for each customer, `customerDao` for working with DB, `save` for saving customer, `buyProduct` which add a product to purchases and withdraw money, `returnProduct` which remove product from purchases and return money, `showPurchases` and `showBalance` methods for printing customer's purchases and money balance.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class Customer {
|
||||
|
||||
@NonNull private final CustomerDao customerDao;
|
||||
@Builder.Default private List<Product> purchases = new ArrayList<>();
|
||||
@NonNull private String name;
|
||||
@NonNull private Money money;
|
||||
|
||||
/**
|
||||
* Save customer or update if customer already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Customer> customer = customerDao.findByName(name);
|
||||
if (customer.isPresent()) {
|
||||
customerDao.update(this);
|
||||
} else {
|
||||
customerDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product to purchases, save to db and withdraw money.
|
||||
*
|
||||
* @param product to buy.
|
||||
*/
|
||||
public void buyProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to buy %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
try {
|
||||
withdraw(product.getSalePrice());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
customerDao.addProduct(product, this);
|
||||
purchases.add(product);
|
||||
LOGGER.info(String.format("%s bought %s!", name, product.getName()));
|
||||
} catch (SQLException exception) {
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.error(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove product from purchases, delete from db and return money.
|
||||
*
|
||||
* @param product to return.
|
||||
*/
|
||||
public void returnProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to return %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
if (purchases.contains(product)) {
|
||||
try {
|
||||
customerDao.deleteProduct(product, this);
|
||||
purchases.remove(product);
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.info(String.format("%s returned %s!", name, product.getName()));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
LOGGER.error(String.format("%s didn't buy %s...", name, product.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's purchases.
|
||||
*/
|
||||
public void showPurchases() {
|
||||
Optional<String> purchasesToShow =
|
||||
purchases.stream()
|
||||
.map(p -> p.getName() + " - $" + p.getSalePrice().getAmount())
|
||||
.reduce((p1, p2) -> p1 + ", " + p2);
|
||||
|
||||
if (purchasesToShow.isPresent()) {
|
||||
LOGGER.info(name + " bought: " + purchasesToShow.get());
|
||||
} else {
|
||||
LOGGER.info(name + " didn't bought anything");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's money balance.
|
||||
*/
|
||||
public void showBalance() {
|
||||
LOGGER.info(name + " balance: " + money);
|
||||
}
|
||||
|
||||
private void withdraw(Money amount) throws IllegalArgumentException {
|
||||
if (money.compareTo(amount) < 0) {
|
||||
throw new IllegalArgumentException("Not enough money!");
|
||||
}
|
||||
money = money.minus(amount);
|
||||
}
|
||||
|
||||
private void receiveMoney(Money amount) {
|
||||
money = money.plus(amount);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the class `App`, we create a new instance of class Customer which represents customer Tom and handle data and actions of that customer and creating three products that Tom wants to buy.
|
||||
|
||||
|
||||
```java
|
||||
// Create data source and create the customers, products and purchases tables
|
||||
final var dataSource = createDataSource();
|
||||
deleteSchema(dataSource);
|
||||
createSchema(dataSource);
|
||||
|
||||
// create customer
|
||||
var customerDao = new CustomerDaoImpl(dataSource);
|
||||
|
||||
var tom =
|
||||
Customer.builder()
|
||||
.name("Tom")
|
||||
.money(Money.of(USD, 30))
|
||||
.customerDao(customerDao)
|
||||
.build();
|
||||
|
||||
tom.save();
|
||||
|
||||
// create products
|
||||
var productDao = new ProductDaoImpl(dataSource);
|
||||
|
||||
var eggs =
|
||||
Product.builder()
|
||||
.name("Eggs")
|
||||
.price(Money.of(USD, 10.0))
|
||||
.expirationDate(LocalDate.now().plusDays(7))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var butter =
|
||||
Product.builder()
|
||||
.name("Butter")
|
||||
.price(Money.of(USD, 20.00))
|
||||
.expirationDate(LocalDate.now().plusDays(9))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var cheese =
|
||||
Product.builder()
|
||||
.name("Cheese")
|
||||
.price(Money.of(USD, 25.0))
|
||||
.expirationDate(LocalDate.now().plusDays(2))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
eggs.save();
|
||||
butter.save();
|
||||
cheese.save();
|
||||
|
||||
// show money balance of customer after each purchase
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
|
||||
// buy eggs
|
||||
tom.buyProduct(eggs);
|
||||
tom.showBalance();
|
||||
|
||||
// buy butter
|
||||
tom.buyProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// trying to buy cheese, but receive a refusal
|
||||
// because he didn't have enough money
|
||||
tom.buyProduct(cheese);
|
||||
tom.showBalance();
|
||||
|
||||
// return butter and get money back
|
||||
tom.returnProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// Tom can buy cheese now because he has enough money
|
||||
// and there is a discount on cheese because it expires in 2 days
|
||||
tom.buyProduct(cheese);
|
||||
|
||||
tom.save();
|
||||
|
||||
// show money balance and purchases after shopping
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
```
|
||||
|
||||
The program output:
|
||||
|
||||
```java
|
||||
17:52:28.690 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 30.00
|
||||
17:52:28.695 [main] INFO com.iluwatar.domainmodel.Customer - Tom didn't bought anything
|
||||
17:52:28.699 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Eggs($10.00)...
|
||||
17:52:28.705 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought Eggs!
|
||||
17:52:28.705 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 20.00
|
||||
17:52:28.705 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Butter($20.00)...
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought Butter!
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 0.00
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Cheese($20.00)...
|
||||
17:52:28.712 [main] ERROR com.iluwatar.domainmodel.Customer - Not enough money!
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 0.00
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to return Butter($20.00)...
|
||||
17:52:28.721 [main] INFO com.iluwatar.domainmodel.Customer - Tom returned Butter!
|
||||
17:52:28.721 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 20.00
|
||||
17:52:28.721 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Cheese($20.00)...
|
||||
17:52:28.726 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought Cheese!
|
||||
17:52:28.737 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 0.00
|
||||
17:52:28.738 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought: Eggs - $10.00, Cheese - $20.00
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Use a Domain model pattern when your domain logic is complex and that complexity can rapidly grow because this pattern handles increasing complexity very well. Otherwise, it's a more complex solution for organizing domain logic, so shouldn't use Domain Model pattern for systems with simple domain logic, because the cost of understanding it and complexity of data source exceeds the benefit of this pattern.
|
||||
|
||||
## Related patterns
|
||||
|
||||
- [Transaction Script](https://java-design-patterns.com/patterns/transaction-script/)
|
||||
|
||||
- [Table Module](https://java-design-patterns.com/patterns/table-module/)
|
||||
|
||||
- [Service Layer](https://java-design-patterns.com/patterns/service-layer/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Domain Model Pattern](https://martinfowler.com/eaaCatalog/domainModel.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=18acc13ba60d66690009505577c45c04)
|
||||
* [Architecture patterns: domain model and friends](https://inviqa.com/blog/architecture-patterns-domain-model-and-friends)
|
BIN
domain-model/etc/domain-model.urm.png
Normal file
BIN
domain-model/etc/domain-model.urm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 314 KiB |
87
domain-model/etc/domain-model.urm.puml
Normal file
87
domain-model/etc/domain-model.urm.puml
Normal file
@ -0,0 +1,87 @@
|
||||
@startuml
|
||||
package com.iluwatar.domainmodel {
|
||||
class App {
|
||||
+ CREATE_SCHEMA_SQL : String {static}
|
||||
+ DELETE_SCHEMA_SQL : String {static}
|
||||
+ H2_DB_URL : String {static}
|
||||
+ App()
|
||||
- createDataSource() : DataSource {static}
|
||||
- createSchema(dataSource : DataSource) {static}
|
||||
- deleteSchema(dataSource : DataSource) {static}
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
class Customer {
|
||||
- customerDao : CustomerDao
|
||||
- money : Money
|
||||
- name : String
|
||||
- purchases : List<Product>
|
||||
~ Customer(customerDao : CustomerDao, purchases : List<Product>, name : String, money : Money)
|
||||
+ builder() : CustomerBuilder {static}
|
||||
+ buyProduct(product : Product)
|
||||
+ getCustomerDao() : CustomerDao
|
||||
+ getMoney() : Money
|
||||
+ getName() : String
|
||||
+ getPurchases() : List<Product>
|
||||
- receiveMoney(amount : Money)
|
||||
+ returnProduct(product : Product)
|
||||
+ save()
|
||||
+ setMoney(money : Money)
|
||||
+ setName(name : String)
|
||||
+ setPurchases(purchases : List<Product>)
|
||||
+ showBalance()
|
||||
+ showPurchases()
|
||||
- withdraw(amount : Money)
|
||||
}
|
||||
interface CustomerDao {
|
||||
+ addProduct(Product, Customer) {abstract}
|
||||
+ deleteProduct(Product, Customer) {abstract}
|
||||
+ findByName(String) : Optional<Customer> {abstract}
|
||||
+ save(Customer) {abstract}
|
||||
+ update(Customer) {abstract}
|
||||
}
|
||||
class CustomerDaoImpl {
|
||||
- dataSource : DataSource
|
||||
+ CustomerDaoImpl(userDataSource : DataSource)
|
||||
+ addProduct(product : Product, customer : Customer)
|
||||
+ deleteProduct(product : Product, customer : Customer)
|
||||
+ findByName(name : String) : Optional<Customer>
|
||||
+ save(customer : Customer)
|
||||
+ update(customer : Customer)
|
||||
}
|
||||
class Product {
|
||||
- expirationDate : LocalDate
|
||||
- name : String
|
||||
- price : Money
|
||||
- productDao : ProductDao
|
||||
+ Product(productDao : ProductDao, name : String, price : Money, expirationDate : LocalDate)
|
||||
+ builder() : ProductBuilder {static}
|
||||
- calculateDiscount() : Money
|
||||
+ getExpirationDate() : LocalDate
|
||||
+ getName() : String
|
||||
+ getPrice() : Money
|
||||
+ getProductDao() : ProductDao
|
||||
+ getSalePrice() : Money
|
||||
+ save()
|
||||
+ setExpirationDate(expirationDate : LocalDate)
|
||||
+ setName(name : String)
|
||||
+ setPrice(price : Money)
|
||||
}
|
||||
interface ProductDao {
|
||||
+ findByName(String) : Optional<Product> {abstract}
|
||||
+ save(Product) {abstract}
|
||||
+ update(Product) {abstract}
|
||||
}
|
||||
class ProductDaoImpl {
|
||||
- dataSource : DataSource
|
||||
+ ProductDaoImpl(userDataSource : DataSource)
|
||||
+ findByName(name : String) : Optional<Product>
|
||||
+ save(product : Product)
|
||||
+ update(product : Product)
|
||||
}
|
||||
}
|
||||
Product --> ProductDao
|
||||
Customer --> CustomerDao
|
||||
Customer --> Product
|
||||
CustomerDaoImpl ..|> CustomerDao
|
||||
ProductDaoImpl ..|> ProductDao
|
||||
@enduml
|
78
domain-model/pom.xml
Normal file
78
domain-model/pom.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
The MIT License
|
||||
Copyright © 2014-2021 Ilkka Seppälä
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>domain-model</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.joda</groupId>
|
||||
<artifactId>joda-money</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.domainmodel.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
173
domain-model/src/main/java/com/iluwatar/domainmodel/App.java
Normal file
173
domain-model/src/main/java/com/iluwatar/domainmodel/App.java
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
import org.joda.money.Money;
|
||||
|
||||
|
||||
/**
|
||||
* Domain Model pattern is a more complex solution for organizing domain logic than Transaction
|
||||
* Script and Table Module. It provides an object-oriented way of dealing with complicated logic.
|
||||
* Instead of having one procedure that handles all business logic for a user action like
|
||||
* Transaction Script there are multiple objects and each of them handles a slice of domain logic
|
||||
* that is relevant to it. The significant difference between Domain Model and Table Module pattern
|
||||
* is that in Table Module a single class encapsulates all the domain logic for all records stored
|
||||
* in table when in Domain Model every single class represents only one record in underlying table.
|
||||
*
|
||||
* <p>In this example, we will use the Domain Model pattern to implement buying of products
|
||||
* by customers in a Shop. The main method will create a customer and a few products.
|
||||
* Customer will do a few purchases, try to buy product which are too expensive for him,
|
||||
* return product which he bought to return money.</p>
|
||||
*/
|
||||
public class App {
|
||||
|
||||
public static final String H2_DB_URL = "jdbc:h2:~/test";
|
||||
|
||||
public static final String CREATE_SCHEMA_SQL =
|
||||
"CREATE TABLE CUSTOMERS (name varchar primary key, money decimal);"
|
||||
+ "CREATE TABLE PRODUCTS (name varchar primary key, price decimal, expiration_date date);"
|
||||
+ "CREATE TABLE PURCHASES ("
|
||||
+ "product_name varchar references PRODUCTS(name),"
|
||||
+ "customer_name varchar references CUSTOMERS(name));";
|
||||
|
||||
public static final String DELETE_SCHEMA_SQL =
|
||||
"DROP TABLE CUSTOMERS IF EXISTS;"
|
||||
+ "DROP TABLE PURCHASES IF EXISTS;"
|
||||
+ "DROP TABLE PRODUCTS IF EXISTS;";
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line arguments
|
||||
* @throws Exception if any error occurs
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// Create data source and create the customers, products and purchases tables
|
||||
final var dataSource = createDataSource();
|
||||
deleteSchema(dataSource);
|
||||
createSchema(dataSource);
|
||||
|
||||
// create customer
|
||||
var customerDao = new CustomerDaoImpl(dataSource);
|
||||
|
||||
var tom =
|
||||
Customer.builder()
|
||||
.name("Tom")
|
||||
.money(Money.of(USD, 30))
|
||||
.customerDao(customerDao)
|
||||
.build();
|
||||
|
||||
tom.save();
|
||||
|
||||
// create products
|
||||
var productDao = new ProductDaoImpl(dataSource);
|
||||
|
||||
var eggs =
|
||||
Product.builder()
|
||||
.name("Eggs")
|
||||
.price(Money.of(USD, 10.0))
|
||||
.expirationDate(LocalDate.now().plusDays(7))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var butter =
|
||||
Product.builder()
|
||||
.name("Butter")
|
||||
.price(Money.of(USD, 20.00))
|
||||
.expirationDate(LocalDate.now().plusDays(9))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var cheese =
|
||||
Product.builder()
|
||||
.name("Cheese")
|
||||
.price(Money.of(USD, 25.0))
|
||||
.expirationDate(LocalDate.now().plusDays(2))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
eggs.save();
|
||||
butter.save();
|
||||
cheese.save();
|
||||
|
||||
// show money balance of customer after each purchase
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
|
||||
// buy eggs
|
||||
tom.buyProduct(eggs);
|
||||
tom.showBalance();
|
||||
|
||||
// buy butter
|
||||
tom.buyProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// trying to buy cheese, but receive a refusal
|
||||
// because he didn't have enough money
|
||||
tom.buyProduct(cheese);
|
||||
tom.showBalance();
|
||||
|
||||
// return butter and get money back
|
||||
tom.returnProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// Tom can buy cheese now because he has enough money
|
||||
// and there is a discount on cheese because it expires in 2 days
|
||||
tom.buyProduct(cheese);
|
||||
|
||||
tom.save();
|
||||
|
||||
// show money balance and purchases after shopping
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
}
|
||||
|
||||
private static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setUrl(H2_DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private static void deleteSchema(DataSource dataSource) throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(DELETE_SCHEMA_SQL);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSchema(DataSource dataSource) throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(CREATE_SCHEMA_SQL);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joda.money.Money;
|
||||
|
||||
/**
|
||||
* This class organizes domain logic of customer.
|
||||
* A single instance of this class
|
||||
* contains both the data and behavior of a single customer.
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class Customer {
|
||||
|
||||
@NonNull private final CustomerDao customerDao;
|
||||
@Builder.Default private List<Product> purchases = new ArrayList<>();
|
||||
@NonNull private String name;
|
||||
@NonNull private Money money;
|
||||
|
||||
/**
|
||||
* Save customer or update if customer already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Customer> customer = customerDao.findByName(name);
|
||||
if (customer.isPresent()) {
|
||||
customerDao.update(this);
|
||||
} else {
|
||||
customerDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product to purchases, save to db and withdraw money.
|
||||
*
|
||||
* @param product to buy.
|
||||
*/
|
||||
public void buyProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to buy %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
try {
|
||||
withdraw(product.getSalePrice());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
customerDao.addProduct(product, this);
|
||||
purchases.add(product);
|
||||
LOGGER.info(String.format("%s bought %s!", name, product.getName()));
|
||||
} catch (SQLException exception) {
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.error(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove product from purchases, delete from db and return money.
|
||||
*
|
||||
* @param product to return.
|
||||
*/
|
||||
public void returnProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to return %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
if (purchases.contains(product)) {
|
||||
try {
|
||||
customerDao.deleteProduct(product, this);
|
||||
purchases.remove(product);
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.info(String.format("%s returned %s!", name, product.getName()));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
LOGGER.error(String.format("%s didn't buy %s...", name, product.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's purchases.
|
||||
*/
|
||||
public void showPurchases() {
|
||||
Optional<String> purchasesToShow =
|
||||
purchases.stream()
|
||||
.map(p -> p.getName() + " - $" + p.getSalePrice().getAmount())
|
||||
.reduce((p1, p2) -> p1 + ", " + p2);
|
||||
|
||||
if (purchasesToShow.isPresent()) {
|
||||
LOGGER.info(name + " bought: " + purchasesToShow.get());
|
||||
} else {
|
||||
LOGGER.info(name + " didn't bought anything");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's money balance.
|
||||
*/
|
||||
public void showBalance() {
|
||||
LOGGER.info(name + " balance: " + money);
|
||||
}
|
||||
|
||||
private void withdraw(Money amount) throws IllegalArgumentException {
|
||||
if (money.compareTo(amount) < 0) {
|
||||
throw new IllegalArgumentException("Not enough money!");
|
||||
}
|
||||
money = money.minus(amount);
|
||||
}
|
||||
|
||||
private void receiveMoney(Money amount) {
|
||||
money = money.plus(amount);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CustomerDao {
|
||||
|
||||
Optional<Customer> findByName(String name) throws SQLException;
|
||||
|
||||
void update(Customer customer) throws SQLException;
|
||||
|
||||
void save(Customer customer) throws SQLException;
|
||||
|
||||
void addProduct(Product product, Customer customer) throws SQLException;
|
||||
|
||||
void deleteProduct(Product product, Customer customer) throws SQLException;
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.joda.money.Money;
|
||||
|
||||
public class CustomerDaoImpl implements CustomerDao {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public CustomerDaoImpl(final DataSource userDataSource) {
|
||||
this.dataSource = userDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Customer> findByName(String name) throws SQLException {
|
||||
var sql = "select * from CUSTOMERS where name = ?;";
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, name);
|
||||
|
||||
ResultSet rs = preparedStatement.executeQuery();
|
||||
|
||||
if (rs.next()) {
|
||||
return Optional.of(
|
||||
Customer.builder()
|
||||
.name(rs.getString("name"))
|
||||
.money(Money.of(USD, rs.getBigDecimal("money")))
|
||||
.customerDao(this)
|
||||
.build());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Customer customer) throws SQLException {
|
||||
var sql = "update CUSTOMERS set money = ? where name = ?;";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setBigDecimal(1, customer.getMoney().getAmount());
|
||||
preparedStatement.setString(2, customer.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Customer customer) throws SQLException {
|
||||
var sql = "insert into CUSTOMERS (name, money) values (?, ?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, customer.getName());
|
||||
preparedStatement.setBigDecimal(2, customer.getMoney().getAmount());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProduct(Product product, Customer customer) throws SQLException {
|
||||
var sql = "insert into PURCHASES (product_name, customer_name) values (?,?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, product.getName());
|
||||
preparedStatement.setString(2, customer.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProduct(Product product, Customer customer) throws SQLException {
|
||||
var sql = "delete from PURCHASES where product_name = ? and customer_name = ?";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, product.getName());
|
||||
preparedStatement.setString(2, customer.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joda.money.Money;
|
||||
|
||||
/**
|
||||
* This class organizes domain logic of product.
|
||||
* A single instance of this class
|
||||
* contains both the data and behavior of a single product.
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class Product {
|
||||
|
||||
private static final int DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE = 4;
|
||||
private static final double DISCOUNT_RATE = 0.2;
|
||||
|
||||
@NonNull private final ProductDao productDao;
|
||||
@NonNull private String name;
|
||||
@NonNull private Money price;
|
||||
@NonNull private LocalDate expirationDate;
|
||||
|
||||
/**
|
||||
* Save product or update if product already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Product> product = productDao.findByName(name);
|
||||
if (product.isPresent()) {
|
||||
productDao.update(this);
|
||||
} else {
|
||||
productDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate sale price of product with discount.
|
||||
*/
|
||||
public Money getSalePrice() {
|
||||
return price.minus(calculateDiscount());
|
||||
}
|
||||
|
||||
private Money calculateDiscount() {
|
||||
if (ChronoUnit.DAYS.between(LocalDate.now(), expirationDate)
|
||||
< DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE) {
|
||||
|
||||
return price.multipliedBy(DISCOUNT_RATE, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
return Money.zero(USD);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProductDao {
|
||||
|
||||
Optional<Product> findByName(String name) throws SQLException;
|
||||
|
||||
void save(Product product) throws SQLException;
|
||||
|
||||
void update(Product product) throws SQLException;
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.joda.money.Money;
|
||||
|
||||
|
||||
public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public ProductDaoImpl(final DataSource userDataSource) {
|
||||
this.dataSource = userDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Product> findByName(String name) throws SQLException {
|
||||
var sql = "select * from PRODUCTS where name = ?;";
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, name);
|
||||
|
||||
ResultSet rs = preparedStatement.executeQuery();
|
||||
|
||||
if (rs.next()) {
|
||||
return Optional.of(
|
||||
Product.builder()
|
||||
.name(rs.getString("name"))
|
||||
.price(Money.of(USD, rs.getBigDecimal("price")))
|
||||
.expirationDate(rs.getDate("expiration_date").toLocalDate())
|
||||
.productDao(this)
|
||||
.build());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Product product) throws SQLException {
|
||||
var sql = "insert into PRODUCTS (name, price, expiration_date) values (?, ?, ?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, product.getName());
|
||||
preparedStatement.setBigDecimal(2, product.getPrice().getAmount());
|
||||
preparedStatement.setDate(3, Date.valueOf(product.getExpirationDate()));
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Product product) throws SQLException {
|
||||
var sql = "update PRODUCTS set price = ?, expiration_date = ? where name = ?;";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setBigDecimal(1, product.getPrice().getAmount());
|
||||
preparedStatement.setDate(2, Date.valueOf(product.getExpirationDate()));
|
||||
preparedStatement.setString(3, product.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
/** Tests that Domain Model example runs without errors. */
|
||||
final class AppTest {
|
||||
|
||||
@Test
|
||||
void shouldExecuteApplicationWithoutException() {
|
||||
assertDoesNotThrow(() -> App.main(new String[] {}));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CustomerDaoImplTest {
|
||||
|
||||
public static final String INSERT_CUSTOMER_SQL = "insert into CUSTOMERS values('customer', 100)";
|
||||
public static final String SELECT_CUSTOMERS_SQL = "select name, money from CUSTOMERS";
|
||||
public static final String INSERT_PURCHASES_SQL =
|
||||
"insert into PURCHASES values('product', 'customer')";
|
||||
public static final String SELECT_PURCHASES_SQL =
|
||||
"select product_name, customer_name from PURCHASES";
|
||||
|
||||
private DataSource dataSource;
|
||||
private Product product;
|
||||
private Customer customer;
|
||||
private CustomerDao customerDao;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws SQLException {
|
||||
// create db schema
|
||||
dataSource = TestUtils.createDataSource();
|
||||
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
TestUtils.createSchema(dataSource);
|
||||
|
||||
// setup objects
|
||||
customerDao = new CustomerDaoImpl(dataSource);
|
||||
|
||||
customer = Customer.builder().name("customer").money(Money.of(CurrencyUnit.USD,100.0)).customerDao(customerDao).build();
|
||||
|
||||
product =
|
||||
Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.parse("2021-06-27"))
|
||||
.productDao(new ProductDaoImpl(dataSource))
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws SQLException {
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindCustomerByName() throws SQLException {
|
||||
var customer = customerDao.findByName("customer");
|
||||
|
||||
assertTrue(customer.isEmpty());
|
||||
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
|
||||
customer = customerDao.findByName("customer");
|
||||
|
||||
assertTrue(customer.isPresent());
|
||||
assertEquals("customer", customer.get().getName());
|
||||
assertEquals(Money.of(USD, 100), customer.get().getMoney());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveCustomer() throws SQLException {
|
||||
customerDao.save(customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_CUSTOMERS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(customer.getName(), rs.getString("name"));
|
||||
assertEquals(customer.getMoney(), Money.of(USD, rs.getBigDecimal("money")));
|
||||
}
|
||||
|
||||
assertThrows(SQLException.class, () -> customerDao.save(customer));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUpdateCustomer() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
|
||||
customer.setMoney(Money.of(CurrencyUnit.USD, 99));
|
||||
|
||||
customerDao.update(customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_CUSTOMERS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(customer.getName(), rs.getString("name"));
|
||||
assertEquals(customer.getMoney(), Money.of(USD, rs.getBigDecimal("money")));
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProductToPurchases() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
TestUtils.executeSQL(ProductDaoImplTest.INSERT_PRODUCT_SQL, dataSource);
|
||||
|
||||
customerDao.addProduct(product, customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PURCHASES_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(product.getName(), rs.getString("product_name"));
|
||||
assertEquals(customer.getName(), rs.getString("customer_name"));
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeleteProductFromPurchases() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
TestUtils.executeSQL(ProductDaoImplTest.INSERT_PRODUCT_SQL, dataSource);
|
||||
TestUtils.executeSQL(INSERT_PURCHASES_SQL, dataSource);
|
||||
|
||||
customerDao.deleteProduct(product, customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PURCHASES_SQL)) {
|
||||
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class CustomerTest {
|
||||
|
||||
private CustomerDao customerDao;
|
||||
private Customer customer;
|
||||
private Product product;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
customerDao = mock(CustomerDao.class);
|
||||
|
||||
customer = Customer.builder()
|
||||
.name("customer")
|
||||
.money(Money.of(CurrencyUnit.USD, 100.0))
|
||||
.customerDao(customerDao)
|
||||
.build();
|
||||
|
||||
product = Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.now().plusDays(10))
|
||||
.productDao(mock(ProductDao.class))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveCustomer() throws SQLException {
|
||||
when(customerDao.findByName("customer")).thenReturn(Optional.empty());
|
||||
|
||||
customer.save();
|
||||
|
||||
verify(customerDao, times(1)).save(customer);
|
||||
|
||||
when(customerDao.findByName("customer")).thenReturn(Optional.of(customer));
|
||||
|
||||
customer.save();
|
||||
|
||||
verify(customerDao, times(1)).update(customer);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProductToPurchases() {
|
||||
product.setPrice(Money.of(USD, 200.0));
|
||||
|
||||
customer.buyProduct(product);
|
||||
|
||||
assertEquals(customer.getPurchases(), new ArrayList<>());
|
||||
assertEquals(customer.getMoney(), Money.of(USD,100));
|
||||
|
||||
product.setPrice(Money.of(USD, 100.0));
|
||||
|
||||
customer.buyProduct(product);
|
||||
|
||||
assertEquals(new ArrayList<>(Arrays.asList(product)), customer.getPurchases());
|
||||
assertEquals(Money.zero(USD), customer.getMoney());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRemoveProductFromPurchases() {
|
||||
customer.setPurchases(new ArrayList<>(Arrays.asList(product)));
|
||||
|
||||
customer.returnProduct(product);
|
||||
|
||||
assertEquals(new ArrayList<>(), customer.getPurchases());
|
||||
assertEquals(Money.of(USD, 200), customer.getMoney());
|
||||
|
||||
customer.returnProduct(product);
|
||||
|
||||
assertEquals(new ArrayList<>(), customer.getPurchases());
|
||||
assertEquals(Money.of(USD, 200), customer.getMoney());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ProductDaoImplTest {
|
||||
|
||||
public static final String INSERT_PRODUCT_SQL =
|
||||
"insert into PRODUCTS values('product', 100, DATE '2021-06-27')";
|
||||
public static final String SELECT_PRODUCTS_SQL =
|
||||
"select name, price, expiration_date from PRODUCTS";
|
||||
|
||||
private DataSource dataSource;
|
||||
private ProductDao productDao;
|
||||
private Product product;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws SQLException {
|
||||
// create schema
|
||||
dataSource = TestUtils.createDataSource();
|
||||
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
TestUtils.createSchema(dataSource);
|
||||
|
||||
// setup objects
|
||||
productDao = new ProductDaoImpl(dataSource);
|
||||
|
||||
product =
|
||||
Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.parse("2021-06-27"))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws SQLException {
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindProductByName() throws SQLException {
|
||||
var product = productDao.findByName("product");
|
||||
|
||||
assertTrue(product.isEmpty());
|
||||
|
||||
TestUtils.executeSQL(INSERT_PRODUCT_SQL, dataSource);
|
||||
|
||||
product = productDao.findByName("product");
|
||||
|
||||
assertTrue(product.isPresent());
|
||||
assertEquals("product", product.get().getName());
|
||||
assertEquals(Money.of(USD, 100), product.get().getPrice());
|
||||
assertEquals(LocalDate.parse("2021-06-27"), product.get().getExpirationDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveProduct() throws SQLException {
|
||||
|
||||
productDao.save(product);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PRODUCTS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(product.getName(), rs.getString("name"));
|
||||
assertEquals(product.getPrice(), Money.of(USD, rs.getBigDecimal("price")));
|
||||
assertEquals(product.getExpirationDate(), rs.getDate("expiration_date").toLocalDate());
|
||||
}
|
||||
|
||||
assertThrows(SQLException.class, () -> productDao.save(product));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUpdateProduct() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_PRODUCT_SQL, dataSource);
|
||||
|
||||
product.setPrice(Money.of(USD, 99.0));
|
||||
|
||||
productDao.update(product);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PRODUCTS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(product.getName(), rs.getString("name"));
|
||||
assertEquals(product.getPrice(), Money.of(USD, rs.getBigDecimal("price")));
|
||||
assertEquals(product.getExpirationDate(), rs.getDate("expiration_date").toLocalDate());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class ProductTest {
|
||||
|
||||
private ProductDao productDao;
|
||||
private Product product;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
productDao = mock(ProductDaoImpl.class);
|
||||
|
||||
product = Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.now().plusDays(10))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveProduct() throws SQLException {
|
||||
when(productDao.findByName("product")).thenReturn(Optional.empty());
|
||||
|
||||
product.save();
|
||||
|
||||
verify(productDao, times(1)).save(product);
|
||||
|
||||
when(productDao.findByName("product")).thenReturn(Optional.of(product));
|
||||
|
||||
product.save();
|
||||
|
||||
verify(productDao, times(1)).update(product);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGetSalePriceOfProduct() {
|
||||
assertEquals(Money.of(USD, 100), product.getSalePrice());
|
||||
|
||||
product.setExpirationDate(LocalDate.now().plusDays(2));
|
||||
|
||||
assertEquals(Money.of(USD, 80), product.getSalePrice());
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static void executeSQL( String sql, DataSource dataSource) throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.executeUpdate(sql);
|
||||
}
|
||||
}
|
||||
|
||||
public static void createSchema(DataSource dataSource) throws SQLException {
|
||||
TestUtils.executeSQL(App.CREATE_SCHEMA_SQL, dataSource);
|
||||
}
|
||||
|
||||
public static void deleteSchema(DataSource dataSource) throws SQLException {
|
||||
TestUtils.executeSQL(App.DELETE_SCHEMA_SQL, dataSource);
|
||||
}
|
||||
|
||||
public static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setURL(App.H2_DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ interface that makes the subsystem easier to use.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you
|
||||
> believe because you are using a simple interface that goldmine provides on the outside, internally
|
||||
|
@ -7,7 +7,7 @@ categories: Creational
|
||||
language: en
|
||||
tags:
|
||||
- Extensibility
|
||||
- Gang Of Four
|
||||
- Gang of Four
|
||||
---
|
||||
|
||||
## Also known as
|
||||
@ -21,7 +21,7 @@ Factory Method lets a class defer instantiation to subclasses.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons.
|
||||
> Depending on the customer at hand the right type of blacksmith is summoned.
|
||||
@ -40,7 +40,7 @@ Wikipedia says
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Taking our blacksmith example above. First of all we have a `Blacksmith` interface and some
|
||||
Taking our blacksmith example above. First of all, we have a `Blacksmith` interface and some
|
||||
implementations for it:
|
||||
|
||||
```java
|
||||
@ -65,15 +65,25 @@ When the customers come, the correct type of blacksmith is summoned and requeste
|
||||
manufactured:
|
||||
|
||||
```java
|
||||
var blacksmith = new ElfBlacksmith();
|
||||
blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
Blacksmith blacksmith = new OrcBlacksmith();
|
||||
Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
|
||||
blacksmith = new ElfBlacksmith();
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
```
|
||||
|
||||
Program output:
|
||||
```java
|
||||
// Elven spear
|
||||
// Elven axe
|
||||
```
|
||||
The orc blacksmith manufactured an orcish spear
|
||||
The orc blacksmith manufactured an orcish axe
|
||||
The elf blacksmith manufactured an elven spear
|
||||
The elf blacksmith manufactured an elven axe
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
@ -89,7 +99,7 @@ Use the Factory Method pattern when:
|
||||
* Classes delegate responsibility to one of several helper subclasses, and you want to localize the
|
||||
knowledge of which helper subclass is the delegate.
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [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-)
|
||||
|
@ -26,7 +26,7 @@ package com.iluwatar.factory.method;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* The Factory Method is a creational design pattern which uses factory methods to deal with the
|
||||
* The Factory Method is a creational design pattern that uses factory methods to deal with the
|
||||
* problem of creating objects without specifying the exact class of object that will be created.
|
||||
* This is done by creating objects via calling a factory method either specified in an interface
|
||||
* and implemented by child classes, or implemented in a base class and optionally overridden by
|
||||
@ -41,39 +41,22 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private final Blacksmith blacksmith;
|
||||
|
||||
/**
|
||||
* Creates an instance of <code>App</code> which will use <code>blacksmith</code> to manufacture
|
||||
* the weapons for war.
|
||||
* <code>App</code> is unaware which concrete implementation of {@link Blacksmith} it is using.
|
||||
* The decision of which blacksmith implementation to use may depend on configuration, or
|
||||
* the type of rival in war.
|
||||
* @param blacksmith a non-null implementation of blacksmith
|
||||
*/
|
||||
public App(Blacksmith blacksmith) {
|
||||
this.blacksmith = blacksmith;
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// Lets go to war with Orc weapons
|
||||
var app = new App(new OrcBlacksmith());
|
||||
app.manufactureWeapons();
|
||||
|
||||
// Lets go to war with Elf weapons
|
||||
app = new App(new ElfBlacksmith());
|
||||
app.manufactureWeapons();
|
||||
}
|
||||
|
||||
private void manufactureWeapons() {
|
||||
var weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info(weapon.toString());
|
||||
Blacksmith blacksmith = new OrcBlacksmith();
|
||||
Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
LOGGER.info(weapon.toString());
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
|
||||
blacksmith = new ElfBlacksmith();
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
|
||||
LOGGER.info("{} manufactured {}", blacksmith, weapon);
|
||||
}
|
||||
}
|
||||
|
@ -44,4 +44,8 @@ public class ElfBlacksmith implements Blacksmith {
|
||||
return ELFARSENAL.get(weaponType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "The elf blacksmith";
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,6 @@ public class ElfWeapon implements Weapon {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Elven " + weaponType;
|
||||
return "an elven " + weaponType;
|
||||
}
|
||||
}
|
||||
|
@ -43,4 +43,9 @@ public class OrcBlacksmith implements Blacksmith {
|
||||
public Weapon manufactureWeapon(WeaponType weaponType) {
|
||||
return ORCARSENAL.get(weaponType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "The orc blacksmith";
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,6 @@ public class OrcWeapon implements Weapon {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Orcish " + weaponType;
|
||||
return "an orcish " + weaponType;
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,17 @@ tags:
|
||||
|
||||
## Intent
|
||||
|
||||
Providing a static method encapsulated in a class called factory, in order to hide the
|
||||
implementation logic and makes client code focus on usage rather then initialization new objects.
|
||||
Providing a static method encapsulated in a class called the factory, to hide the implementation
|
||||
logic and make client code focus on usage rather than initializing new objects.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Lets say we have a web application connected to SQLServer, but now we want to switch to Oracle. To
|
||||
> do so without modifying existing source code, we need to implements Simple Factory pattern, in
|
||||
> which a static method can be invoked to create connection to a given database.
|
||||
> Imagine an alchemist who is about to manufacture coins. The alchemist must be able to create both
|
||||
> gold and copper coins and switching between them must be possible without modifying the existing
|
||||
> source code. The factory pattern makes it possible by providing a static construction method which
|
||||
> can be called with relevant parameters.
|
||||
|
||||
Wikipedia says
|
||||
|
||||
@ -34,16 +35,16 @@ Wikipedia says
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
We have an interface `Car` and two implementations `Ford` and `Ferrari`.
|
||||
We have an interface `Coin` and two implementations `GoldCoin` and `CopperCoin`.
|
||||
|
||||
```java
|
||||
public interface Car {
|
||||
public interface Coin {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
public class Ford implements Car {
|
||||
public class GoldCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is Ford.";
|
||||
static final String DESCRIPTION = "This is a gold coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
@ -51,9 +52,9 @@ public class Ford implements Car {
|
||||
}
|
||||
}
|
||||
|
||||
public class Ferrari implements Car {
|
||||
public class CopperCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is Ferrari.";
|
||||
static final String DESCRIPTION = "This is a copper coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
@ -62,51 +63,48 @@ public class Ferrari implements Car {
|
||||
}
|
||||
```
|
||||
|
||||
Enumeration above represents types of cars that we support (`Ford` and `Ferrari`).
|
||||
Enumeration above represents types of coins that we support (`GoldCoin` and `CopperCoin`).
|
||||
|
||||
```java
|
||||
public enum CarType {
|
||||
|
||||
FORD(Ford::new),
|
||||
FERRARI(Ferrari::new);
|
||||
|
||||
private final Supplier<Car> constructor;
|
||||
|
||||
CarType(Supplier<Car> constructor) {
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Supplier<Car> getConstructor() {
|
||||
return this.constructor;
|
||||
}
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CoinType {
|
||||
|
||||
COPPER(CopperCoin::new),
|
||||
GOLD(GoldCoin::new);
|
||||
|
||||
private final Supplier<Coin> constructor;
|
||||
}
|
||||
```
|
||||
Then we have the static method `getCar` to create car objects encapsulated in the factory class
|
||||
`CarsFactory`.
|
||||
|
||||
Then we have the static method `getCoin` to create coin objects encapsulated in the factory class
|
||||
`CoinFactory`.
|
||||
|
||||
```java
|
||||
public class CarsFactory {
|
||||
|
||||
public static Car getCar(CarType type) {
|
||||
public class CoinFactory {
|
||||
|
||||
public static Coin getCoin(CoinType type) {
|
||||
return type.getConstructor().get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now on the client code we can create different types of cars using the factory class.
|
||||
Now on the client code we can create different types of coins using the factory class.
|
||||
|
||||
```java
|
||||
var car1 = CarsFactory.getCar(CarType.FORD);
|
||||
var car2 = CarsFactory.getCar(CarType.FERRARI);
|
||||
LOGGER.info(car1.getDescription());
|
||||
LOGGER.info(car2.getDescription());
|
||||
LOGGER.info("The alchemist begins his work.");
|
||||
var coin1 = CoinFactory.getCoin(CoinType.COPPER);
|
||||
var coin2 = CoinFactory.getCoin(CoinType.GOLD);
|
||||
LOGGER.info(coin1.getDescription());
|
||||
LOGGER.info(coin2.getDescription());
|
||||
```
|
||||
|
||||
Program output:
|
||||
|
||||
```java
|
||||
This is Ford.
|
||||
This is Ferrari.
|
||||
The alchemist begins his work.
|
||||
This is a copper coin.
|
||||
This is a gold coin.
|
||||
```
|
||||
|
||||
## Class Diagram
|
||||
@ -115,7 +113,7 @@ This is Ferrari.
|
||||
|
||||
## Applicability
|
||||
|
||||
Use the Simple Factory pattern when you only care about the creation of a object, not how to create
|
||||
Use the factory pattern when you only care about the creation of a object, not how to create
|
||||
and manage it.
|
||||
|
||||
Pros
|
||||
@ -127,13 +125,13 @@ Cons
|
||||
|
||||
* The code becomes more complicated than it should be.
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
|
||||
* [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
|
||||
* [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
|
||||
* [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
|
||||
* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (Returns different singleton objects, depending on a protocol)
|
||||
* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (returns different singleton objects, depending on a protocol)
|
||||
* [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E))
|
||||
* [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) and other similar methods.
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 29 KiB |
@ -5,31 +5,32 @@ package com.iluwatar.factory {
|
||||
+ App()
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
interface Car {
|
||||
interface Coin {
|
||||
+ getDescription() : String {abstract}
|
||||
}
|
||||
class CarsFactory {
|
||||
+ CarsFactory()
|
||||
+ getCar(type : CarType) : Car {static}
|
||||
class CoinFactory {
|
||||
+ CoinFactory()
|
||||
+ getCoin(type : CoinType) : Coin {static}
|
||||
}
|
||||
~enum CarType {
|
||||
+ FERRARI {static}
|
||||
+ FORD {static}
|
||||
+ valueOf(name : String) : CarType {static}
|
||||
+ values() : CarType[] {static}
|
||||
enum CoinType {
|
||||
+ COPPER {static}
|
||||
+ GOLD {static}
|
||||
- constructor : Supplier<Coin>
|
||||
+ getConstructor() : Supplier<Coin>
|
||||
+ valueOf(name : String) : CoinType {static}
|
||||
+ values() : CoinType[] {static}
|
||||
}
|
||||
class Ferrari {
|
||||
class CopperCoin {
|
||||
~ DESCRIPTION : String {static}
|
||||
+ Ferrari()
|
||||
+ CopperCoin()
|
||||
+ getDescription() : String
|
||||
}
|
||||
class Ford {
|
||||
class GoldCoin {
|
||||
~ DESCRIPTION : String {static}
|
||||
+ Ford()
|
||||
+ GoldCoin()
|
||||
+ getDescription() : String
|
||||
}
|
||||
}
|
||||
CarType ..+ CarsFactory
|
||||
Ferrari ..|> Car
|
||||
Ford ..|> Car
|
||||
CopperCoin ..|> Coin
|
||||
GoldCoin ..|> Coin
|
||||
@enduml
|
@ -30,8 +30,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* create and return objects of varying classes, in order to hide the implementation logic
|
||||
* and makes client code focus on usage rather then objects initialization and management.
|
||||
*
|
||||
* <p>In this example the CarFactory is the factory class and it provides a static method to
|
||||
* create different cars.
|
||||
* <p>In this example an alchemist manufactures coins. CoinFactory is the factory class and it
|
||||
* provides a static method to create different types of coins.
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@ -41,9 +41,10 @@ public class App {
|
||||
* Program main entry point.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
var car1 = CarsFactory.getCar(CarType.FORD);
|
||||
var car2 = CarsFactory.getCar(CarType.FERRARI);
|
||||
LOGGER.info(car1.getDescription());
|
||||
LOGGER.info(car2.getDescription());
|
||||
LOGGER.info("The alchemist begins his work.");
|
||||
var coin1 = CoinFactory.getCoin(CoinType.COPPER);
|
||||
var coin2 = CoinFactory.getCoin(CoinType.GOLD);
|
||||
LOGGER.info(coin1.getDescription());
|
||||
LOGGER.info(coin2.getDescription());
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,9 @@
|
||||
package com.iluwatar.factory;
|
||||
|
||||
/**
|
||||
* Car interface.
|
||||
* Coin interface.
|
||||
*/
|
||||
public interface Car {
|
||||
public interface Coin {
|
||||
|
||||
String getDescription();
|
||||
|
@ -24,14 +24,14 @@
|
||||
package com.iluwatar.factory;
|
||||
|
||||
/**
|
||||
* Factory of cars.
|
||||
* Factory of coins.
|
||||
*/
|
||||
public class CarsFactory {
|
||||
public class CoinFactory {
|
||||
|
||||
/**
|
||||
* Factory method takes as parameter a car type and initiate the appropriate class.
|
||||
* Factory method takes as a parameter the coin type and calls the appropriate class.
|
||||
*/
|
||||
public static Car getCar(CarType type) {
|
||||
public static Coin getCoin(CoinType type) {
|
||||
return type.getConstructor().get();
|
||||
}
|
||||
}
|
@ -28,15 +28,14 @@ import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Enumeration for different types of cars.
|
||||
* Enumeration for different types of coins.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CarType {
|
||||
public enum CoinType {
|
||||
|
||||
FORD(Ford::new),
|
||||
FERRARI(Ferrari::new);
|
||||
|
||||
private final Supplier<Car> constructor;
|
||||
COPPER(CopperCoin::new),
|
||||
GOLD(GoldCoin::new);
|
||||
|
||||
private final Supplier<Coin> constructor;
|
||||
}
|
@ -24,11 +24,11 @@
|
||||
package com.iluwatar.factory;
|
||||
|
||||
/**
|
||||
* Ford implementation.
|
||||
* CopperCoin implementation.
|
||||
*/
|
||||
public class Ford implements Car {
|
||||
public class CopperCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is Ford.";
|
||||
static final String DESCRIPTION = "This is a copper coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
@ -24,11 +24,11 @@
|
||||
package com.iluwatar.factory;
|
||||
|
||||
/**
|
||||
* Ferrari implementation.
|
||||
* GoldCoin implementation.
|
||||
*/
|
||||
public class Ferrari implements Car {
|
||||
public class GoldCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is Ferrari.";
|
||||
static final String DESCRIPTION = "This is a gold coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
@ -27,12 +27,11 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CarsFactoryTest {
|
||||
class CoinFactoryTest {
|
||||
|
||||
@Test
|
||||
void shouldReturnFerrariInstance() {
|
||||
final var ferrari = CarsFactory.getCar(CarType.FERRARI);
|
||||
assertTrue(ferrari instanceof Ferrari);
|
||||
void shouldReturnGoldCoinInstance() {
|
||||
final var goldCoin = CoinFactory.getCoin(CoinType.GOLD);
|
||||
assertTrue(goldCoin instanceof GoldCoin);
|
||||
}
|
||||
|
||||
}
|
@ -23,11 +23,14 @@
|
||||
|
||||
package com.iluwatar.filterer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AppTest {
|
||||
|
||||
@Test
|
||||
void shouldLaunchApp() {
|
||||
App.main(new String[]{});
|
||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ permalink: /patterns/flyweight/
|
||||
categories: Structural
|
||||
language: en
|
||||
tags:
|
||||
- Gang Of Four
|
||||
- Gang of Four
|
||||
- Performance
|
||||
---
|
||||
|
||||
@ -16,11 +16,11 @@ Use sharing to support large numbers of fine-grained objects efficiently.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Alchemist's shop has shelves full of magic potions. Many of the potions are the same so there is
|
||||
> no need to create new object for each of them. Instead one object instance can represent multiple
|
||||
> shelf items so memory footprint remains small.
|
||||
> no need to create a new object for each of them. Instead, one object instance can represent
|
||||
> multiple shelf items so the memory footprint remains small.
|
||||
|
||||
In plain words
|
||||
|
||||
@ -36,7 +36,7 @@ Wikipedia says
|
||||
|
||||
**Programmatic example**
|
||||
|
||||
Translating our alchemist shop example from above. First of all we have different potion types:
|
||||
Translating our alchemist shop example from above. First of all, we have different potion types:
|
||||
|
||||
```java
|
||||
public interface Potion {
|
||||
@ -104,27 +104,81 @@ public class PotionFactory {
|
||||
}
|
||||
```
|
||||
|
||||
And it can be used as below:
|
||||
`AlchemistShop` contains two shelves of magic potions. The potions are created using the
|
||||
aforementioned `PotionFactory`.
|
||||
|
||||
```java
|
||||
var factory = new PotionFactory();
|
||||
factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818)
|
||||
factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364)
|
||||
factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818)
|
||||
factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489)
|
||||
factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489)
|
||||
factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364)
|
||||
@Slf4j
|
||||
public class AlchemistShop {
|
||||
|
||||
private final List<Potion> topShelf;
|
||||
private final List<Potion> bottomShelf;
|
||||
|
||||
public AlchemistShop() {
|
||||
var factory = new PotionFactory();
|
||||
topShelf = List.of(
|
||||
factory.createPotion(PotionType.INVISIBILITY),
|
||||
factory.createPotion(PotionType.INVISIBILITY),
|
||||
factory.createPotion(PotionType.STRENGTH),
|
||||
factory.createPotion(PotionType.HEALING),
|
||||
factory.createPotion(PotionType.INVISIBILITY),
|
||||
factory.createPotion(PotionType.STRENGTH),
|
||||
factory.createPotion(PotionType.HEALING),
|
||||
factory.createPotion(PotionType.HEALING)
|
||||
);
|
||||
bottomShelf = List.of(
|
||||
factory.createPotion(PotionType.POISON),
|
||||
factory.createPotion(PotionType.POISON),
|
||||
factory.createPotion(PotionType.POISON),
|
||||
factory.createPotion(PotionType.HOLY_WATER),
|
||||
factory.createPotion(PotionType.HOLY_WATER)
|
||||
);
|
||||
}
|
||||
|
||||
public final List<Potion> getTopShelf() {
|
||||
return List.copyOf(this.topShelf);
|
||||
}
|
||||
|
||||
public final List<Potion> getBottomShelf() {
|
||||
return List.copyOf(this.bottomShelf);
|
||||
}
|
||||
|
||||
public void drinkPotions() {
|
||||
LOGGER.info("Drinking top shelf potions\n");
|
||||
topShelf.forEach(Potion::drink);
|
||||
LOGGER.info("Drinking bottom shelf potions\n");
|
||||
bottomShelf.forEach(Potion::drink);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In our scenario, a brave visitor enters the alchemist shop and drinks all the potions.
|
||||
|
||||
```java
|
||||
// create the alchemist shop with the potions
|
||||
var alchemistShop = new AlchemistShop();
|
||||
// a brave visitor enters the alchemist shop and drinks all the potions
|
||||
alchemistShop.drinkPotions();
|
||||
```
|
||||
|
||||
Program output:
|
||||
|
||||
```java
|
||||
You become invisible. (Potion=6566818)
|
||||
You feel healed. (Potion=648129364)
|
||||
You become invisible. (Potion=6566818)
|
||||
You feel blessed. (Potion=1104106489)
|
||||
You feel blessed. (Potion=1104106489)
|
||||
You feel healed. (Potion=648129364)
|
||||
Drinking top shelf potions
|
||||
You become invisible. (Potion=1509514333)
|
||||
You become invisible. (Potion=1509514333)
|
||||
You feel strong. (Potion=739498517)
|
||||
You feel healed. (Potion=125130493)
|
||||
You become invisible. (Potion=1509514333)
|
||||
You feel strong. (Potion=739498517)
|
||||
You feel healed. (Potion=125130493)
|
||||
You feel healed. (Potion=125130493)
|
||||
Drinking bottom shelf potions
|
||||
Urgh! This is poisonous. (Potion=166239592)
|
||||
Urgh! This is poisonous. (Potion=166239592)
|
||||
Urgh! This is poisonous. (Potion=166239592)
|
||||
You feel blessed. (Potion=991505714)
|
||||
You feel blessed. (Potion=991505714)
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
@ -138,13 +192,13 @@ Flyweight pattern when all of the following are true:
|
||||
|
||||
* An application uses a large number of objects.
|
||||
* Storage costs are high because of the sheer quantity of objects.
|
||||
* Most object state can be made extrinsic.
|
||||
* Many groups of objects may be replaced by relatively few shared objects once extrinsic state is
|
||||
removed.
|
||||
* Most of the object state can be made extrinsic.
|
||||
* Many groups of objects may be replaced by relatively few shared objects once the extrinsic state
|
||||
is removed.
|
||||
* The application doesn't depend on object identity. Since flyweight objects may be shared, identity
|
||||
tests will return true for conceptually distinct objects.
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29) and similarly for Byte, Character and other wrapped types.
|
||||
|
||||
|
@ -78,12 +78,12 @@ public class AlchemistShop {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate potions.
|
||||
* Drink all the potions.
|
||||
*/
|
||||
public void enumerate() {
|
||||
LOGGER.info("Enumerating top shelf potions\n");
|
||||
public void drinkPotions() {
|
||||
LOGGER.info("Drinking top shelf potions");
|
||||
topShelf.forEach(Potion::drink);
|
||||
LOGGER.info("Enumerating bottom shelf potions\n");
|
||||
LOGGER.info("Drinking bottom shelf potions");
|
||||
bottomShelf.forEach(Potion::drink);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,9 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// create the alchemist shop with the potions
|
||||
var alchemistShop = new AlchemistShop();
|
||||
alchemistShop.enumerate();
|
||||
// a brave visitor enters the alchemist shop and drinks all the potions
|
||||
alchemistShop.drinkPotions();
|
||||
}
|
||||
}
|
||||
|
674
gpl-3.0.txt
Normal file
674
gpl-3.0.txt
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
@ -10,22 +10,161 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
Given a language, define a representation for its grammar along
|
||||
with an interpreter that uses the representation to interpret sentences in the
|
||||
language.
|
||||
|
||||
Given a language, define a representation for its grammar along with an interpreter that uses the
|
||||
representation to interpret sentences in the language.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real-world example
|
||||
|
||||
> The halfling kids are learning basic math at school. They start from the very basics "1 + 1",
|
||||
> "4 - 2", "5 + 5", and so forth.
|
||||
|
||||
In plain words
|
||||
|
||||
> Interpreter pattern interprets sentences in the desired language.
|
||||
|
||||
Wikipedia says
|
||||
|
||||
> In computer programming, the interpreter pattern is a design pattern that specifies how to
|
||||
> evaluate sentences in a language. The basic idea is to have a class for each symbol (terminal or
|
||||
> nonterminal) in a specialized computer language. The syntax tree of a sentence in the language
|
||||
> is an instance of the composite pattern and is used to evaluate (interpret) the sentence for
|
||||
> a client.
|
||||
|
||||
**Programmatic example**
|
||||
|
||||
To be able to interpret basic math, we need a hierarchy of expressions. The basic abstraction for
|
||||
it is the `Expression` class.
|
||||
|
||||
```java
|
||||
public abstract class Expression {
|
||||
|
||||
public abstract int interpret();
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
}
|
||||
```
|
||||
|
||||
The simplest of the expressions is the `NumberExpression` that contains only a single integer
|
||||
number.
|
||||
|
||||
```java
|
||||
public class NumberExpression extends Expression {
|
||||
|
||||
private final int number;
|
||||
|
||||
public NumberExpression(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public NumberExpression(String s) {
|
||||
this.number = Integer.parseInt(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int interpret() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "number";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The more complex expressions are operations such as `PlusExpression`, `MinusExpression`, and
|
||||
`MultiplyExpression`. Here's the first of them, the others are similar.
|
||||
|
||||
```java
|
||||
public class PlusExpression extends Expression {
|
||||
|
||||
private final Expression leftExpression;
|
||||
private final Expression rightExpression;
|
||||
|
||||
public PlusExpression(Expression leftExpression, Expression rightExpression) {
|
||||
this.leftExpression = leftExpression;
|
||||
this.rightExpression = rightExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int interpret() {
|
||||
return leftExpression.interpret() + rightExpression.interpret();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "+";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we are able to show the interpreter pattern in action parsing some simple math.
|
||||
|
||||
```java
|
||||
// the halfling kids are learning some basic math at school
|
||||
// define the math string we want to parse
|
||||
final var tokenString = "4 3 2 - 1 + *";
|
||||
|
||||
// the stack holds the parsed expressions
|
||||
var stack = new Stack<Expression>();
|
||||
|
||||
// tokenize the string and go through them one by one
|
||||
var tokenList = tokenString.split(" ");
|
||||
for (var s : tokenList) {
|
||||
if (isOperator(s)) {
|
||||
// when an operator is encountered we expect that the numbers can be popped from the top of
|
||||
// the stack
|
||||
var rightExpression = stack.pop();
|
||||
var leftExpression = stack.pop();
|
||||
LOGGER.info("popped from stack left: {} right: {}",
|
||||
leftExpression.interpret(), rightExpression.interpret());
|
||||
var operator = getOperatorInstance(s, leftExpression, rightExpression);
|
||||
LOGGER.info("operator: {}", operator);
|
||||
var result = operator.interpret();
|
||||
// the operation result is pushed on top of the stack
|
||||
var resultExpression = new NumberExpression(result);
|
||||
stack.push(resultExpression);
|
||||
LOGGER.info("push result to stack: {}", resultExpression.interpret());
|
||||
} else {
|
||||
// numbers are pushed on top of the stack
|
||||
var i = new NumberExpression(s);
|
||||
stack.push(i);
|
||||
LOGGER.info("push to stack: {}", i.interpret());
|
||||
}
|
||||
}
|
||||
// in the end, the final result lies on top of the stack
|
||||
LOGGER.info("result: {}", stack.pop().interpret());
|
||||
```
|
||||
|
||||
Executing the program produces the following console output.
|
||||
|
||||
```
|
||||
popped from stack left: 1 right: 1
|
||||
operator: +
|
||||
push result to stack: 2
|
||||
popped from stack left: 4 right: 2
|
||||
operator: *
|
||||
push result to stack: 8
|
||||
result: 8
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
Use the Interpreter pattern when there is a language to
|
||||
interpret, and you can represent statements in the language as abstract syntax
|
||||
trees. The Interpreter pattern works best when
|
||||
|
||||
* the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time
|
||||
* efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable
|
||||
Use the Interpreter pattern when there is a language to interpret, and you can represent statements
|
||||
in the language as abstract syntax trees. The Interpreter pattern works best when
|
||||
|
||||
## Real world examples
|
||||
* The grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time
|
||||
* Efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable
|
||||
|
||||
## Known uses
|
||||
|
||||
* [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
|
||||
* [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html)
|
||||
|
@ -34,25 +34,33 @@ import lombok.extern.slf4j.Slf4j;
|
||||
*
|
||||
* <p>In this example we use the Interpreter pattern to break sentences into expressions ({@link
|
||||
* Expression}) that can be evaluated and as a whole form the result.
|
||||
*
|
||||
* <p>Expressions can be evaluated using prefix, infix or postfix notations This sample uses
|
||||
* postfix, where operator comes after the operands.
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* <p>Expressions can be evaluated using prefix, infix or postfix notations This sample uses
|
||||
* postfix, where operator comes after the operands.
|
||||
*
|
||||
* @param args command line args
|
||||
* @param args program arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
var tokenString = "4 3 2 - 1 + *";
|
||||
|
||||
// the halfling kids are learning some basic math at school
|
||||
// define the math string we want to parse
|
||||
final var tokenString = "4 3 2 - 1 + *";
|
||||
|
||||
// the stack holds the parsed expressions
|
||||
var stack = new Stack<Expression>();
|
||||
|
||||
// tokenize the string and go through them one by one
|
||||
var tokenList = tokenString.split(" ");
|
||||
for (var s : tokenList) {
|
||||
if (isOperator(s)) {
|
||||
// when an operator is encountered we expect that the numbers can be popped from the top of
|
||||
// the stack
|
||||
var rightExpression = stack.pop();
|
||||
var leftExpression = stack.pop();
|
||||
LOGGER.info("popped from stack left: {} right: {}",
|
||||
@ -60,24 +68,36 @@ public class App {
|
||||
var operator = getOperatorInstance(s, leftExpression, rightExpression);
|
||||
LOGGER.info("operator: {}", operator);
|
||||
var result = operator.interpret();
|
||||
// the operation result is pushed on top of the stack
|
||||
var resultExpression = new NumberExpression(result);
|
||||
stack.push(resultExpression);
|
||||
LOGGER.info("push result to stack: {}", resultExpression.interpret());
|
||||
} else {
|
||||
// numbers are pushed on top of the stack
|
||||
var i = new NumberExpression(s);
|
||||
stack.push(i);
|
||||
LOGGER.info("push to stack: {}", i.interpret());
|
||||
}
|
||||
}
|
||||
// in the end, the final result lies on top of the stack
|
||||
LOGGER.info("result: {}", stack.pop().interpret());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the input parameter is an operator.
|
||||
* @param s input string
|
||||
* @return true if the input parameter is an operator
|
||||
*/
|
||||
public static boolean isOperator(String s) {
|
||||
return s.equals("+") || s.equals("-") || s.equals("*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expression for string.
|
||||
* Returns correct expression based on the parameters.
|
||||
* @param s input string
|
||||
* @param left expression
|
||||
* @param right expression
|
||||
* @return expression
|
||||
*/
|
||||
public static Expression getOperatorInstance(String s, Expression left, Expression right) {
|
||||
switch (s) {
|
||||
@ -85,8 +105,6 @@ public class App {
|
||||
return new PlusExpression(left, right);
|
||||
case "-":
|
||||
return new MinusExpression(left, right);
|
||||
case "*":
|
||||
return new MultiplyExpression(left, right);
|
||||
default:
|
||||
return new MultiplyExpression(left, right);
|
||||
}
|
||||
|
@ -19,10 +19,10 @@ underlying representation.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
Real-world example
|
||||
|
||||
> Treasure chest contains a set of magical items. There multiple types of items such as rings,
|
||||
> potions and weapons. The items can be browsed by type using an iterator the treasure chest
|
||||
> potions, and weapons. The items can be browsed by type using an iterator the treasure chest
|
||||
> provides.
|
||||
|
||||
In plain words
|
||||
@ -113,7 +113,7 @@ public interface Iterator<T> {
|
||||
}
|
||||
```
|
||||
|
||||
In the following example we iterate through the ring type items found in the chest.
|
||||
In the following example, we iterate through the ring-type items found in the chest.
|
||||
|
||||
```java
|
||||
var itemIterator = TREASURE_CHEST.iterator(ItemType.RING);
|
||||
@ -145,7 +145,7 @@ Use the Iterator pattern
|
||||
|
||||
* [How to Use Iterator?](http://www.tutorialspoint.com/java/java_using_iterator.htm)
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html)
|
||||
* [java.util.Enumeration](http://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html)
|
||||
|
165
lgpl-3.0.txt
Normal file
165
lgpl-3.0.txt
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
334
localization/pt/README.md
Normal file
334
localization/pt/README.md
Normal file
@ -0,0 +1,334 @@
|
||||
<!-- the line below needs to be an empty line C: (its because kramdown isnt
|
||||
that smart and dearly wants an empty line before a heading to be able to
|
||||
display it as such, e.g. website) -->
|
||||
|
||||
# Padrões de projeto implementados em Java
|
||||
|
||||

|
||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
|
||||
<br/>
|
||||
|
||||
Leia em outro idioma: [**zh**](/localization/zh/README.md), [**ko**](/localization/ko/README.md), [**fr**](/localization/fr/README.md), [**tr**](/localization/tr/README.md), [**ar**](/localization/ar/README.md), [**es**](/localization/es/README.md)
|
||||
|
||||
<br/>
|
||||
|
||||
# Introdução
|
||||
|
||||
Os padrões de projeto são um conjunto das melhores práticas e soluções formalizadas que um programador pode usar para resolver problemas comuns ao projetar um aplicativo ou sistema.
|
||||
|
||||
Os padrões de projeto podem acelerar o processo de desenvolvimento, fornecendo testes e comprovados paradigmas de desenvolvimento.
|
||||
|
||||
Reutilizar padrões de projeto ajuda a evitar problemas sutis que causam
|
||||
problemas, e também melhora a legibilidade do código para desenvolvedores e arquitetos que
|
||||
estão familiarizados com os padrões.
|
||||
|
||||
# Começando
|
||||
|
||||
Este site apresenta padrões de projeto Java. As soluções foram desenvolvidas por
|
||||
programadores e arquitetos experientes da comunidade de código aberto. Os
|
||||
padrões podem ser acessados por meio de suas descrições de alto nível ou por meio de seu
|
||||
Código fonte. Os exemplos de código-fonte são bem comentados e podem ser considerados como
|
||||
tutoriais de programação sobre como implementar um padrão específico. Nós usamos as mais
|
||||
populares tecnologias Java de código aberto comprovadas em batalhas.
|
||||
|
||||
Antes de mergulhar no material, você deve estar familiarizado com vários
|
||||
[Princípios de design de software](https://java-design-patterns.com/principles/).
|
||||
|
||||
Todos os projetos devem ser o mais simples possível. Você deve começar com KISS, YAGNI,
|
||||
e fazer a coisa mais simples que poderia funcionar com os princípios. Complexidade e
|
||||
os padrões só devem ser introduzidos quando são necessários para fins práticos e
|
||||
extensibilidade.
|
||||
|
||||
Assim que estiver familiarizado com esses conceitos, você pode começar a se aprofundar nos
|
||||
[padrões de projeto disponíveis](https://java-design-patterns.com/patterns/) por qualquer
|
||||
das seguintes abordagens
|
||||
|
||||
- Pesquise um padrão específico por nome. Não consegue encontrar um? Informe um novo padrão [aqui](https://github.com/iluwatar/java-design-patterns/issues).
|
||||
- Usando tags como `Performance`,` Gang of Four` ou `Acesso de dados`.
|
||||
- Usando categorias de padrões, `Criacional`,` Comportamental` e outros.
|
||||
|
||||
Esperamos que você encontre as soluções orientadas a objetos apresentadas neste site úteis
|
||||
em suas arquiteturas e divirta-se as aprendendo tanto quanto nos divertimos ao desenvolvê-las.
|
||||
|
||||
# Como contribuir
|
||||
|
||||
Se você estiver disposto a contribuir para o projeto, você encontrará as informações mais relevantes em nossa [wiki do desenvolvedor](https://github.com/iluwatar/java-design-patterns/wiki). Ajudaremos você e responderemos as suas perguntas na [sala de bate-papo do Gitter](https://gitter.im/iluwatar/java-design-patterns).
|
||||
|
||||
# Licença
|
||||
|
||||
Este projeto está licenciado sob os termos da licença MIT.
|
||||
|
||||
# Contribuidores
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/iluwatar"><img src="https://avatars1.githubusercontent.com/u/582346?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ilkka Seppälä</b></sub></a><br /><a href="#projectManagement-iluwatar" title="Project Management">📆</a> <a href="#maintenance-iluwatar" title="Maintenance">🚧</a> <a href="#content-iluwatar" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/amit1307"><img src="https://avatars0.githubusercontent.com/u/23420222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>amit1307</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit1307" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/npathai"><img src="https://avatars2.githubusercontent.com/u/1792515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Narendra Pathai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npathai" title="Code">💻</a> <a href="#ideas-npathai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Anpathai" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/fluxw42"><img src="https://avatars1.githubusercontent.com/u/1545460?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeroen Meulemeester</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fluxw42" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.joemccarthy.co.uk"><img src="https://avatars0.githubusercontent.com/u/4526195?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joseph McCarthy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mikulucky" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/thomasoss"><img src="https://avatars1.githubusercontent.com/u/22516154?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=thomasoss" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/anuragagarwal561994"><img src="https://avatars1.githubusercontent.com/u/6075379?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anurag Agarwal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anuragagarwal561994" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://markusmo3.github.io"><img src="https://avatars1.githubusercontent.com/u/3317416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Markus Moser</b></sub></a><br /><a href="#design-markusmo3" title="Design">🎨</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=markusmo3" title="Code">💻</a> <a href="#ideas-markusmo3" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://twitter.com/i_sabiq"><img src="https://avatars1.githubusercontent.com/u/19510920?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sabiq Ihab</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=isabiq" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://inbravo.github.io"><img src="https://avatars3.githubusercontent.com/u/5253764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Dixit</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=inbravo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/piyushchaudhari04"><img src="https://avatars3.githubusercontent.com/u/10268029?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piyush Kailash Chaudhari</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=piyushchaudhari04" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/joshzambales"><img src="https://avatars1.githubusercontent.com/u/8704552?v=4?s=100" width="100px;" alt=""/><br /><sub><b>joshzambales</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joshzambales" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Crossy147"><img src="https://avatars2.githubusercontent.com/u/7272996?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kamil Pietruszka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Crossy147" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://cs.joensuu.fi/~zkhayda"><img src="https://avatars2.githubusercontent.com/u/660742?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zafar Khaydarov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://kemitix.github.io/"><img src="https://avatars1.githubusercontent.com/u/1147749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Campbell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kemitix" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Argyro-Sioziou"><img src="https://avatars0.githubusercontent.com/u/22822639?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Argyro Sioziou</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Argyro-Sioziou" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TylerMcConville"><img src="https://avatars0.githubusercontent.com/u/4946449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>TylerMcConville</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=TylerMcConville" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/saksham93"><img src="https://avatars1.githubusercontent.com/u/37399540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>saksham93</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=saksham93" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nikhilbarar"><img src="https://avatars2.githubusercontent.com/u/37332144?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nikhilbarar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nikhilbarar" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://colinbut.com"><img src="https://avatars2.githubusercontent.com/u/10725674?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Colin But</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=colinbut" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ruslanpa"><img src="https://avatars2.githubusercontent.com/u/1503411?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ruslan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruslanpa" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juho Kang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JuhoKang" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dheeraj-mummareddy"><img src="https://avatars2.githubusercontent.com/u/7002230?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dheeraj Mummareddy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dheeraj-mummareddy" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.bernardosulzbach.com"><img src="https://avatars0.githubusercontent.com/u/8271090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bernardo Sulzbach</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=bernardosulzbach" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/4lexis"><img src="https://avatars0.githubusercontent.com/u/19871727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandar Dudukovic</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=4lexis" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.yusufaytas.com"><img src="https://avatars2.githubusercontent.com/u/1049483?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yusuf Aytaş</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yusufaytas" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://futurehomes.hu"><img src="https://avatars2.githubusercontent.com/u/1001491?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihály Kuprivecz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qpi" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/kapinuss"><img src="https://avatars0.githubusercontent.com/u/17639945?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stanislav Kapinus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kapinuss" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/gvsharma"><img src="https://avatars1.githubusercontent.com/u/6648152?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GVSharma</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gvsharma" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/SrdjanPaunovic"><img src="https://avatars1.githubusercontent.com/u/22815104?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Srđan Paunović</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=SrdjanPaunovic" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://sideris.xyz/"><img src="https://avatars3.githubusercontent.com/u/5484694?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Petros G. Sideris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sideris" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/pramodgupta3/"><img src="https://avatars1.githubusercontent.com/u/2184241?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pramod Gupta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AIAmPramod" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://amarnath510.github.io/portfolio"><img src="https://avatars0.githubusercontent.com/u/4599623?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amarnath Chandana</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Amarnath510" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Anurag870"><img src="https://avatars1.githubusercontent.com/u/6295975?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anurag870</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Anurag870" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=Anurag870" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://theerroris.me"><img src="https://avatars0.githubusercontent.com/u/1685953?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wes Gilleland</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Deathnerd" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Harshrajsinh"><img src="https://avatars2.githubusercontent.com/u/22811531?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harshraj Thakor</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Harshrajsinh" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/MaVdbussche"><img src="https://avatars1.githubusercontent.com/u/26136934?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martin Vandenbussche</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MaVdbussche" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://alexsomai.com"><img src="https://avatars1.githubusercontent.com/u/5720977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandru Somai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=alexsomai" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/amogozov"><img src="https://avatars3.githubusercontent.com/u/7372215?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artur Mogozov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amogozov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/anthonycampbell"><img src="https://avatars3.githubusercontent.com/u/10249255?v=4?s=100" width="100px;" alt=""/><br /><sub><b>anthony</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anthonycampbell" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://ccygnus.com/"><img src="https://avatars1.githubusercontent.com/u/9342724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Cygnus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christophercolumbusdog" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://about.me/dzmitryh"><img src="https://avatars2.githubusercontent.com/u/5390492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dima Gubin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dzmitryh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jjjimenez100"><img src="https://avatars3.githubusercontent.com/u/22243493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joshua Jimenez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jjjimenez100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://about.me/kaiwinter"><img src="https://avatars0.githubusercontent.com/u/110982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Winter</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kaiwinter" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/lbroman"><img src="https://avatars1.githubusercontent.com/u/86007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lbroman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=lbroman" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://przemeknowak.com"><img src="https://avatars1.githubusercontent.com/u/3254609?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Przemek</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pnowy" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/prafful1"><img src="https://avatars0.githubusercontent.com/u/14350274?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Prafful Agarwal</b></sub></a><br /><a href="#content-prafful1" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/sankypanhale"><img src="https://avatars1.githubusercontent.com/u/6478783?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sanket Panhale</b></sub></a><br /><a href="#content-sankypanhale" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/staillebois"><img src="https://avatars0.githubusercontent.com/u/23701200?v=4?s=100" width="100px;" alt=""/><br /><sub><b>staillebois</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=staillebois" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/valdar-hu"><img src="https://avatars3.githubusercontent.com/u/17962817?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krisztián Nagy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=valdar-hu" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.vanogrid.com"><img src="https://avatars0.githubusercontent.com/u/4307918?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Ivanov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vanogrid" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/yosfik"><img src="https://avatars3.githubusercontent.com/u/4850270?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yosfik Alqadri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yosfik" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/7agustibm"><img src="https://avatars0.githubusercontent.com/u/8149332?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Agustí Becerra Milà</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=7agustibm" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Juaanma"><img src="https://avatars3.githubusercontent.com/u/7390500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Suárez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Juaanma" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.devsedge.net/"><img src="https://avatars0.githubusercontent.com/u/9956006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luigi Cortese</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=LuigiCortese" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Rzeposlaw"><img src="https://avatars2.githubusercontent.com/u/18425745?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katarzyna Rzepecka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Rzeposlaw" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://adamski.pro"><img src="https://avatars1.githubusercontent.com/u/6537430?v=4?s=100" width="100px;" alt=""/><br /><sub><b>adamski.pro</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=akrystian" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/baislsl"><img src="https://avatars0.githubusercontent.com/u/17060584?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shengli Bai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=baislsl" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/besok"><img src="https://avatars2.githubusercontent.com/u/29834592?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=besok" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dmitraver"><img src="https://avatars3.githubusercontent.com/u/1798156?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Avershin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dmitraver" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/fanofxiaofeng"><img src="https://avatars0.githubusercontent.com/u/3983683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>靳阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fanofxiaofeng" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hoangnam2261"><img src="https://avatars2.githubusercontent.com/u/31692990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hoangnam2261</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoangnam2261" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jarpit96"><img src="https://avatars2.githubusercontent.com/u/10098713?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arpit Jain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jarpit96" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://joningi.net"><img src="https://avatars2.githubusercontent.com/u/6115148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jón Ingi Sveinbjörnsson</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joningiwork" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/kirill-vlasov"><img src="https://avatars3.githubusercontent.com/u/16112495?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kirill Vlasov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kirill-vlasov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://mitchell-irvin.com"><img src="https://avatars0.githubusercontent.com/u/16233245?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mitchell Irvin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mitchellirvin" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://ranjeet-floyd.github.io"><img src="https://avatars0.githubusercontent.com/u/1992972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ranjeet</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ranjeet-floyd" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://alwayswithme.github.io"><img src="https://avatars3.githubusercontent.com/u/3234786?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PhoenixYip</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Alwayswithme" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/MSaifAsif"><img src="https://avatars1.githubusercontent.com/u/6280554?v=4?s=100" width="100px;" alt=""/><br /><sub><b>M Saif Asif</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MSaifAsif" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/kanwarpreet25"><img src="https://avatars0.githubusercontent.com/u/39183641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kanwarpreet25</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kanwarpreet25" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://leonmak.me"><img src="https://avatars3.githubusercontent.com/u/13071508?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leon Mak</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leonmak" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.wramdemark.se"><img src="https://avatars2.githubusercontent.com/u/7052193?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Per Wramdemark</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=perwramdemark" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/waisuan"><img src="https://avatars2.githubusercontent.com/u/10975700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evan Sia Wai Suan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=waisuan" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/AnaghaSasikumar"><img src="https://avatars2.githubusercontent.com/u/42939261?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AnaghaSasikumar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AnaghaSasikumar" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://christofferh.com"><img src="https://avatars1.githubusercontent.com/u/767643?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoffer Hamberg</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christofferh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dgruntz"><img src="https://avatars0.githubusercontent.com/u/1516800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dominik Gruntz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dgruntz" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://bitbucket.org/hannespernpeintner/"><img src="https://avatars3.githubusercontent.com/u/1679437?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hannes</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hannespernpeintner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/leogtzr"><img src="https://avatars0.githubusercontent.com/u/1211969?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leo Gutiérrez Ramírez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leogtzr" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/npczwh"><img src="https://avatars0.githubusercontent.com/u/14066422?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zhang WH</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npczwh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/oconnelc"><img src="https://avatars0.githubusercontent.com/u/1112973?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christopher O'Connell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=oconnelc" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/giorgosmav21"><img src="https://avatars2.githubusercontent.com/u/22855493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Mavroeidis</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=giorgosmav21" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hbothra15"><img src="https://avatars1.githubusercontent.com/u/7418012?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hemant Bothra</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hbothra15" title="Code">💻</a> <a href="#design-hbothra15" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars1.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=igeligel" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://llorllale.github.io/"><img src="https://avatars1.githubusercontent.com/u/2019896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Aristy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=llorllale" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/mookkiah"><img src="https://avatars1.githubusercontent.com/u/8975264?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mahendran Mookkiah</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mookkiah" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Azureyjt"><img src="https://avatars2.githubusercontent.com/u/18476317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Azureyjt</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Azureyjt" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vehpsr"><img src="https://avatars2.githubusercontent.com/u/3133265?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vehpsr" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ThatGuyWithTheHat"><img src="https://avatars0.githubusercontent.com/u/24470582?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt</b></sub></a><br /><a href="#content-ThatGuyWithTheHat" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/gopinathlangote/"><img src="https://avatars2.githubusercontent.com/u/10210778?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gopinath Langote</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gopinath-langote" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hoswey"><img src="https://avatars3.githubusercontent.com/u/3689445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hoswey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoswey" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/amit2103"><img src="https://avatars3.githubusercontent.com/u/7566692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Pandey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit2103" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/gwildor28"><img src="https://avatars0.githubusercontent.com/u/16000365?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gwildor28</b></sub></a><br /><a href="#content-gwildor28" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://t.me/paul_docker"><img src="https://avatars1.githubusercontent.com/u/2404785?v=4?s=100" width="100px;" alt=""/><br /><sub><b>田浩</b></sub></a><br /><a href="#content-llitfkitfk" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://twitter.com/StPitsios"><img src="https://avatars1.githubusercontent.com/u/6773603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stamatis Pitsios</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pitsios-s" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/qza"><img src="https://avatars3.githubusercontent.com/u/233149?v=4?s=100" width="100px;" alt=""/><br /><sub><b>qza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qza" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://tschis.github.io"><img src="https://avatars1.githubusercontent.com/u/20662669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodolfo Forte</b></sub></a><br /><a href="#content-Tschis" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ankurkaushal"><img src="https://avatars2.githubusercontent.com/u/2236616?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ankur Kaushal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ankurkaushal" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/ovidijus-okinskas/"><img src="https://avatars0.githubusercontent.com/u/20372387?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ovidijus Okinskas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=okinskas" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/robertt240"><img src="https://avatars1.githubusercontent.com/u/9137432?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert Kasperczyk</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=robertt240" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/trautonen"><img src="https://avatars3.githubusercontent.com/u/1641063?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tapio Rautonen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=trautonen" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://vk.com/yuri.orlov"><img src="https://avatars0.githubusercontent.com/u/1595733?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yuri Orlov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yorlov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/varunu28/"><img src="https://avatars0.githubusercontent.com/u/7676016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Varun Upadhyay</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=varunu28" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/PalAditya"><img src="https://avatars2.githubusercontent.com/u/25523604?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aditya Pal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=PalAditya" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/grzesiekkedzior"><img src="https://avatars3.githubusercontent.com/u/23739158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>grzesiekkedzior</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=grzesiekkedzior" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Agrzesiekkedzior" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/sivasubramanim"><img src="https://avatars2.githubusercontent.com/u/51107434?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sivasubramani M</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sivasubramanim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/d4gg4d"><img src="https://avatars2.githubusercontent.com/u/99457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sami Airaksinen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=d4gg4d" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vertti"><img src="https://avatars0.githubusercontent.com/u/557751?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Janne Sinivirta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vertti" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Bobo1239"><img src="https://avatars1.githubusercontent.com/u/2302947?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris-Chengbiao Zhou</b></sub></a><br /><a href="#content-Bobo1239" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://jahhein.github.io"><img src="https://avatars2.githubusercontent.com/u/10779515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob Hein</b></sub></a><br /><a href="#content-Jahhein" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/iamrichardjones"><img src="https://avatars3.githubusercontent.com/u/14842151?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richard Jones</b></sub></a><br /><a href="#content-iamrichardjones" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://rachelcarmena.github.io"><img src="https://avatars0.githubusercontent.com/u/22792183?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rachel M. Carmena</b></sub></a><br /><a href="#content-rachelcarmena" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://zd-zero.github.io"><img src="https://avatars0.githubusercontent.com/u/21978370?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zaerald Denze Lungos</b></sub></a><br /><a href="#content-zd-zero" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://webpro.nl"><img src="https://avatars1.githubusercontent.com/u/456426?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lars Kappert</b></sub></a><br /><a href="#content-webpro" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://xiaod.info"><img src="https://avatars2.githubusercontent.com/u/21277644?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Liu</b></sub></a><br /><a href="#translation-xiaod-dev" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nishant"><img src="https://avatars2.githubusercontent.com/u/15331971?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nishant Arora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nishant" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/raja-peeyush-kumar-singh"><img src="https://avatars0.githubusercontent.com/u/5496024?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Peeyush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=raja-peeyush-kumar-singh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aravening" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/vINCENT8888801"><img src="https://avatars0.githubusercontent.com/u/8037883?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wei Seng</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vINCENT8888801" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/ashish-trivedi-218379135/"><img src="https://avatars3.githubusercontent.com/u/23194128?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashish Trivedi</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ashishtrivedi16" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://rayyounghong.com"><img src="https://avatars1.githubusercontent.com/u/41055099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>洪月阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=RayYH" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://xdvrx1.github.io/"><img src="https://avatars0.githubusercontent.com/u/47092464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xdvrx1</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Axdvrx1" title="Reviewed Pull Requests">👀</a> <a href="#ideas-xdvrx1" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="http://subho.xyz"><img src="https://avatars0.githubusercontent.com/u/13291222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Subhrodip Mohanta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ohbus" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aohbus" title="Reviewed Pull Requests">👀</a> <a href="#maintenance-ohbus" title="Maintenance">🚧</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nahteb"><img src="https://avatars3.githubusercontent.com/u/13121570?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bethan Palmer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nahteb" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ToxicDreamz"><img src="https://avatars0.githubusercontent.com/u/45225562?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Toxic Dreamz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ToxicDreamz" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.edycutjong.com"><img src="https://avatars1.githubusercontent.com/u/1098102?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Edy Cu Tjong</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=edycutjong" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/mkrzywanski"><img src="https://avatars0.githubusercontent.com/u/15279585?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michał Krzywański</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mkrzywanski" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.stefan-birkner.de"><img src="https://avatars1.githubusercontent.com/u/711349?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Birkner</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=stefanbirkner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/fedorskvorcov"><img src="https://avatars3.githubusercontent.com/u/43882212?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fedor Skvorcov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fedorskvorcov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/samilAyoub"><img src="https://avatars0.githubusercontent.com/u/61546990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>samilAyoub</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samilAyoub" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vdlald"><img src="https://avatars0.githubusercontent.com/u/29997701?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Golubinov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vdlald" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/swarajsaaj"><img src="https://avatars2.githubusercontent.com/u/6285049?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Swaraj</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=swarajsaaj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://christophflick.de"><img src="https://avatars0.githubusercontent.com/u/4465376?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoph Flick</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ChFlick" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/Ascenio"><img src="https://avatars1.githubusercontent.com/u/7662016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ascênio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AAscenio" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/domenico-sibilio/"><img src="https://avatars2.githubusercontent.com/u/24280982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Domenico Sibilio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dsibilio" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/akashchandwani"><img src="https://avatars2.githubusercontent.com/u/3483277?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akash Chandwani</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aakashchandwani" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="http://www.linkedin.com/in/manannikov"><img src="https://avatars2.githubusercontent.com/u/7019769?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pavlo Manannikov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=manannikov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/eimanip"><img src="https://avatars0.githubusercontent.com/u/20307301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eiman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eimanip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/OrangePants-R"><img src="https://avatars0.githubusercontent.com/u/42976136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rocky</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=OrangePants-R" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://ibrahimalii.github.io/"><img src="https://avatars2.githubusercontent.com/u/21141301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ibrahim ali abdelghany</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AibrahimAlii" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/gkulkarni2020"><img src="https://avatars3.githubusercontent.com/u/5161548?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Girish Kulkarni</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gkulkarni2020" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/omk13"><img src="https://avatars0.githubusercontent.com/u/59054172?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Omar Karazoun</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=omk13" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jeff303"><img src="https://avatars0.githubusercontent.com/u/3521562?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeff Evans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jeff303" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://viveksb007.github.io"><img src="https://avatars1.githubusercontent.com/u/12713808?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vivek Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=viveksb007" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/siavashsoleymani"><img src="https://avatars2.githubusercontent.com/u/18074419?v=4?s=100" width="100px;" alt=""/><br /><sub><b>siavash</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=siavashsoleymani" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ruchpeanuts"><img src="https://avatars0.githubusercontent.com/u/29301900?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ruchpeanuts</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruchpeanuts" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/warp125"><img src="https://avatars1.githubusercontent.com/u/48073115?v=4?s=100" width="100px;" alt=""/><br /><sub><b>warp125</b></sub></a><br /><a href="#translation-warp125" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://libkhadir.fr"><img src="https://avatars1.githubusercontent.com/u/45130488?v=4?s=100" width="100px;" alt=""/><br /><sub><b>KHADIR Tayeb</b></sub></a><br /><a href="#translation-tkhadir" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/ignite1771"><img src="https://avatars2.githubusercontent.com/u/59446563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ignite1771</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ignite1771" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/demirhalil"><img src="https://avatars1.githubusercontent.com/u/22895118?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Halil Demir</b></sub></a><br /><a href="#translation-demirhalil" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/rohit10000"><img src="https://avatars.githubusercontent.com/u/20845565?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rohit Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=rohit10000" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/byoungju94"><img src="https://avatars.githubusercontent.com/u/42516378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>byoungju94</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=byoungju94" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/moustafafarhat"><img src="https://avatars.githubusercontent.com/u/38836727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moustafa Farhat</b></sub></a><br /><a href="#translation-moustafafarhat" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/richardmr36"><img src="https://avatars.githubusercontent.com/u/19147333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martel Richard</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=richardmr36" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/va1m"><img src="https://avatars.githubusercontent.com/u/17025445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>va1m</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=va1m" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/noamgrinch"><img src="https://avatars.githubusercontent.com/u/31648669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Noam Greenshtain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=noamgrinch" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://xuyonghong.cn/"><img src="https://avatars.githubusercontent.com/u/14086462?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yonghong Xu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qfxl" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/jinisha-vora"><img src="https://avatars.githubusercontent.com/u/40777762?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jinishavora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Ajinishavora" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=jinishavora" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/eas5"><img src="https://avatars.githubusercontent.com/u/50836521?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Elvys Soares</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eas5" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/zWeBrain"><img src="https://avatars.githubusercontent.com/u/46642512?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zWeBrain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zWeBrain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://al-assad.github.io/notion/"><img src="https://avatars.githubusercontent.com/u/22493821?v=4?s=100" width="100px;" alt=""/><br /><sub><b>余林颖</b></sub></a><br /><a href="#translation-Al-assad" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/STudio26"><img src="https://avatars.githubusercontent.com/u/6988911?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alain</b></sub></a><br /><a href="#translation-STudio26" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/DEV-VRUPER"><img src="https://avatars.githubusercontent.com/u/30525467?v=4?s=100" width="100px;" alt=""/><br /><sub><b>VR</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=DEV-VRUPER" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/JackieNim"><img src="https://avatars.githubusercontent.com/u/4138836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JackieNim</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JackieNim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/EdisonE3"><img src="https://avatars.githubusercontent.com/u/52118917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>EdisonE3</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=EdisonE3" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/tao-sun2"><img src="https://avatars.githubusercontent.com/u/66189688?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tao</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=tao-sun2" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JuanManuelAbate"><img src="https://avatars.githubusercontent.com/u/16357060?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Abate</b></sub></a><br /><a href="#translation-JuanManuelAbate" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Xenilo137"><img src="https://avatars.githubusercontent.com/u/24865069?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xenilo137</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Xenilo137" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/souzasamuel/"><img src="https://avatars.githubusercontent.com/u/17254162?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samuel Souza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samuelpsouza" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Abstract Document
|
||||
folder: abstract-document
|
||||
permalink: /patterns/abstract-document/zh
|
||||
permalink: /patterns/abstract-document/
|
||||
categories: Structural
|
||||
language: zh
|
||||
tags:
|
||||
@ -166,7 +166,7 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Abstract Factory
|
||||
folder: abstract-factory
|
||||
permalink: /patterns/abstract-factory/zh
|
||||
permalink: /patterns/abstract-factory/
|
||||
categories: Creational
|
||||
language: zh
|
||||
tags:
|
||||
@ -168,7 +168,7 @@ public static void main(String[] args) {
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## 适用性
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Active Object
|
||||
folder: active-object
|
||||
permalink: /patterns/active-object/zh
|
||||
permalink: /patterns/active-object/
|
||||
categories: Concurrency
|
||||
language: zh
|
||||
tags:
|
||||
@ -122,4 +122,4 @@ public class Orc extends ActiveCreature {
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Acyclic Visitor
|
||||
folder: acyclic-visitor
|
||||
permalink: /patterns/acyclic-visitor/zh
|
||||
permalink: /patterns/acyclic-visitor/
|
||||
categories: Behavioral
|
||||
language: zh
|
||||
tags:
|
||||
@ -123,7 +123,7 @@ public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Adapter
|
||||
folder: adapter
|
||||
permalink: /patterns/adapter/zh
|
||||
permalink: /patterns/adapter/
|
||||
categories: Structural
|
||||
language: zh
|
||||
tags:
|
||||
@ -94,7 +94,7 @@ captain.row();
|
||||
```
|
||||
|
||||
## 类图
|
||||

|
||||

|
||||
|
||||
|
||||
## 应用
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Aggregator Microservices
|
||||
folder: aggregator-microservices
|
||||
permalink: /patterns/aggregator-microservices/zh
|
||||
permalink: /patterns/aggregator-microservices/
|
||||
categories: Architectural
|
||||
language: zh
|
||||
tags:
|
||||
@ -95,7 +95,7 @@ curl http://localhost:50004/product
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Ambassador
|
||||
folder: ambassador
|
||||
permalink: /patterns/ambassador/zh
|
||||
permalink: /patterns/ambassador/
|
||||
categories: Structural
|
||||
language: zh
|
||||
tags:
|
||||
@ -167,7 +167,7 @@ Service result: -1
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: API Gateway
|
||||
folder: api-gateway
|
||||
permalink: /patterns/api-gateway/zh
|
||||
permalink: /patterns/api-gateway/
|
||||
categories: Architectural
|
||||
language: zh
|
||||
tags:
|
||||
@ -123,7 +123,7 @@ public class ApiGateway {
|
||||
```
|
||||
|
||||
## 类图
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Arrange/Act/Assert
|
||||
folder: arrange-act-assert
|
||||
permalink: /patterns/arrange-act-assert/zh
|
||||
permalink: /patterns/arrange-act-assert/
|
||||
categories: Idiom
|
||||
language: zh
|
||||
tags:
|
||||
@ -73,10 +73,7 @@ public class Cash {
|
||||
}
|
||||
```
|
||||
|
||||
Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the clearly
|
||||
separated steps for each unit test.
|
||||
|
||||
然后我们根据Arrange / Act / Assert模式编写单元测试。 注意每个单元测试的步骤是分开的清晰的。
|
||||
然后我们根据安排/ 执行 / 断言模式编写单元测试。 注意每个单元测试的步骤是分开的清晰的。
|
||||
|
||||
```java
|
||||
class CashAAATest {
|
||||
@ -129,9 +126,8 @@ class CashAAATest {
|
||||
|
||||
## 适用性
|
||||
|
||||
使用 Arrange/Act/Assert 模式当
|
||||
使用 安排/执行/断言 模式当
|
||||
|
||||
* You need to structure your unit tests so that they're easier to read, maintain, and enhance.
|
||||
* 你需要结构化你的单元测试代码这样它们可以更好的阅读,维护和增强。
|
||||
|
||||
## 鸣谢
|
||||
|
@ -4,33 +4,32 @@ title: Async Method Invocation
|
||||
folder: async-method-invocation
|
||||
permalink: /patterns/async-method-invocation/
|
||||
categories: Concurrency
|
||||
language: zh
|
||||
tags:
|
||||
- Reactive
|
||||
---
|
||||
|
||||
## 含义
|
||||
## 意图
|
||||
|
||||
异步方法是一种调用线程在等待任务结果时候不会被阻塞的模式。该模式提供了对多个任务的并行处理,并通过回调或等待,在所有任务完成后在提供结果读取。
|
||||
异步方法调用是一个调用线程在等待任务结果时不会阻塞的模式。模式为多个独立的任务提供并行的处理方式并且通过回调或等到它们全部完成来接收任务结果。
|
||||
|
||||
## 解释
|
||||
|
||||
真实世界案例
|
||||
真实世界例子
|
||||
|
||||
> 发射太空火箭是一项令人兴奋的事业。在任务指挥部下达发射命令后, 经过一些未确定的时间,火箭要么成功发射,要么重演挑战者悲剧。
|
||||
> 发射火箭是一项令人激动的事务。任务指挥官发出了发射命令,经过一段不确定的时间后,火箭要么成功发射,要么惨遭失败。
|
||||
|
||||
简而言之
|
||||
通俗地说
|
||||
|
||||
> 异步方法调用开始任务处理并,在任务结果准备好之前立即返回。任务处理的结果会在稍后再返回给调用者。
|
||||
> 异步方法调用开始任务处理,并在任务完成之前立即返回。 任务处理的结果稍后返回给调用方。
|
||||
|
||||
维基百科的解释
|
||||
维基百科说
|
||||
|
||||
> 在多线程计算机编程中,异步方法调用(AMI),也被称为异步方法调用或异步模式。这是一种设计模式,在这种模式下,调用点在等待被调用代码完成时不会被阻塞。相反,当返回点到达时,调用线程会得到通知。轮询结果是一种不受欢迎的选择。
|
||||
> 在多线程计算机编程中,异步方法调用(AMI),也称为异步方法调用或异步模式,是一种设计模式,其中在等待被调用的代码完成时不会阻塞调用站点。 而是在执行结果到达时通知调用线程。轮询调用结果是不希望的选项。
|
||||
|
||||
**编程示例**
|
||||
**程序示例**
|
||||
|
||||
在这个例子中,我们正在发射太空火箭和部署月球车。
|
||||
|
||||
该应用演示了异步方法调用模式。该模式的关键部分是 `AsyncResult`,它是一个异步计算值的中间容器,`AsyncCallback` 可以在任务完成时提供执行行动作,`AsyncExecutor` 负责管理异步任务的执行。
|
||||
在此示例中,我们正在发射太空火箭并部署月球漫游车。该应用演示了异步方法调用模式。 模式的关键部分是`AsyncResult`(用于异步评估值的中间容器),`AsyncCallback`(可以在任务完成时被执行)和`AsyncExecutor`(用于管理异步任务的执行)。
|
||||
|
||||
```java
|
||||
public interface AsyncResult<T> {
|
||||
@ -54,7 +53,7 @@ public interface AsyncExecutor {
|
||||
}
|
||||
```
|
||||
|
||||
`ThreadAsyncExecutor` 是 `AsyncExecutor` 的一个实现。接下来将着重说明它的一些关键部分。
|
||||
`ThreadAsyncExecutor`是`AsyncExecutor`的实现。 接下来将突出显示其一些关键部分。
|
||||
|
||||
```java
|
||||
public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
@ -91,14 +90,14 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
}
|
||||
```
|
||||
|
||||
然后我们准备发射一些火箭,看看所有东西是如何一起运作的。
|
||||
然后,我们准备发射一些火箭,看看一切是如何协同工作的。
|
||||
|
||||
```java
|
||||
public static void main(String[] args) throws Exception {
|
||||
// construct a new executor that will run async tasks
|
||||
// 构造一个将执行异步任务的新执行程序
|
||||
var executor = new ThreadAsyncExecutor();
|
||||
|
||||
// start few async tasks with varying processing times, two last with callback handlers
|
||||
// 以不同的处理时间开始一些异步任务,最后两个使用回调处理程序
|
||||
final var asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||
@ -106,11 +105,11 @@ public static void main(String[] args) throws Exception {
|
||||
final var asyncResult5 =
|
||||
executor.startProcess(lazyval("callback", 600), callback("Deploying lunar rover"));
|
||||
|
||||
// emulate processing in the current thread while async tasks are running in their own threads
|
||||
Thread.sleep(350); // Oh boy, we are working hard here
|
||||
// 在当前线程中模拟异步任务正在它们自己的线程中执行
|
||||
Thread.sleep(350); // 哦,兄弟,我们在这很辛苦
|
||||
log("Mission command is sipping coffee");
|
||||
|
||||
// wait for completion of the tasks
|
||||
// 等待任务完成
|
||||
final var result1 = executor.endProcess(asyncResult1);
|
||||
final var result2 = executor.endProcess(asyncResult2);
|
||||
final var result3 = executor.endProcess(asyncResult3);
|
||||
@ -118,13 +117,14 @@ public static void main(String[] args) throws Exception {
|
||||
asyncResult5.await();
|
||||
|
||||
// log the results of the tasks, callbacks log immediately when complete
|
||||
// 记录任务结果的日志, 回调的日志会在回调完成时立刻记录
|
||||
log("Space rocket <" + result1 + "> launch complete");
|
||||
log("Space rocket <" + result2 + "> launch complete");
|
||||
log("Space rocket <" + result3 + "> launch complete");
|
||||
}
|
||||
```
|
||||
|
||||
以下是控制台输出。
|
||||
这是程序控制台的输出。
|
||||
|
||||
```java
|
||||
21:47:08.227 [executor-2] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launched successfully
|
||||
@ -140,22 +140,21 @@ public static void main(String[] args) throws Exception {
|
||||
21:47:08.618 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <50> launch complete
|
||||
```
|
||||
|
||||
## 类图
|
||||
# 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用场景
|
||||
## 适用性
|
||||
|
||||
在以下场景可以使用异步调用模式
|
||||
在以下情况下使用异步方法调用模式
|
||||
|
||||
* 你有多有可以并行执行的独立任务
|
||||
* 你需要提高一组串行任务的性能
|
||||
* 你的处理能力有限、或者有长期运行的任务,调用者不应该等待任务所有任务运行结束
|
||||
* 您有多个可以并行运行的独立任务
|
||||
* 您需要提高一组顺序任务的性能
|
||||
* 您的处理能力或长时间运行的任务数量有限,并且调用方不应等待任务执行完毕
|
||||
|
||||
## 现实示例
|
||||
## 真实世界例子
|
||||
|
||||
* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html)
|
||||
* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
|
||||
* [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
|
||||
* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx)
|
||||
|
||||
|
@ -4,33 +4,34 @@ title: Balking
|
||||
folder: balking
|
||||
permalink: /patterns/balking/
|
||||
categories: Concurrency
|
||||
language: zh
|
||||
tags:
|
||||
- Decoupling
|
||||
---
|
||||
|
||||
## 含义
|
||||
## 意图
|
||||
|
||||
阻止模式用于防止一个对象在不完整或不适当的状态下执行某段代码。
|
||||
止步模式用于防止对象在不完整或不合适的状态下执行某些代码。
|
||||
|
||||
## 解释
|
||||
|
||||
真实世界的案例
|
||||
真实世界例子
|
||||
|
||||
> 洗衣机里有一个用于启动衣物洗涤的启动按钮。当洗衣机没有启动时,该按钮可以正常按下生效,但如果洗衣机已经在洗衣服了,再按下按钮就不生效了。
|
||||
> 洗衣机中有一个开始按钮,用于启动衣物洗涤。当洗衣机处于非活动状态时,按钮将按预期工作,但是如果已经在洗涤,则按钮将不起任何作用。
|
||||
|
||||
简而言之
|
||||
通俗地说
|
||||
|
||||
> 使用阻止模式,只有当对象处于特定状态时,才会执行某段代码。
|
||||
> 使用止步模式,仅当对象处于特定状态时才执行特定代码。
|
||||
|
||||
维基百科的解释
|
||||
维基百科说
|
||||
|
||||
> 阻止模式是一种软件设计模式,它只在对象处于特定状态时对其执行动作。例如,如果一个对象读取 ZIP 文件,当 ZIP 文件没有打开时,如果一个方法在该对象上调用一个获取方法,该对象就会对阻止这个请求。
|
||||
> 禁止模式是一种软件设计模式,仅当对象处于特定状态时才对对象执行操作。例如,一个对象读取zip压缩文件并在压缩文件没打开的时候调用get方法,对象将在请求的时候”止步“。
|
||||
|
||||
**编程示例**
|
||||
**程序示例**
|
||||
|
||||
在这个例子的实现中,`WashingMachine` 对象存在 2 种状态: `ENABLED` 和 `WASHING`。如果该对象处于 `ENABLED` 状态,则使用一个线程安全的方法可以其状态改变为 `WASHING`。在另一方面,如果它已经处于 `WASHING` 状态,而任何其他线程执行了 `wash()`,它不会执行该指令,而是什么都不做就返回。
|
||||
在此示例中,` WashingMachine`是一个具有两个状态的对象,可以处于两种状态:ENABLED和WASHING。 如果机器已启用,则使用线程安全方法将状态更改为WASHING。 另一方面,如果已经进行了清洗并且任何其他线程执行`wash()`,则它将不执行该操作,而是不执行任何操作而返回。
|
||||
|
||||
以下是 `WashingMachine` 类的相关代码。
|
||||
这里是`WashingMachine` 类相关的部分。
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@ -69,7 +70,7 @@ public class WashingMachine {
|
||||
}
|
||||
```
|
||||
|
||||
以下是 `WashingMachine` 使用的简单 `DelayProvider` 接口。
|
||||
这里是一个`WashingMachine`所使用的`DelayProvider`简单接口。
|
||||
|
||||
```java
|
||||
public interface DelayProvider {
|
||||
@ -77,7 +78,7 @@ public interface DelayProvider {
|
||||
}
|
||||
```
|
||||
|
||||
现在我们介绍一下使用 `WashingMachine` 的应用。
|
||||
现在,我们使用`WashingMachine`介绍该应用程序。
|
||||
|
||||
```java
|
||||
public static void main(String... args) {
|
||||
@ -96,7 +97,7 @@ public interface DelayProvider {
|
||||
}
|
||||
```
|
||||
|
||||
以下是程序的控制台输出。
|
||||
下面是程序的输出。
|
||||
|
||||
```
|
||||
14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
|
||||
@ -110,20 +111,21 @@ public interface DelayProvider {
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用场景
|
||||
## 适用性
|
||||
|
||||
在以下情况下可以使用阻止模式:
|
||||
|
||||
* 你想要在某个对象上调用一个动作,只有当该对象处于特定状态时才允许该调用。
|
||||
* 对象一般只处于容易暂时阻止的状态,只不过该时间是未知的。
|
||||
使用止步模式当
|
||||
|
||||
## 教学
|
||||
* 您只想在对象处于特定状态时才对其调用操作
|
||||
* 对象通常仅处于容易暂时停止但状态未知的状态
|
||||
|
||||
* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/)
|
||||
* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/)
|
||||
## 相关模式
|
||||
|
||||
## 引用
|
||||
* [保护性暂挂模式](https://java-design-patterns.com/patterns/guarded-suspension/)
|
||||
* [双重检查锁模式](https://java-design-patterns.com/patterns/double-checked-locking/)
|
||||
|
||||
## 鸣谢
|
||||
|
||||
* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99)
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Bridge
|
||||
folder: bridge
|
||||
permalink: /patterns/bridge/zh
|
||||
permalink: /patterns/bridge/
|
||||
categories: Structural
|
||||
language: zh
|
||||
tags:
|
||||
@ -184,7 +184,7 @@ hammer.unwield();
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Builder
|
||||
folder: builder
|
||||
permalink: /patterns/builder/zh
|
||||
permalink: /patterns/builder/
|
||||
categories: Creational
|
||||
language: zh
|
||||
tags:
|
||||
@ -114,7 +114,7 @@ var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
@ -4,36 +4,32 @@ title: Business Delegate
|
||||
folder: business-delegate
|
||||
permalink: /patterns/business-delegate/
|
||||
categories: Structural
|
||||
language: zh
|
||||
tags:
|
||||
- Decoupling
|
||||
---
|
||||
|
||||
## 含义
|
||||
## 意图
|
||||
|
||||
业务委托模式(译者:国内也有翻译成业务代表模式)在表现层和业务层之间增加了一个抽象层。通过使用该模式,我们获得了各层之间的松散耦合,并封装了关于如何定位、连接和与构成应用程序的业务对象进行交互的知识。
|
||||
业务委托模式在表示层和业务层之间添加了一个抽象层。 通过使用该模式,我们获得了各层之间的松散耦合,并封装了有关如何定位,连接到组成应用程序的业务对象以及与之交互的逻辑。
|
||||
|
||||
## 解释
|
||||
|
||||
真实世界的案例
|
||||
真实世界例子
|
||||
|
||||
> 一个手机应用程序承诺将现有的任何电影传输到你的手机上。它捕获了用户的搜索关键字内容,并将其传递给业务委托层。业务委托层选择最合适的视频流服务,并从该服务进行视频播放。
|
||||
> 手机应用程序承诺将现有的任何电影流式传输到您的手机。它捕获用户的搜索字符串,并将其传递给业务委托层。业务委托层选择最合适的视频流服务,然后从那里播放视频。
|
||||
|
||||
简而言之
|
||||
通俗的说
|
||||
|
||||
> 业务委托模式在表现层和业务层之间增加了一个抽象层。
|
||||
> 业务委托模式在表示层和业务层之间添加了一个抽象层。
|
||||
|
||||
维基百科的解释
|
||||
维基百科说
|
||||
|
||||
> Business delegate is a Java EE design pattern. This pattern is directing to reduce the coupling
|
||||
> in between business services and the connected presentation tier, and to hide the implementation
|
||||
> details of services (including lookup and accessibility of EJB architecture). Business delegates
|
||||
> acts as an adaptor to invoke business objects from the presentation tier.
|
||||
>
|
||||
> 业务委托模式是一种 Java EE 设计模式。这种模式旨在减少业务服务和所连接的表现层之间的耦合度,并隐藏服务的实现细节(包括 EJB 架构的查询和可访问性)。业务代表作为一个适配器,从表现层调用业务对象。
|
||||
> 业务委托是一种Java EE设计模式。 该模式旨在减少业务服务与连接的表示层之间的耦合,并隐藏服务的实现细节(包括EJB体系结构的查找和可访问性)。 业务代表充当适配器,以从表示层调用业务对象。
|
||||
|
||||
**编程示例**
|
||||
**程序示例**
|
||||
|
||||
首先,我们实现了一个视频流服务的抽象,和几个具体实现。
|
||||
首先,我们有视频流服务的抽象类和一些它的实现。
|
||||
|
||||
```java
|
||||
public interface VideoStreamingService {
|
||||
@ -57,7 +53,7 @@ public class YouTubeService implements VideoStreamingService {
|
||||
}
|
||||
```
|
||||
|
||||
接下来,我们实现一个查询服务,用于决定使用哪个视频流服务。
|
||||
然后我们有一个查找服务来决定我们使用哪个视频流服务。
|
||||
|
||||
```java
|
||||
@Setter
|
||||
@ -76,7 +72,7 @@ public class BusinessLookup {
|
||||
}
|
||||
```
|
||||
|
||||
业务委托层使用业务查询,将电影播放请求路由到合适的视频流服务。
|
||||
业务委托类使用业务查找服务将电影播放请求路由到合适的视频流服务。
|
||||
|
||||
```java
|
||||
@Setter
|
||||
@ -108,7 +104,7 @@ public class MobileClient {
|
||||
}
|
||||
```
|
||||
|
||||
最后,我们展示一下这个示例完整的操作。
|
||||
最后我们展示完整示例。
|
||||
|
||||
```java
|
||||
public static void main(String[] args) {
|
||||
@ -127,7 +123,7 @@ public class MobileClient {
|
||||
}
|
||||
```
|
||||
|
||||
以下是终端输出的内容。
|
||||
这是控制台的输出。
|
||||
|
||||
```
|
||||
21:15:33.790 [main] INFO com.iluwatar.business.delegate.NetflixService - NetflixService is now processing
|
||||
@ -136,25 +132,25 @@ public class MobileClient {
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 相关模式
|
||||
|
||||
* [Service locator pattern](https://java-design-patterns.com/patterns/service-locator/)
|
||||
* [服务定位器模式](https://java-design-patterns.com/patterns/service-locator/)
|
||||
|
||||
## 适用场景
|
||||
## 适用性
|
||||
|
||||
业务委托模式的适用场景:
|
||||
使用业务委托模式当
|
||||
|
||||
* 你希望表现层和业务层之间是松耦合的。
|
||||
* 你想要协调对多个业务服务的调用。
|
||||
* 你想要对服务查询、服务调用进行封装。
|
||||
* 你希望表示层和业务层之间的松散耦合
|
||||
* 你想编排对多个业务服务的调用
|
||||
* 你希望封装查找服务和服务调用
|
||||
|
||||
## 教程
|
||||
|
||||
* [Business Delegate Pattern at TutorialsPoint](https://www.tutorialspoint.com/design_pattern/business_delegate_pattern.htm)
|
||||
|
||||
## 引用
|
||||
## 鸣谢
|
||||
|
||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
|
||||
* [Core J2EE Patterns: Best Practices and Design Strategies](https://www.amazon.com/gp/product/0130648841/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0130648841&linkId=a0100de2b28c71ede8db1757fb2b5947)
|
||||
|
235
localization/zh/bytecode/README.md
Normal file
235
localization/zh/bytecode/README.md
Normal file
@ -0,0 +1,235 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Bytecode
|
||||
folder: bytecode
|
||||
permalink: /patterns/bytecode/
|
||||
categories: Behavioral
|
||||
language: zh
|
||||
tags:
|
||||
- Game programming
|
||||
---
|
||||
|
||||
## 意图
|
||||
|
||||
允许编码行为作为虚拟机的指令。
|
||||
|
||||
## 解释
|
||||
|
||||
真实世界例子
|
||||
|
||||
> 一个团队正在开发一款新的巫师对战游戏。巫师的行为需要经过精心的调整和上百次的游玩测试。每次当游戏设计师想改变巫师行为时都让程序员去修改代码这是不妥的,所以巫师行为以数据驱动的虚拟机方式实现。
|
||||
|
||||
通俗地说
|
||||
|
||||
> 字节码模式支持由数据而不是代码驱动的行为。
|
||||
|
||||
[Gameprogrammingpatterns.com](https://gameprogrammingpatterns.com/bytecode.html) 中做了如下阐述:
|
||||
|
||||
> 指令集定义了可以执行的低级操作。一系列指令被编码为字节序列。虚拟机一次一条地执行这些指令,中间的值用栈处理。通过组合指令,可以定义复杂的高级行为。
|
||||
|
||||
**程序示例**
|
||||
|
||||
其中最重要的游戏对象是`巫师`类。
|
||||
|
||||
```java
|
||||
@AllArgsConstructor
|
||||
@Setter
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class Wizard {
|
||||
|
||||
private int health;
|
||||
private int agility;
|
||||
private int wisdom;
|
||||
private int numberOfPlayedSounds;
|
||||
private int numberOfSpawnedParticles;
|
||||
|
||||
public void playSound() {
|
||||
LOGGER.info("Playing sound");
|
||||
numberOfPlayedSounds++;
|
||||
}
|
||||
|
||||
public void spawnParticles() {
|
||||
LOGGER.info("Spawning particles");
|
||||
numberOfSpawnedParticles++;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
下面我们展示虚拟机可用的指令。每个指令对于如何操作栈中的数据都有自己的语义。例如,增加指令,其取得栈顶的两个元素并把结果压入栈中。
|
||||
|
||||
```java
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum Instruction {
|
||||
|
||||
LITERAL(1), // e.g. "LITERAL 0", push 0 to stack
|
||||
SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health
|
||||
SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
|
||||
SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
|
||||
PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
|
||||
SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
|
||||
GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
|
||||
GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
|
||||
GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
|
||||
ADD(10), // e.g. "ADD", pop 2 values, push their sum
|
||||
DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
我们示例的核心是`虚拟机`类。 它将指令作为输入并执行它们以提供游戏对象行为。
|
||||
|
||||
```java
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class VirtualMachine {
|
||||
|
||||
private final Stack<Integer> stack = new Stack<>();
|
||||
|
||||
private final Wizard[] wizards = new Wizard[2];
|
||||
|
||||
public VirtualMachine() {
|
||||
wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||
0, 0);
|
||||
wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||
0, 0);
|
||||
}
|
||||
|
||||
public VirtualMachine(Wizard wizard1, Wizard wizard2) {
|
||||
wizards[0] = wizard1;
|
||||
wizards[1] = wizard2;
|
||||
}
|
||||
|
||||
public void execute(int[] bytecode) {
|
||||
for (var i = 0; i < bytecode.length; i++) {
|
||||
Instruction instruction = Instruction.getInstruction(bytecode[i]);
|
||||
switch (instruction) {
|
||||
case LITERAL:
|
||||
// Read the next byte from the bytecode.
|
||||
int value = bytecode[++i];
|
||||
// Push the next value to stack
|
||||
stack.push(value);
|
||||
break;
|
||||
case SET_AGILITY:
|
||||
var amount = stack.pop();
|
||||
var wizard = stack.pop();
|
||||
setAgility(wizard, amount);
|
||||
break;
|
||||
case SET_WISDOM:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setWisdom(wizard, amount);
|
||||
break;
|
||||
case SET_HEALTH:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setHealth(wizard, amount);
|
||||
break;
|
||||
case GET_HEALTH:
|
||||
wizard = stack.pop();
|
||||
stack.push(getHealth(wizard));
|
||||
break;
|
||||
case GET_AGILITY:
|
||||
wizard = stack.pop();
|
||||
stack.push(getAgility(wizard));
|
||||
break;
|
||||
case GET_WISDOM:
|
||||
wizard = stack.pop();
|
||||
stack.push(getWisdom(wizard));
|
||||
break;
|
||||
case ADD:
|
||||
var a = stack.pop();
|
||||
var b = stack.pop();
|
||||
stack.push(a + b);
|
||||
break;
|
||||
case DIVIDE:
|
||||
a = stack.pop();
|
||||
b = stack.pop();
|
||||
stack.push(b / a);
|
||||
break;
|
||||
case PLAY_SOUND:
|
||||
wizard = stack.pop();
|
||||
getWizards()[wizard].playSound();
|
||||
break;
|
||||
case SPAWN_PARTICLES:
|
||||
wizard = stack.pop();
|
||||
getWizards()[wizard].spawnParticles();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid instruction value");
|
||||
}
|
||||
LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());
|
||||
}
|
||||
}
|
||||
|
||||
public void setHealth(int wizard, int amount) {
|
||||
wizards[wizard].setHealth(amount);
|
||||
}
|
||||
// other setters ->
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
现在我们可以展示使用虚拟机的完整示例。
|
||||
|
||||
```java
|
||||
public static void main(String[] args) {
|
||||
|
||||
var vm = new VirtualMachine(
|
||||
new Wizard(45, 7, 11, 0, 0),
|
||||
new Wizard(36, 18, 8, 0, 0));
|
||||
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH"));
|
||||
}
|
||||
```
|
||||
|
||||
下面是控制台输出。
|
||||
|
||||
```
|
||||
16:20:10.193 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0]
|
||||
16:20:10.196 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 0]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_HEALTH, Stack contains [0, 45]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 0]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_AGILITY, Stack contains [0, 45, 7]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 7, 0]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_WISDOM, Stack contains [0, 45, 7, 11]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 45, 18]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 18, 2]
|
||||
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed DIVIDE, Stack contains [0, 45, 9]
|
||||
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 54]
|
||||
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed SET_HEALTH, Stack contains []
|
||||
```
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||
|
||||
## 适用性
|
||||
|
||||
|
||||
|
||||
当您需要定义很多行为并且游戏的实现语言不合适时,请使用字节码模式,因为:
|
||||
|
||||
* 它的等级太低,使得编程变得乏味或容易出错。
|
||||
* 由于编译时间慢或其他工具问题,迭代它需要很长时间。
|
||||
* 它有太多的信任。 如果您想确保定义的行为不会破坏游戏,您需要将其与代码库的其余部分进行沙箱化。
|
||||
|
||||
## 相关模式
|
||||
|
||||
* [Interpreter](https://java-design-patterns.com/patterns/interpreter/)
|
||||
|
||||
## 鸣谢
|
||||
|
||||
* [Game programming patterns](http://gameprogrammingpatterns.com/bytecode.html)
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Caching
|
||||
folder: caching
|
||||
permalink: /patterns/caching/zh
|
||||
permalink: /patterns/caching/
|
||||
categories: Behavioral
|
||||
language: zh
|
||||
tags:
|
||||
@ -14,7 +14,7 @@ tags:
|
||||
为了避免昂贵的资源重新获取,方法是在资源使用后不立即释放资源。资源保留其身份,保留在某些快速访问的存储中,并被重新使用,以避免再次获取它们。
|
||||
|
||||
## 类图
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
在以下情况下使用缓存模式
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Callback
|
||||
folder: callback
|
||||
permalink: /patterns/callback/zh
|
||||
permalink: /patterns/callback/
|
||||
categories: Idiom
|
||||
language: zh
|
||||
tags:
|
||||
@ -69,7 +69,7 @@ public final class SimpleTask extends Task {
|
||||
task.executeWith(() -> LOGGER.info("I'm done now."));
|
||||
```
|
||||
## 类图
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
使用回调模式当
|
||||
|
@ -2,7 +2,7 @@
|
||||
layout: pattern
|
||||
title: Chain of responsibility
|
||||
folder: chain
|
||||
permalink: /patterns/chain/zh
|
||||
permalink: /patterns/chain/
|
||||
categories: Behavioral
|
||||
language: zh
|
||||
tags:
|
||||
@ -139,7 +139,7 @@ king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax")); // Orc so
|
||||
```
|
||||
|
||||
## 类图
|
||||

|
||||

|
||||
|
||||
## 适用性
|
||||
使用责任链模式当
|
||||
|
@ -4,39 +4,45 @@ title: Circuit Breaker
|
||||
folder: circuit-breaker
|
||||
permalink: /patterns/circuit-breaker/
|
||||
categories: Behavioral
|
||||
language: zh
|
||||
tags:
|
||||
- Performance
|
||||
- Decoupling
|
||||
- Cloud distributed
|
||||
---
|
||||
|
||||
## 含义
|
||||
## 意图
|
||||
|
||||
以这样的方式(译者:指断路器方式)处理昂贵的远程服务调用,可以防止单个服务/组件的故障导致整个应用程序崩溃,同时我们可以尽快地进行服务重连。
|
||||
以这样一种方式处理昂贵的远程服务调用,即单个服务/组件的故障不会导致整个应用程序宕机,我们可以尽快重新连接到服务。
|
||||
|
||||
## 解释
|
||||
|
||||
现实世界案例
|
||||
真实世界例子
|
||||
|
||||
> 设想一下,一个网络应用程序既有本地文件/图像,又有用于获取数据的远程服务。这些远程服务可能在某些时候是健康的、有反应的,也可能在某些时候由于各种原因而变得缓慢和无反应。因此,如果其中一个远程服务速度慢或不能成功响应,我们的应用程序将尝试使用多个线程/进程从远程服务中获取响应,很快所有的线程/进程都会挂起(也称为线程饥饿 thread starvation),从而导致我们整个 Web 应用程序崩溃。我们应该能够检测到这种情况,并向用户显示一个适当的信息,以便用户可以探索应用程序的其他部分,而不受远程服务故障的影响。同时,其他正常工作的服务应该保持运作,不受这次故障的影响。
|
||||
> 想象一个 Web 应用程序,它同时具有用于获取数据的本地文件/图像和远程服务。 这些远程服务有时可能健康且响应迅速,或者由于各种原因可能在某 个时间点变得缓慢和无响应。因此,如果其中一个远程服务缓慢或未成功响应,我们的应用程序将尝试使用多个线程/进程从远程服务获取响应,很快它们都会挂起(也称为 [线程饥饿][thread starvation](https://en.wikipedia.org/wiki/Starvation_(computer_science)))导致我们的整个 Web 应用程序崩溃。我们应该能够检测到这种情况并向用户显示适当的消息,以便他/她可以探索不受远程服务故障影响的应用程序的其他部分。 同时,其他正常工作的服务应保持正常运行,不受此故障的影响。
|
||||
>
|
||||
|
||||
简而言之
|
||||
通俗地说
|
||||
|
||||
> 断路器允许优雅地处理失败的远程服务。当我们的应用程序的所有部分都高度解耦时,这种方式的效果会很好,一个组件的失败并不会导致其他部分停止工作。
|
||||
> 断路器允许优雅地处理失败的远程服务。当我们应用程序的所有部分彼此高度解耦时,它特别有用,一个组件的故障并不意味着其他部分将停止工作。
|
||||
|
||||
维基百科的解释
|
||||
维基百科说
|
||||
|
||||
> 断路器是现代软件开发中使用的一种设计模式。它用于检测故障,并封装了防止故障不断复发的逻辑,在维护期间,临时地处理外部系统故障或意外的系统问题。
|
||||
> 断路器是现代软件开发中使用的一种设计模式。 它用于检测故障并封装防止故障不断重复发生、维护期间、临时外部系统故障或意外系统困难的逻辑。
|
||||
|
||||
## Programmatic Example
|
||||
## 程序示例
|
||||
|
||||
那么,这一切是如何实现的呢?考虑到上面的例子,我们将在一个简单的例子中模拟这个功能。一个监控服务(译者:下图的 Monitoring Service)模拟了网络应用,进行本地和远程调用。
|
||||
So, how does this all come together? With the above example in mind we will imitate the
|
||||
functionality in a simple example. A monitoring service mimics the web app and makes both local and
|
||||
remote calls.
|
||||
|
||||
该服务架构如下:
|
||||
那么,这一切是如何结合在一起的呢? 记住上面的例子,我们将在一个简单的例子中模仿这个功能。 监控服务模仿 Web 应用程序并进行本地和远程调用。
|
||||
|
||||

|
||||
服务架构如下:
|
||||
|
||||
终端用户(译者:上图的 End User)应用的代码如下:
|
||||

|
||||
|
||||
在代码方面,最终用户应用程序是:
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@ -61,44 +67,44 @@ public class App {
|
||||
var quickServiceCircuitBreaker = new DefaultCircuitBreaker(quickService, 3000, 2,
|
||||
2000 * 1000 * 1000);
|
||||
|
||||
//Create an object of monitoring service which makes both local and remote calls
|
||||
// 创建一个可以进行本地和远程调用的监控服务对象
|
||||
var monitoringService = new MonitoringService(delayedServiceCircuitBreaker,
|
||||
quickServiceCircuitBreaker);
|
||||
|
||||
//Fetch response from local resource
|
||||
// 获取本地资源
|
||||
LOGGER.info(monitoringService.localResourceResponse());
|
||||
|
||||
//Fetch response from delayed service 2 times, to meet the failure threshold
|
||||
// 从延迟服务中获取响应 2 次,以满足失败阈值
|
||||
LOGGER.info(monitoringService.delayedServiceResponse());
|
||||
LOGGER.info(monitoringService.delayedServiceResponse());
|
||||
|
||||
//Fetch current state of delayed service circuit breaker after crossing failure threshold limit
|
||||
//which is OPEN now
|
||||
// 在超过故障阈值限制后获取延迟服务断路器的当前状态
|
||||
// 现在是打开状态
|
||||
LOGGER.info(delayedServiceCircuitBreaker.getState());
|
||||
|
||||
//Meanwhile, the delayed service is down, fetch response from the healthy quick service
|
||||
// 同时,延迟服务宕机,从健康快速服务获取响应
|
||||
LOGGER.info(monitoringService.quickServiceResponse());
|
||||
LOGGER.info(quickServiceCircuitBreaker.getState());
|
||||
|
||||
//Wait for the delayed service to become responsive
|
||||
// 等待延迟的服务响应
|
||||
try {
|
||||
LOGGER.info("Waiting for delayed service to become responsive");
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//Check the state of delayed circuit breaker, should be HALF_OPEN
|
||||
// 检查延时断路器的状态,应该是HALF_OPEN
|
||||
LOGGER.info(delayedServiceCircuitBreaker.getState());
|
||||
|
||||
//Fetch response from delayed service, which should be healthy by now
|
||||
// 从延迟服务中获取响应,现在应该是健康的
|
||||
LOGGER.info(monitoringService.delayedServiceResponse());
|
||||
//As successful response is fetched, it should be CLOSED again.
|
||||
// 获取成功响应后,它的状态应该是关闭。
|
||||
LOGGER.info(delayedServiceCircuitBreaker.getState());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
监控服务代码(译者:上图的 monitoring service):
|
||||
监控服务类:
|
||||
|
||||
```java
|
||||
public class MonitoringService {
|
||||
@ -112,7 +118,7 @@ public class MonitoringService {
|
||||
this.quickService = quickService;
|
||||
}
|
||||
|
||||
//Assumption: Local service won't fail, no need to wrap it in a circuit breaker logic
|
||||
// 假设:本地服务不会失败,无需将其包装在断路器逻辑中
|
||||
public String localResourceResponse() {
|
||||
return "Local Service is working";
|
||||
}
|
||||
@ -144,7 +150,7 @@ public class MonitoringService {
|
||||
}
|
||||
}
|
||||
```
|
||||
可以看出,它直接进行了获取本地资源的调用,但它把对远程(昂贵的)服务的调用包装在一个断路器对象中,这样可以防止出现如下故障:
|
||||
可以看出,它直接调用获取本地资源,但它将对远程(昂贵)服务的调用包装在断路器对象中,防止故障如下:
|
||||
|
||||
```java
|
||||
public class DefaultCircuitBreaker implements CircuitBreaker {
|
||||
@ -171,11 +177,11 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
|
||||
DefaultCircuitBreaker(RemoteService serviceToCall, long timeout, int failureThreshold,
|
||||
long retryTimePeriod) {
|
||||
this.service = serviceToCall;
|
||||
// We start in a closed state hoping that everything is fine
|
||||
// 我们从关闭状态开始希望一切都是正常的
|
||||
this.state = State.CLOSED;
|
||||
this.failureThreshold = failureThreshold;
|
||||
// Timeout for the API request.
|
||||
// Used to break the calls made to remote resource if it exceeds the limit
|
||||
// API的超时时间.
|
||||
// 用于在超过限制时中断对远程资源的调用
|
||||
this.timeout = timeout;
|
||||
this.retryTimePeriod = retryTimePeriod;
|
||||
//An absurd amount of time in future which basically indicates the last failure never happened
|
||||
@ -183,7 +189,7 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
|
||||
this.failureCount = 0;
|
||||
}
|
||||
|
||||
// Reset everything to defaults
|
||||
// 重置所有
|
||||
@Override
|
||||
public void recordSuccess() {
|
||||
this.failureCount = 0;
|
||||
@ -199,18 +205,18 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
|
||||
this.lastFailureResponse = response;
|
||||
}
|
||||
|
||||
// Evaluate the current state based on failureThreshold, failureCount and lastFailureTime.
|
||||
// 根据 failureThreshold、failureCount 和 lastFailureTime 评估当前状态。
|
||||
protected void evaluateState() {
|
||||
if (failureCount >= failureThreshold) { //Then something is wrong with remote service
|
||||
if ((System.nanoTime() - lastFailureTime) > retryTimePeriod) {
|
||||
//We have waited long enough and should try checking if service is up
|
||||
// 我们已经等得够久了,应该尝试检查服务是否已启动
|
||||
state = State.HALF_OPEN;
|
||||
} else {
|
||||
//Service would still probably be down
|
||||
// 服务可能仍会出现故障
|
||||
state = State.OPEN;
|
||||
}
|
||||
} else {
|
||||
//Everything is working fine
|
||||
// 一切正常
|
||||
state = State.CLOSED;
|
||||
}
|
||||
}
|
||||
@ -253,16 +259,15 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
|
||||
public String attemptRequest() throws RemoteServiceException {
|
||||
evaluateState();
|
||||
if (state == State.OPEN) {
|
||||
// return cached response if the circuit is in OPEN state
|
||||
// 如果电路处于打开状态,则返回缓存的响应
|
||||
return this.lastFailureResponse;
|
||||
} else {
|
||||
// Make the API request if the circuit is not OPEN
|
||||
// 如果电路未打开,则发出 API 请求
|
||||
try {
|
||||
//In a real application, this would be run in a thread and the timeout
|
||||
//parameter of the circuit breaker would be utilized to know if service
|
||||
//is working. Here, we simulate that based on server response itself
|
||||
//在实际应用程序中,这将在线程中运行,并且将利用断路器的超时参数来了解服务
|
||||
// 是否正在工作。 在这里,我们根据服务器响应本身模拟
|
||||
var response = service.call();
|
||||
// Yay!! the API responded fine. Let's reset everything.
|
||||
// api 响应正常,重置所有。
|
||||
recordSuccess();
|
||||
return response;
|
||||
} catch (RemoteServiceException ex) {
|
||||
@ -274,39 +279,39 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
|
||||
}
|
||||
```
|
||||
|
||||
上述模式是如何防止失败的呢?让我们通过它所实现的这个有限状态机来了解。
|
||||
上述模式如何防止失败? 让我们通过它实现的这个有限状态机来理解。
|
||||
|
||||

|
||||

|
||||
|
||||
- 我们用 `timeout`(超时)、 `failureThreshold` (失败阈值)、`retryTimePeriod`(重试时间周期) 参数初始化断路器对象 ,用于确定 API 的适应性。
|
||||
- 最初,断路器处于 `closed` 关闭状态,没有发生对 API 的远程调用。
|
||||
- 每次调用成功,我们就把状态重置为开始时的样子。
|
||||
- 如果失败的次数超过了一定的阈值(`failureThreshold`),断路器就会进入 `open` 开启状态,它的作用就像一个开启的电路,阻止远程服务的调用,从而节省资源。
|
||||
- 一旦我们超过重试时间周期(`retryTimePeriod`),断路器就会转到 `half-open` 半启用状态,并再次调用远程服务,检查服务是否正常,以便我们可以提供最新的响应内容。如果远程服务调用失败会使断路器回到 `open` 状态,并在重试超时后进行另一次尝试;如果远程服务调用成功则使断路器进入 `closed` 状态,这样一切又开始正常工作。
|
||||
- 我们使用某些参数初始化断路器对象:`timeout`、`failureThreshold` 和 `retryTimePeriod`,这有助于确定 API 的弹性。
|
||||
- 最初,我们处于“关闭”状态,没有发生对 API 的远程调用。
|
||||
- 每次调用成功时,我们都会将状态重置为开始时的状态。
|
||||
- 如果失败次数超过某个阈值,我们将进入“open”状态,这就像开路一样,阻止远程服务调用,从而节省资源。 (这里,我们从 API 返回名为 ```stale response``` 的响应)
|
||||
- 一旦超过重试超时时间,我们就会进入“半开”状态并再次调用远程服务以检查服务是否正常工作,以便我们可以提供新鲜内容。 失败将其设置回“打开”状态,并在重试超时时间后进行另一次尝试,而成功将其设置为“关闭”状态,以便一切重新开始正常工作。
|
||||
|
||||
## 类图
|
||||
|
||||

|
||||

|
||||
|
||||
## 适用场景
|
||||
## 适用性
|
||||
|
||||
在以下场景下,可以使用断路器模式:
|
||||
在以下情况下使用断路器模式
|
||||
|
||||
- 构建一个高可用的应用程序,某些些服务的失败不会导致整个应用程序的崩溃。
|
||||
- 构建一个持续运行(长期在线)的应用程序,以便其组件可以在不完全关闭的情况下进行升级。
|
||||
- 构建一个容错应用程序,其中某些服务的故障不应导致整个应用程序宕机。
|
||||
- 构建一个持续运行(永远在线)的应用程序,这样它的组件就可以在不完全关闭的情况下升级。
|
||||
|
||||
## 相关模式
|
||||
|
||||
- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry)
|
||||
|
||||
## 现实案例
|
||||
## 真实世界例子
|
||||
|
||||
* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker)
|
||||
* [Netflix Hystrix API](https://github.com/Netflix/Hystrix)
|
||||
|
||||
## 引用
|
||||
## 鸣谢
|
||||
|
||||
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
|
||||
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
|
||||
* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a)
|
||||
* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
|
||||
* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user