Compare commits
31 Commits
bytecode-e
...
all-contri
Author | SHA1 | Date | |
---|---|---|---|
d1e5a22448 | |||
38e183bc00 | |||
32b33480dd | |||
068fa0371e | |||
b5aaa94794 | |||
825b5a9a29 | |||
31890f67e6 | |||
41b1462eed | |||
276549d156 | |||
d67b625a74 | |||
1b14ebcbb1 | |||
a471ce25da | |||
74caa0c4e5 | |||
53a294fee5 | |||
a5062908c0 | |||
076310bb79 | |||
470d29e715 | |||
74802e83b5 | |||
09b577f634 | |||
2fce2e44e2 | |||
b3a1749bd0 | |||
af0ccdc6e1 | |||
323dd63e66 | |||
be3250bd0d | |||
1222f12b99 | |||
965d38f139 | |||
eb8f9db575 | |||
6d7084f18d | |||
74f5cfa670 | |||
b525d871b4 | |||
c413e0902e |
@ -1132,7 +1132,8 @@
|
||||
"profile": "http://subho.xyz",
|
||||
"contributions": [
|
||||
"code",
|
||||
"review"
|
||||
"review",
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1440,6 +1441,61 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jinishavora",
|
||||
"name": "jinishavora",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/40777762?v=4",
|
||||
"profile": "https://www.linkedin.com/in/jinisha-vora",
|
||||
"contributions": [
|
||||
"review",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "eas5",
|
||||
"name": "Elvys Soares",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/50836521?v=4",
|
||||
"profile": "https://github.com/eas5",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zWeBrain",
|
||||
"name": "zWeBrain",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/46642512?v=4",
|
||||
"profile": "https://github.com/zWeBrain",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Al-assad",
|
||||
"name": "余林颖",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/22493821?v=4",
|
||||
"profile": "https://al-assad.github.io/notion/",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "STudio26",
|
||||
"name": "Alain",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6988911?v=4",
|
||||
"profile": "https://github.com/STudio26",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "DEV-VRUPER",
|
||||
"name": "VR",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/30525467?v=4",
|
||||
"profile": "https://github.com/DEV-VRUPER",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
9
.github/workflows/maven-ci.yml
vendored
9
.github/workflows/maven-ci.yml
vendored
@ -40,25 +40,26 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# Disabling shallow clone for improving relevancy of SonarQube reporting
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@master
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'adopt'
|
||||
|
||||
- name: Cache SonarCloud packages
|
||||
uses: actions/cache@master
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.sonar/cache
|
||||
key: ${{ runner.os }}-sonar
|
||||
restore-keys: ${{ runner.os }}-sonar
|
||||
|
||||
- name: Cache Maven dependencies
|
||||
uses: actions/cache@master
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
|
9
.github/workflows/maven-pr-builder.yml
vendored
9
.github/workflows/maven-pr-builder.yml
vendored
@ -29,7 +29,7 @@ name: Java PR Builder
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
types: [ opened, reopened, synchronize, labeled, unlabeled ]
|
||||
types: [ opened, reopened, synchronize ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -38,15 +38,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@master
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'adopt'
|
||||
|
||||
- name: Cache Maven Dependecies
|
||||
uses: actions/cache@master
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
|
12
README.md
12
README.md
@ -10,7 +10,7 @@
|
||||
[](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/>
|
||||
@ -259,7 +259,7 @@ This project is licensed under the terms of the MIT license.
|
||||
<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></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>
|
||||
@ -312,6 +312,14 @@ This project is licensed under the terms of the MIT license.
|
||||
<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>
|
||||
</table>
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>abstract-document</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>abstract-factory</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>active-object</artifactId>
|
||||
<dependencies>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>acyclic-visitor</artifactId>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>adapter</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>aggregator-service</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>inventory-microservice</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ambassador</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>api-gateway-service</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>image-microservice</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>async-method-invocation</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bridge</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>builder</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>business-delegate</artifactId>
|
||||
<dependencies>
|
||||
|
@ -9,18 +9,234 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
Allows to encode behaviour as instructions for virtual machine.
|
||||
|
||||
Allows encoding behavior as instructions for a virtual machine.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> A team is working on a new game where wizards battle against each other. The wizard behavior
|
||||
> needs to be carefully adjusted and iterated hundreds of times through playtesting. It's not
|
||||
> optimal to ask the programmer to make changes each time the game designer wants to vary the
|
||||
> behavior, so the wizard behavior is implemented as a data-driven virtual machine.
|
||||
|
||||
In plain words
|
||||
|
||||
> Bytecode pattern enables behavior driven by data instead of code.
|
||||
|
||||
[Gameprogrammingpatterns.com](https://gameprogrammingpatterns.com/bytecode.html) documentation
|
||||
states:
|
||||
|
||||
> An instruction set defines the low-level operations that can be performed. A series of
|
||||
> instructions is encoded as a sequence of bytes. A virtual machine executes these instructions one
|
||||
> at a time, using a stack for intermediate values. By combining instructions, complex high-level
|
||||
> behavior can be defined.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
One of the most important game objects is the `Wizard` class.
|
||||
|
||||
```java
|
||||
@AllArgsConstructor
|
||||
@Setter
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class Wizard {
|
||||
|
||||
private int health;
|
||||
private int agility;
|
||||
private int wisdom;
|
||||
private int numberOfPlayedSounds;
|
||||
private int numberOfSpawnedParticles;
|
||||
|
||||
public void playSound() {
|
||||
LOGGER.info("Playing sound");
|
||||
numberOfPlayedSounds++;
|
||||
}
|
||||
|
||||
public void spawnParticles() {
|
||||
LOGGER.info("Spawning particles");
|
||||
numberOfSpawnedParticles++;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Next, we show the available instructions for our virtual machine. Each of the instructions has its
|
||||
own semantics on how it operates with the stack data. For example, the ADD instruction takes the top
|
||||
two items from the stack, adds them together and pushes the result to the stack.
|
||||
|
||||
```java
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum Instruction {
|
||||
|
||||
LITERAL(1), // e.g. "LITERAL 0", push 0 to stack
|
||||
SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health
|
||||
SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
|
||||
SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
|
||||
PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
|
||||
SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
|
||||
GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
|
||||
GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
|
||||
GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
|
||||
ADD(10), // e.g. "ADD", pop 2 values, push their sum
|
||||
DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
At the heart of our example is the `VirtualMachine` class. It takes instructions as input and
|
||||
executes them to provide the game object behavior.
|
||||
|
||||
```java
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class VirtualMachine {
|
||||
|
||||
private final Stack<Integer> stack = new Stack<>();
|
||||
|
||||
private final Wizard[] wizards = new Wizard[2];
|
||||
|
||||
public VirtualMachine() {
|
||||
wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||
0, 0);
|
||||
wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
|
||||
0, 0);
|
||||
}
|
||||
|
||||
public VirtualMachine(Wizard wizard1, Wizard wizard2) {
|
||||
wizards[0] = wizard1;
|
||||
wizards[1] = wizard2;
|
||||
}
|
||||
|
||||
public void execute(int[] bytecode) {
|
||||
for (var i = 0; i < bytecode.length; i++) {
|
||||
Instruction instruction = Instruction.getInstruction(bytecode[i]);
|
||||
switch (instruction) {
|
||||
case LITERAL:
|
||||
// Read the next byte from the bytecode.
|
||||
int value = bytecode[++i];
|
||||
// Push the next value to stack
|
||||
stack.push(value);
|
||||
break;
|
||||
case SET_AGILITY:
|
||||
var amount = stack.pop();
|
||||
var wizard = stack.pop();
|
||||
setAgility(wizard, amount);
|
||||
break;
|
||||
case SET_WISDOM:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setWisdom(wizard, amount);
|
||||
break;
|
||||
case SET_HEALTH:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setHealth(wizard, amount);
|
||||
break;
|
||||
case GET_HEALTH:
|
||||
wizard = stack.pop();
|
||||
stack.push(getHealth(wizard));
|
||||
break;
|
||||
case GET_AGILITY:
|
||||
wizard = stack.pop();
|
||||
stack.push(getAgility(wizard));
|
||||
break;
|
||||
case GET_WISDOM:
|
||||
wizard = stack.pop();
|
||||
stack.push(getWisdom(wizard));
|
||||
break;
|
||||
case ADD:
|
||||
var a = stack.pop();
|
||||
var b = stack.pop();
|
||||
stack.push(a + b);
|
||||
break;
|
||||
case DIVIDE:
|
||||
a = stack.pop();
|
||||
b = stack.pop();
|
||||
stack.push(b / a);
|
||||
break;
|
||||
case PLAY_SOUND:
|
||||
wizard = stack.pop();
|
||||
getWizards()[wizard].playSound();
|
||||
break;
|
||||
case SPAWN_PARTICLES:
|
||||
wizard = stack.pop();
|
||||
getWizards()[wizard].spawnParticles();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid instruction value");
|
||||
}
|
||||
LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());
|
||||
}
|
||||
}
|
||||
|
||||
public void setHealth(int wizard, int amount) {
|
||||
wizards[wizard].setHealth(amount);
|
||||
}
|
||||
// other setters ->
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Now we can show the full example utilizing the virtual machine.
|
||||
|
||||
```java
|
||||
public static void main(String[] args) {
|
||||
|
||||
var vm = new VirtualMachine(
|
||||
new Wizard(45, 7, 11, 0, 0),
|
||||
new Wizard(36, 18, 8, 0, 0));
|
||||
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
|
||||
vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH"));
|
||||
}
|
||||
```
|
||||
|
||||
Here is the console output.
|
||||
|
||||
```
|
||||
16:20:10.193 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0]
|
||||
16:20:10.196 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 0]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_HEALTH, Stack contains [0, 45]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 0]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_AGILITY, Stack contains [0, 45, 7]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 7, 0]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_WISDOM, Stack contains [0, 45, 7, 11]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 45, 18]
|
||||
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 18, 2]
|
||||
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed DIVIDE, Stack contains [0, 45, 9]
|
||||
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 54]
|
||||
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed SET_HEALTH, Stack contains []
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

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

|
||||
|
||||
## Applicability
|
||||
|
||||
Use the Caching pattern(s) when
|
||||
|
||||
* Repetitious acquisition, initialization, and release of the same resource causes unnecessary performance overhead.
|
||||
* Repetitious acquisition, initialization, and release of the same resource cause unnecessary
|
||||
performance overhead.
|
||||
|
||||
## Related patterns
|
||||
|
||||
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
|
||||
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
|
||||
* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
|
||||
* [Java EE 8 High Performance: Master techniques such as memory optimization, caching, concurrency, and multithreading to achieve maximum performance from your enterprise applications](https://www.amazon.com/gp/product/178847306X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=178847306X&linkId=e948720055599f248cdac47da9125ff4)
|
||||
* [Java Performance: In-Depth Advice for Tuning and Programming Java 8, 11, and Beyond](https://www.amazon.com/gp/product/1492056111/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1492056111&linkId=7e553581559b9ec04221259e52004b08)
|
||||
* [Effective Java](https://www.amazon.com/gp/product/B078H61SCH/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B078H61SCH&linkId=f06607a0b48c76541ef19c5b8b9e7882)
|
||||
* [Java Performance: The Definitive Guide: Getting the Most Out of Your Code](https://www.amazon.com/gp/product/1449358454/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1449358454&linkId=475c18363e350630cc0b39ab681b2687)
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>caching</artifactId>
|
||||
<dependencies>
|
||||
|
@ -25,6 +25,7 @@ package com.iluwatar.caching;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Optional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* AppManager helps to bridge the gap in communication between the main class and the application's
|
||||
@ -33,6 +34,7 @@ import java.util.Optional;
|
||||
* Depending on the chosen caching policy, AppManager will call the appropriate function in the
|
||||
* CacheStore class.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class AppManager {
|
||||
|
||||
private static CachingPolicy cachingPolicy;
|
||||
@ -50,7 +52,7 @@ public final class AppManager {
|
||||
try {
|
||||
DbManager.connect();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error connecting to MongoDB", e);
|
||||
}
|
||||
} else {
|
||||
DbManager.createVirtualDb();
|
||||
|
@ -30,6 +30,7 @@ import com.mongodb.client.model.UpdateOptions;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
@ -41,6 +42,7 @@ import org.bson.Document;
|
||||
* underlying data storage (connect()) or a simple Java data structure to (temporarily) store the
|
||||
* data/objects during runtime (createVirtualDB()).</p>
|
||||
*/
|
||||
@Slf4j
|
||||
public final class DbManager {
|
||||
|
||||
private static MongoClient mongoClient;
|
||||
@ -83,7 +85,7 @@ public final class DbManager {
|
||||
try {
|
||||
connect();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error connecting to MongoDB", e);
|
||||
}
|
||||
}
|
||||
var iterable = db
|
||||
@ -110,7 +112,7 @@ public final class DbManager {
|
||||
try {
|
||||
connect();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error connecting to MongoDB", e);
|
||||
}
|
||||
}
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).insertOne(
|
||||
@ -132,7 +134,7 @@ public final class DbManager {
|
||||
try {
|
||||
connect();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error connecting to MongoDB", e);
|
||||
}
|
||||
}
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).updateOne(
|
||||
@ -153,7 +155,7 @@ public final class DbManager {
|
||||
try {
|
||||
connect();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error connecting to MongoDB", e);
|
||||
}
|
||||
}
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).updateOne(
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>callback</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>chain</artifactId>
|
||||
<dependencies>
|
||||
|
@ -27,7 +27,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>circuit-breaker</artifactId>
|
||||
<dependencies>
|
||||
|
@ -27,7 +27,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collection-pipeline</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>combinator</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>command</artifactId>
|
||||
<dependencies>
|
||||
|
@ -27,7 +27,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>commander</artifactId>
|
||||
<dependencies>
|
||||
|
122
composite-entity/README.md
Normal file
122
composite-entity/README.md
Normal file
@ -0,0 +1,122 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Composite Entity
|
||||
folder: composite-entity
|
||||
permalink: /patterns/composite-entity/
|
||||
categories: Structural
|
||||
tags:
|
||||
- Enterprise Integration Pattern
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
It is used to model, represent, and manage a set of persistent objects that are interrelated, rather than representing them as individual fine-grained entities.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> For a console, there may be many interfaces that need to be managed and controlled. Using the composite entity pattern, dependent objects such as messages and signals can be combined together and controlled using a single object.
|
||||
|
||||
In plain words
|
||||
|
||||
> Composite entity pattern allows a set of related objects to be represented and managed by a unified object.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
We need a generic solution for the problem. To achieve this, let's introduce a generic
|
||||
Composite Entity Pattern.
|
||||
|
||||
```java
|
||||
public abstract class DependentObject<T> {
|
||||
|
||||
T data;
|
||||
|
||||
public void setData(T message) {
|
||||
this.data = message;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class CoarseGrainedObject<T> {
|
||||
|
||||
DependentObject<T>[] dependentObjects;
|
||||
|
||||
public void setData(T... data) {
|
||||
IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i]));
|
||||
}
|
||||
|
||||
public T[] getData() {
|
||||
return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The specialized composite entity `console` inherit from this base class as follows.
|
||||
|
||||
```java
|
||||
public class MessageDependentObject extends DependentObject<String> {
|
||||
|
||||
}
|
||||
|
||||
public class SignalDependentObject extends DependentObject<String> {
|
||||
|
||||
}
|
||||
|
||||
public class ConsoleCoarseGrainedObject extends CoarseGrainedObject<String> {
|
||||
|
||||
@Override
|
||||
public String[] getData() {
|
||||
super.getData();
|
||||
return new String[]{
|
||||
dependentObjects[0].getData(), dependentObjects[1].getData()
|
||||
};
|
||||
}
|
||||
|
||||
public void init() {
|
||||
dependentObjects = new DependentObject[]{
|
||||
new MessageDependentObject(), new SignalDependentObject()};
|
||||
}
|
||||
}
|
||||
|
||||
public class CompositeEntity {
|
||||
|
||||
private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject();
|
||||
|
||||
public void setData(String message, String signal) {
|
||||
console.setData(message, signal);
|
||||
}
|
||||
|
||||
public String[] getData() {
|
||||
return console.getData();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now managing the assignment of message and signal objects with the composite entity `console`.
|
||||
|
||||
```java
|
||||
var console = new CompositeEntity();
|
||||
console.init();
|
||||
console.setData("No Danger", "Green Light");
|
||||
Arrays.stream(console.getData()).forEach(LOGGER::info);
|
||||
console.setData("Danger", "Red Light");
|
||||
Arrays.stream(console.getData()).forEach(LOGGER::info);
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Use the Composite Entity Pattern in the following situation:
|
||||
|
||||
* You want to manage multiple dependency objects through one object to adjust the degree of granularity between objects. At the same time, the lifetime of dependency objects depends on a coarse-grained object.
|
||||
## Credits
|
||||
|
||||
* [Composite Entity Pattern in wikipedia](https://en.wikipedia.org/wiki/Composite_entity_pattern)
|
45
composite-entity/etc/composite-entity.urm.puml
Normal file
45
composite-entity/etc/composite-entity.urm.puml
Normal file
@ -0,0 +1,45 @@
|
||||
@startuml
|
||||
package com.iluwatar.compositeentity {
|
||||
class App {
|
||||
+ App(message: String, signal: String)
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
class CompositeEntity{
|
||||
- console : ConsoleCoarseGrainedObject
|
||||
+ CompositeEntity()
|
||||
+ setData(message: String, signal: String)
|
||||
+ getData()
|
||||
+ init()
|
||||
}
|
||||
abstract CoarseGrainedObject{
|
||||
- dependentObjects : DependentObject[]
|
||||
+ CoarseGrainedObject()
|
||||
+ setData(data: T[])
|
||||
+ getData()
|
||||
}
|
||||
abstract DependentObject{
|
||||
- data : T
|
||||
+ DependentObject()
|
||||
+ setData(data: T)
|
||||
+ getData()
|
||||
}
|
||||
class ConsoleCoarseGrainedObject{
|
||||
+ ConsoleCoarseGrainedObject()
|
||||
+ getData()
|
||||
+ init()
|
||||
}
|
||||
class MessageDependentObject{
|
||||
+ MessageDependentObject()
|
||||
}
|
||||
class SignalDependentObject{
|
||||
+ SignalDependentObject()
|
||||
}
|
||||
|
||||
MessageDependentObject --|> DependentObject
|
||||
SignalDependentObject --|> DependentObject
|
||||
ConsoleCoarseGrainedObject --|> CoarseGrainedObject
|
||||
CompositeEntity -right-> ConsoleCoarseGrainedObject
|
||||
CoarseGrainedObject "1" o--> "0.." DependentObject
|
||||
App .right.> CompositeEntity
|
||||
}
|
||||
@enduml
|
BIN
composite-entity/etc/composite_entity.urm.png
Normal file
BIN
composite-entity/etc/composite_entity.urm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 90 KiB |
39
composite-entity/pom.xml
Normal file
39
composite-entity/pom.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>composite-entity</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.composite-entity.com.iluwatar.compositeentity.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,38 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
/**
|
||||
* Composite entity is a Java EE Software design pattern and it is used to model, represent, and
|
||||
* manage a set of interrelated persistent objects rather than representing them as individual
|
||||
* fine-grained entity beans, and also a composite entity bean represents a graph of objects.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
|
||||
/**
|
||||
* An instance that a console manages two related objects.
|
||||
*/
|
||||
public App(String message, String signal) {
|
||||
var console = new CompositeEntity();
|
||||
console.init();
|
||||
console.setData(message, signal);
|
||||
Arrays.stream(console.getData()).forEach(LOGGER::info);
|
||||
console.setData("Danger", "Red Light");
|
||||
Arrays.stream(console.getData()).forEach(LOGGER::info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
new App("No Danger", "Green Light");
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* A coarse-grained object is an object with its own life cycle manages its own relationships to
|
||||
* other objects. It can be an object contained in the composite entity, or, composite entity itself
|
||||
* can be the coarse-grained object which holds dependent objects.
|
||||
*/
|
||||
|
||||
public abstract class CoarseGrainedObject<T> {
|
||||
|
||||
DependentObject<T>[] dependentObjects;
|
||||
|
||||
public void setData(T... data) {
|
||||
IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i]));
|
||||
}
|
||||
|
||||
public T[] getData() {
|
||||
return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
/**
|
||||
* Composite entity is the coarse-grained entity bean which may be the coarse-grained object, or may
|
||||
* contain a reference to the coarse-grained object.
|
||||
*/
|
||||
|
||||
public class CompositeEntity {
|
||||
|
||||
private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject();
|
||||
|
||||
public void setData(String message, String signal) {
|
||||
console.setData(message, signal);
|
||||
}
|
||||
|
||||
public String[] getData() {
|
||||
return console.getData();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
console.init();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
/**
|
||||
* A specific CoarseGrainedObject to implement a console.
|
||||
*/
|
||||
|
||||
public class ConsoleCoarseGrainedObject extends CoarseGrainedObject<String> {
|
||||
|
||||
@Override
|
||||
public String[] getData() {
|
||||
return new String[]{
|
||||
dependentObjects[0].getData(), dependentObjects[1].getData()
|
||||
};
|
||||
}
|
||||
|
||||
public void init() {
|
||||
dependentObjects = new DependentObject[]{
|
||||
new MessageDependentObject(), new SignalDependentObject()};
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
/**
|
||||
* It is an object, which can contain other dependent objects (there may be a tree of objects within
|
||||
* the composite entity), that depends on the coarse-grained object and has its life cycle managed
|
||||
* by the coarse-grained object.
|
||||
*/
|
||||
|
||||
public abstract class DependentObject<T> {
|
||||
|
||||
T data;
|
||||
|
||||
public void setData(T message) {
|
||||
this.data = message;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
/**
|
||||
* The first DependentObject to show message.
|
||||
*/
|
||||
|
||||
public class MessageDependentObject extends DependentObject<String> {
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
/**
|
||||
* The second DependentObject to show message.
|
||||
*/
|
||||
|
||||
public class SignalDependentObject extends DependentObject<String> {
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* com.iluwatar.compositeentity.App running test
|
||||
*/
|
||||
class AppTest {
|
||||
|
||||
/**
|
||||
* Issue: Add at least one assertion to this test case.
|
||||
* <p>
|
||||
* Solution: Inserted assertion to check whether the execution of the main method in {@link
|
||||
* App#main(String[])} throws an exception.
|
||||
*/
|
||||
|
||||
@Test
|
||||
void shouldExecuteApplicationWithoutException() {
|
||||
|
||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.iluwatar.compositeentity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PersistenceTest {
|
||||
|
||||
final static ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject();
|
||||
|
||||
@Test
|
||||
void dependentObjectChangedForPersistenceTest() {
|
||||
MessageDependentObject dependentObject = new MessageDependentObject();
|
||||
console.init();
|
||||
console.dependentObjects[0] = dependentObject;
|
||||
String message = "Danger";
|
||||
assertNull(console.dependentObjects[0].getData());
|
||||
dependentObject.setData(message);
|
||||
assertEquals(message, console.dependentObjects[0].getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
void coarseGrainedObjectChangedForPersistenceTest() {
|
||||
MessageDependentObject dependentObject = new MessageDependentObject();
|
||||
console.init();
|
||||
console.dependentObjects[0] = dependentObject;
|
||||
String message = "Danger";
|
||||
assertNull(console.dependentObjects[0].getData());
|
||||
console.setData(message);
|
||||
assertEquals(message, dependentObject.getData());
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>composite</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>converter</artifactId>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>cqrs</artifactId>
|
||||
<dependencies>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dao</artifactId>
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>data-bus</artifactId>
|
||||
<dependencies>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>data-locality</artifactId>
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>data-mapper</artifactId>
|
||||
<dependencies>
|
||||
|
@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>data-transfer-object</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>decorator</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dependency-injection</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,10 +29,10 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dirty-flag</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
<name>dirty-flag</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
<properties>
|
||||
|
@ -25,4 +25,4 @@ This pattern is one of those ones where you’ll know when you need it. If you h
|
||||
|
||||
## Credits
|
||||
|
||||
* [Game Programming Patterns - Double Buffer]([http://gameprogrammingpatterns.com/double-buffer.html](http://gameprogrammingpatterns.com/double-buffer.html))
|
||||
* [Game Programming Patterns - Double Buffer](http://gameprogrammingpatterns.com/double-buffer.html)
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>double-checked-locking</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>double-dispatch</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>eip-message-channel</artifactId>
|
||||
<dependencies>
|
||||
|
@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>eip-publish-subscribe</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>event-aggregator</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>event-asynchronous</artifactId>
|
||||
<dependencies>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>event-driven-architecture</artifactId>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>event-queue</artifactId>
|
||||
<dependencies>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>event-sourcing</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>execute-around</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>facade</artifactId>
|
||||
<dependencies>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>factory-kit</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>factory-method</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>factory</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>flux</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>flyweight</artifactId>
|
||||
<dependencies>
|
||||
|
62
fr/README.md
62
fr/README.md
@ -1,12 +1,12 @@
|
||||
<!-- Cette ligne doit restée vide pour des raisons de formatage
|
||||
afin qu'on puisse avoir un affichage agréable comme sur un
|
||||
afin qu’on puisse avoir un affichage agréable comme sur un
|
||||
site web par exemple -->
|
||||
|
||||
# Les patrons de conception implémentés en 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://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 -->
|
||||
@ -15,46 +15,56 @@
|
||||
|
||||
# Introduction
|
||||
|
||||
Le patron de conception est la meilleure formatalisation qu'un programmeur
|
||||
peut utiliser pour résoudre un problème lors d'une conception d'une application/system.
|
||||
Les patrons de conception (design patterns) sont les meilleures
|
||||
pratiques formalisées qu’un programmeur peut utiliser pour résoudre
|
||||
des problèmes courants lors de la conception d’une application
|
||||
ou d’un système.
|
||||
|
||||
Le patron de conception (design pattern) est là pour accélérer le processus de
|
||||
Les patrons de conception peuvent accélérer le processus de
|
||||
développement en fournissant des paradigmes éprouvés.
|
||||
|
||||
La réutilisation de patron de conception aide à prévenir des problèmes subtiles mais
|
||||
qui sont à l'origine de problèmes majeures, comme cette pratique augmente la lisibilitée
|
||||
du code par les développeurs/architectes familiers avec l'utilisation de ces concepts.
|
||||
La réutilisation de patrons de conception aide à se prémunir des problèmes subtils
|
||||
qui causent des problèmes majeurs, et cette pratique augmente la lisibilité
|
||||
du code pour les développeurs et architectes familiers de ces concepts.
|
||||
|
||||
# Commencer
|
||||
|
||||
Ce site présente des modèles de conception Java. Les solutions ont été développées par des
|
||||
développeurs et architectes expérimentés de la communauté open source. Les modèles peuvent être parcourus par leurs descriptions de haut niveau ou en regardant leur code source. Les exemples de code source sont bien commentés et peuvent être considérés comme tutoriels de programmation sur la façon d'implémenter un modèle spécifique. Nous utilisons le plus technologies Java open source éprouvées au combat.
|
||||
Ce site présente des patrons de conception Java. Les solutions ont été développées
|
||||
par des développeurs et architectes expérimentés de la communauté open source.
|
||||
Les modèles peuvent être parcourus par leurs descriptions de haut niveau ou
|
||||
en regardant leur code source.
|
||||
Les exemples de code source sont bien commentés et peuvent être considérés
|
||||
comme tutoriels de programmation sur la façon d’implémenter un modèle spécifique.
|
||||
Nous utilisons les technologies Java open source les plus populaires et éprouvées.
|
||||
|
||||
Avant de plonger dans le matériau, vous devez vous familiariser avec divers
|
||||
Avant de vous plonger dans le contenu, vous devriez vous familiariser avec divers
|
||||
[Principes de conception de logiciels](https://java-design-patterns.com/principles/).
|
||||
|
||||
Toutes les conceptions doivent être aussi simples que possible. Vous devriez commencer par KISS, YAGNI,
|
||||
et faire la chose la plus simple qui pourrait éventuellement fonctionner principes. Complexité et
|
||||
les modèles ne devraient être introduits que lorsqu'ils sont nécessaires pour
|
||||
extensibilité.
|
||||
Tous les modèles doivent être aussi simples que possible.
|
||||
Vous devriez commencer par les principes KISS, YAGNI et
|
||||
Faites La Chose La Plus Simple Qui Fonctionne.
|
||||
La complexité et les modèles ne devraient être introduits
|
||||
que lorsqu’ils sont nécessaires pour une extensibilité pratique.
|
||||
|
||||
Une fois que vous êtes familiarisé avec ces concepts, vous pouvez commencer à explorer
|
||||
[modèles de conception disponibles](https://java-design-patterns.com/patterns/) par tout
|
||||
des approches suivantes
|
||||
Une fois que vous êtes familiarisé avec ces concepts, vous pouvez commencer à explorer les
|
||||
[modèles de conception disponibles](https://java-design-patterns.com/patterns/)
|
||||
par n’importe laquelle les approches suivantes :
|
||||
|
||||
- Recherchez un modèle spécifique par son nom. Vous n'en trouvez pas? Veuillez signaler un nouveau modèle [ici](https://github.com/iluwatar/java-design-patterns/issues).
|
||||
- Utilisation de balises telles que `Performance`, `Gang of Four` ou `Data access`.
|
||||
- Utilisation des catégories de modèles, `Créatif`, `Comportemental` et autres.
|
||||
- Recherchez un modèle spécifique par son nom.
|
||||
Vous n’en trouvez pas ? Veuillez signaler un nouveau modèle [ici](https://github.com/iluwatar/java-design-patterns/issues).
|
||||
- Utilisation de balises telles que `Performance`, `Gang of Four` ou `Data access`.
|
||||
- Utilisation des catégories de modèles, `Creational`, `Behavioral` et autres.
|
||||
|
||||
J'espère que les solutions orientées objet présentées sur ce site vous seront utiles
|
||||
dans vos architectures et ayez autant de plaisir à les apprendre que nous en avons eu à les développer.
|
||||
Nous espérons que vous trouverez les solutions orientées objet présentées
|
||||
sur ce site utiles dans vos architectures et que vous aurez autant
|
||||
de plaisir à les apprendre que nous en avons eu à les développer.
|
||||
|
||||
# Comment contribuer
|
||||
|
||||
Si vous souhaitez contribuer au projet, vous trouverez les informations pertinentes dans
|
||||
notre [wiki développeur](https://github.com/iluwatar/java-design-patterns/wiki). Nous aiderons
|
||||
vous et répondez à vos questions dans le [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
|
||||
notre [wiki développeur](https://github.com/iluwatar/java-design-patterns/wiki).
|
||||
Nous vous aiderons répondrons à vos questions dans le [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
|
||||
|
||||
# Licence
|
||||
|
||||
Ce projet est concédé sous les termes de la licence MIT.
|
||||
Ce projet est concédé sous les termes de la licence MIT.
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>front-controller</artifactId>
|
||||
<dependencies>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>guarded-suspension</artifactId>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user