Compare commits
1 Commits
all-contri
...
fix-domain
Author | SHA1 | Date | |
---|---|---|---|
9b911ebecf |
@ -1568,15 +1568,6 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "karthikbhat13",
|
|
||||||
"name": "karthikbhat13",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/22431014?v=4",
|
|
||||||
"profile": "https://github.com/karthikbhat13",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 4,
|
"contributorsPerLine": 4,
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
[](#contributors-)
|
[](#contributors-)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
@ -333,9 +333,6 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<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/marlo2222"><img src="https://avatars.githubusercontent.com/u/40809563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marlo Henrique</b></sub></a><br /><a href="#translation-marlo2222" title="Translation">🌍</a></td>
|
||||||
<td align="center"><a href="https://github.com/AndriyPyzh"><img src="https://avatars.githubusercontent.com/u/57706635?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AndriyPyzh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AndriyPyzh" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/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>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/karthikbhat13"><img src="https://avatars.githubusercontent.com/u/22431014?v=4?s=100" width="100px;" alt=""/><br /><sub><b>karthikbhat13</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=karthikbhat13" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
<!-- markdownlint-restore -->
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
---
|
|
||||||
layout: pattern
|
|
||||||
title: Fan-Out/Fan-In
|
|
||||||
folder: fanout-fanin
|
|
||||||
permalink: /patterns/fanout-fanin/
|
|
||||||
categories: Integration
|
|
||||||
language: en
|
|
||||||
tags:
|
|
||||||
- Microservices
|
|
||||||
---
|
|
||||||
|
|
||||||
## Intent
|
|
||||||
The pattern is used when a source system needs to run one or more long-running processes that will fetch some data.
|
|
||||||
The source will not block itself waiting for the reply. <br> The pattern will run the same function in multiple
|
|
||||||
services or machines to fetch the data. This is equivalent to invoking the function multiple times on different chunks of data.
|
|
||||||
|
|
||||||
## Explanation
|
|
||||||
The FanOut/FanIn service will take in a list of requests and a consumer. Each request might complete at a different time.
|
|
||||||
FanOut/FanIn service will accept the input params and returns the initial system an ID to acknowledge that the pattern
|
|
||||||
service has received the requests. Now the caller will not wait or expect the result in the same connection.
|
|
||||||
|
|
||||||
Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time.
|
|
||||||
These requests will be processed in different instances of the same function in different machines or services. As the
|
|
||||||
requests get completed, a callback service everytime is called that transforms the result into a common single object format
|
|
||||||
that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
|
||||||
|
|
||||||
The implementation provided has a list of numbers and end goal is to square the numbers and add them to a single result.
|
|
||||||
`FanOutFanIn` class receives the list of numbers in the form of list of `SquareNumberRequest` and a `Consumer` instance
|
|
||||||
that collects the results as the requests get over. `SquareNumberRequest` will square the number with a random delay
|
|
||||||
to give the impression of a long-running process that can complete at any time. `Consumer` instance will add the results from
|
|
||||||
different `SquareNumberRequest` that will come random time instances.
|
|
||||||
|
|
||||||
Let's look at `FanOutFanIn` class that fans out the requests in async processes.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class FanOutFanIn {
|
|
||||||
public static Long fanOutFanIn(
|
|
||||||
final List<SquareNumberRequest> requests, final Consumer consumer) {
|
|
||||||
|
|
||||||
ExecutorService service = Executors.newFixedThreadPool(requests.size());
|
|
||||||
|
|
||||||
// fanning out
|
|
||||||
List<CompletableFuture<Void>> futures =
|
|
||||||
requests.stream()
|
|
||||||
.map(
|
|
||||||
request ->
|
|
||||||
CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
|
||||||
|
|
||||||
return consumer.getSumOfSquaredNumbers().get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`Consumer` is used a callback class that will be called when a request is completed. This will aggregate
|
|
||||||
the result from all requests.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Consumer {
|
|
||||||
|
|
||||||
private final AtomicLong sumOfSquaredNumbers;
|
|
||||||
|
|
||||||
Consumer(Long init) {
|
|
||||||
sumOfSquaredNumbers = new AtomicLong(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long add(final Long num) {
|
|
||||||
return sumOfSquaredNumbers.addAndGet(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Request is represented as a `SquareNumberRequest` that squares the number with random delay and calls the
|
|
||||||
`Consumer` once it is squared.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class SquareNumberRequest {
|
|
||||||
|
|
||||||
private final Long number;
|
|
||||||
public void delayedSquaring(final Consumer consumer) {
|
|
||||||
|
|
||||||
var minTimeOut = 5000L;
|
|
||||||
|
|
||||||
SecureRandom secureRandom = new SecureRandom();
|
|
||||||
var randomTimeOut = secureRandom.nextInt(2000);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// this will make the thread sleep from 5-7s.
|
|
||||||
Thread.sleep(minTimeOut + randomTimeOut);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.error("Exception while sleep ", e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} finally {
|
|
||||||
consumer.add(number * number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class diagram
|
|
||||||

|
|
||||||
|
|
||||||
## Applicability
|
|
||||||
|
|
||||||
Use this pattern when you can divide the workload into multiple chunks that can be dealt with separately.
|
|
||||||
|
|
||||||
## Related patterns
|
|
||||||
|
|
||||||
* [Aggregator Microservices](https://java-design-patterns.com/patterns/aggregator-microservices/)
|
|
||||||
* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
* [Understanding Azure Durable Functions - Part 8: The Fan Out/Fan In Pattern](http://dontcodetired.com/blog/post/Understanding-Azure-Durable-Functions-Part-8-The-Fan-OutFan-In-Pattern)
|
|
||||||
* [Fan-out/fan-in scenario in Durable Functions - Cloud backup example](https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-cloud-backup)
|
|
||||||
* [Understanding the Fan-Out/Fan-In API Integration Pattern](https://dzone.com/articles/understanding-the-fan-out-fan-in-api-integration-p)
|
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB |
@ -1,39 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.fanout.fanin {
|
|
||||||
class App {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class Consumer {
|
|
||||||
- sumOfSquaredNumbers : AtomicLong
|
|
||||||
~ Consumer(init : Long)
|
|
||||||
+ add(num : Long) : Long
|
|
||||||
+ getSumOfSquaredNumbers() : AtomicLong
|
|
||||||
}
|
|
||||||
class FanOutFanIn {
|
|
||||||
+ FanOutFanIn()
|
|
||||||
+ fanOutFanIn(requests : List<SquareNumberRequest>, consumer : Consumer) : Long {static}
|
|
||||||
}
|
|
||||||
class SquareNumberRequest {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
- number : Long
|
|
||||||
+ SquareNumberRequest(number : Long)
|
|
||||||
+ delayedSquaring(consumer : Consumer)
|
|
||||||
}
|
|
||||||
|
|
||||||
object SquareNumberRequest1
|
|
||||||
object SquareNumberRequest2
|
|
||||||
object SquareNumberRequest3
|
|
||||||
diamond dia
|
|
||||||
}
|
|
||||||
|
|
||||||
App --> FanOutFanIn
|
|
||||||
FanOutFanIn --> "fan out - running in parallel" SquareNumberRequest1
|
|
||||||
FanOutFanIn --> "fan out" SquareNumberRequest2
|
|
||||||
FanOutFanIn --> "fan out" SquareNumberRequest3
|
|
||||||
SquareNumberRequest1 --> "fan in - aggregate using callback" dia
|
|
||||||
SquareNumberRequest2 --> "fan in" dia
|
|
||||||
SquareNumberRequest3 --> "fan in" dia
|
|
||||||
dia --> Consumer
|
|
||||||
@enduml
|
|
@ -1,69 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
-->
|
|
||||||
<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>fanout-fanin</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.fanout.fanin.App</mainClass>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FanOut/FanIn pattern is a concurrency pattern that refers to executing multiple instances of the
|
|
||||||
* activity function concurrently. The "fan out" part is essentially splitting the data into
|
|
||||||
* multiple chunks and then calling the activity function multiple times, passing the chunks.
|
|
||||||
*
|
|
||||||
* <p>When each chunk has been processed, the "fan in" takes place that aggregates results from each
|
|
||||||
* instance of function and forms a single final result.
|
|
||||||
*
|
|
||||||
* <p>This pattern is only really useful if you can “chunk” the workload in a meaningful way for
|
|
||||||
* splitting up to be processed in parallel.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class App {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry point.
|
|
||||||
*
|
|
||||||
* <p>Implementation provided has a list of numbers that has to be squared and added. The list can
|
|
||||||
* be chunked in any way and the "activity function" {@link
|
|
||||||
* SquareNumberRequest#delayedSquaring(Consumer)} i.e. squaring the number ca be done
|
|
||||||
* concurrently. The "fan in" part is handled by the {@link Consumer} that takes in the result
|
|
||||||
* from each instance of activity and aggregates it whenever that particular activity function
|
|
||||||
* gets over.
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final List<Long> numbers = Arrays.asList(1L, 3L, 4L, 7L, 8L);
|
|
||||||
|
|
||||||
LOGGER.info("Numbers to be squared and get sum --> {}", numbers);
|
|
||||||
|
|
||||||
final List<SquareNumberRequest> requests =
|
|
||||||
numbers.stream().map(SquareNumberRequest::new).collect(Collectors.toList());
|
|
||||||
|
|
||||||
var consumer = new Consumer(0L);
|
|
||||||
|
|
||||||
// Pass the request and the consumer to fanOutFanIn or sometimes referred as Orchestrator
|
|
||||||
// function
|
|
||||||
final Long sumOfSquaredNumbers = FanOutFanIn.fanOutFanIn(requests, consumer);
|
|
||||||
|
|
||||||
LOGGER.info("Sum of all squared numbers --> {}", sumOfSquaredNumbers);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumer or callback class that will be called everytime a request is complete This will
|
|
||||||
* aggregate individual result to form a final result.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public class Consumer {
|
|
||||||
|
|
||||||
private final AtomicLong sumOfSquaredNumbers;
|
|
||||||
|
|
||||||
Consumer(Long init) {
|
|
||||||
sumOfSquaredNumbers = new AtomicLong(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long add(final Long num) {
|
|
||||||
return sumOfSquaredNumbers.addAndGet(num);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FanOutFanIn class processes long running requests, when any of the processes gets over, result is
|
|
||||||
* passed over to the consumer or the callback function. Consumer will aggregate the results as they
|
|
||||||
* keep on completing.
|
|
||||||
*/
|
|
||||||
public class FanOutFanIn {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the main fanOutFanIn function or orchestrator function.
|
|
||||||
* @param requests List of numbers that need to be squared and summed up
|
|
||||||
* @param consumer Takes in the squared number from {@link SquareNumberRequest} and sums it up
|
|
||||||
* @return Aggregated sum of all squared numbers.
|
|
||||||
*/
|
|
||||||
public static Long fanOutFanIn(
|
|
||||||
final List<SquareNumberRequest> requests, final Consumer consumer) {
|
|
||||||
|
|
||||||
ExecutorService service = Executors.newFixedThreadPool(requests.size());
|
|
||||||
|
|
||||||
// fanning out
|
|
||||||
List<CompletableFuture<Void>> futures =
|
|
||||||
requests.stream()
|
|
||||||
.map(
|
|
||||||
request ->
|
|
||||||
CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
|
||||||
|
|
||||||
return consumer.getSumOfSquaredNumbers().get();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Squares the number with a little timeout to give impression of long running process that return
|
|
||||||
* at different times.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SquareNumberRequest {
|
|
||||||
|
|
||||||
private final Long number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Squares the number with a little timeout to give impression of long running process that return
|
|
||||||
* at different times.
|
|
||||||
* @param consumer callback class that takes the result after the delay.
|
|
||||||
* */
|
|
||||||
public void delayedSquaring(final Consumer consumer) {
|
|
||||||
|
|
||||||
var minTimeOut = 5000L;
|
|
||||||
|
|
||||||
SecureRandom secureRandom = new SecureRandom();
|
|
||||||
var randomTimeOut = secureRandom.nextInt(2000);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// this will make the thread sleep from 5-7s.
|
|
||||||
Thread.sleep(minTimeOut + randomTimeOut);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.error("Exception while sleep ", e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} finally {
|
|
||||||
consumer.add(number * number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
|
|
||||||
class AppTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldLaunchApp() {
|
|
||||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
class FanOutFanInTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void fanOutFanInTest() {
|
|
||||||
final List<Long> numbers = Arrays.asList(1L, 3L, 4L, 7L, 8L);
|
|
||||||
|
|
||||||
final List<SquareNumberRequest> requests =
|
|
||||||
numbers.stream().map(SquareNumberRequest::new).collect(Collectors.toList());
|
|
||||||
|
|
||||||
final Consumer consumer = new Consumer(0L);
|
|
||||||
|
|
||||||
final Long sumOfSquaredNumbers = FanOutFanIn.fanOutFanIn(requests, consumer);
|
|
||||||
|
|
||||||
Assertions.assertEquals(139, sumOfSquaredNumbers);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fanout.fanin;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class SquareNumberRequestTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void delayedSquaringTest() {
|
|
||||||
Consumer consumer = new Consumer(10L);
|
|
||||||
|
|
||||||
SquareNumberRequest squareNumberRequest = new SquareNumberRequest(5L);
|
|
||||||
|
|
||||||
squareNumberRequest.delayedSquaring(consumer);
|
|
||||||
|
|
||||||
Assertions.assertEquals(35, consumer.getSumOfSquaredNumbers().get());
|
|
||||||
}
|
|
||||||
}
|
|
23
gpl-3.0.txt
23
gpl-3.0.txt
@ -1,26 +1,3 @@
|
|||||||
====
|
|
||||||
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.
|
|
||||||
====
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
23
lgpl-3.0.txt
23
lgpl-3.0.txt
@ -1,26 +1,3 @@
|
|||||||
====
|
|
||||||
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.
|
|
||||||
====
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Abstract Document
|
title: Abstract Document
|
||||||
folder: abstract-document
|
folder: abstract-document
|
||||||
permalink: /patterns/abstract-document/
|
permalink: /patterns/abstract-document/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -166,7 +166,7 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

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

|

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

|

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

|

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

|

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

|

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

|

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

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Arrange/Act/Assert
|
title: Arrange/Act/Assert
|
||||||
folder: arrange-act-assert
|
folder: arrange-act-assert
|
||||||
permalink: /patterns/arrange-act-assert/
|
permalink: /patterns/arrange-act-assert/zh
|
||||||
categories: Idiom
|
categories: Idiom
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -73,7 +73,10 @@ 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
|
```java
|
||||||
class CashAAATest {
|
class CashAAATest {
|
||||||
@ -126,8 +129,9 @@ class CashAAATest {
|
|||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
使用 安排/执行/断言 模式当
|
使用 Arrange/Act/Assert 模式当
|
||||||
|
|
||||||
|
* You need to structure your unit tests so that they're easier to read, maintain, and enhance.
|
||||||
* 你需要结构化你的单元测试代码这样它们可以更好的阅读,维护和增强。
|
* 你需要结构化你的单元测试代码这样它们可以更好的阅读,维护和增强。
|
||||||
|
|
||||||
## 鸣谢
|
## 鸣谢
|
||||||
|
@ -4,32 +4,33 @@ title: Async Method Invocation
|
|||||||
folder: async-method-invocation
|
folder: async-method-invocation
|
||||||
permalink: /patterns/async-method-invocation/
|
permalink: /patterns/async-method-invocation/
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Reactive
|
- Reactive
|
||||||
---
|
---
|
||||||
|
|
||||||
## 意图
|
## 含义
|
||||||
|
|
||||||
异步方法调用是一个调用线程在等待任务结果时不会阻塞的模式。模式为多个独立的任务提供并行的处理方式并且通过回调或等到它们全部完成来接收任务结果。
|
异步方法是一种调用线程在等待任务结果时候不会被阻塞的模式。该模式提供了对多个任务的并行处理,并通过回调或等待,在所有任务完成后在提供结果读取。
|
||||||
|
|
||||||
## 解释
|
## 解释
|
||||||
|
|
||||||
真实世界例子
|
真实世界案例
|
||||||
|
|
||||||
> 发射火箭是一项令人激动的事务。任务指挥官发出了发射命令,经过一段不确定的时间后,火箭要么成功发射,要么惨遭失败。
|
> 发射太空火箭是一项令人兴奋的事业。在任务指挥部下达发射命令后, 经过一些未确定的时间,火箭要么成功发射,要么重演挑战者悲剧。
|
||||||
|
|
||||||
通俗地说
|
简而言之
|
||||||
|
|
||||||
> 异步方法调用开始任务处理,并在任务完成之前立即返回。 任务处理的结果稍后返回给调用方。
|
> 异步方法调用开始任务处理并,在任务结果准备好之前立即返回。任务处理的结果会在稍后再返回给调用者。
|
||||||
|
|
||||||
维基百科说
|
维基百科的解释
|
||||||
|
|
||||||
> 在多线程计算机编程中,异步方法调用(AMI),也称为异步方法调用或异步模式,是一种设计模式,其中在等待被调用的代码完成时不会阻塞调用站点。 而是在执行结果到达时通知调用线程。轮询调用结果是不希望的选项。
|
> 在多线程计算机编程中,异步方法调用(AMI),也被称为异步方法调用或异步模式。这是一种设计模式,在这种模式下,调用点在等待被调用代码完成时不会被阻塞。相反,当返回点到达时,调用线程会得到通知。轮询结果是一种不受欢迎的选择。
|
||||||
|
|
||||||
**程序示例**
|
**编程示例**
|
||||||
|
|
||||||
在此示例中,我们正在发射太空火箭并部署月球漫游车。该应用演示了异步方法调用模式。 模式的关键部分是`AsyncResult`(用于异步评估值的中间容器),`AsyncCallback`(可以在任务完成时被执行)和`AsyncExecutor`(用于管理异步任务的执行)。
|
在这个例子中,我们正在发射太空火箭和部署月球车。
|
||||||
|
|
||||||
|
该应用演示了异步方法调用模式。该模式的关键部分是 `AsyncResult`,它是一个异步计算值的中间容器,`AsyncCallback` 可以在任务完成时提供执行行动作,`AsyncExecutor` 负责管理异步任务的执行。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface AsyncResult<T> {
|
public interface AsyncResult<T> {
|
||||||
@ -53,7 +54,7 @@ public interface AsyncExecutor {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`ThreadAsyncExecutor`是`AsyncExecutor`的实现。 接下来将突出显示其一些关键部分。
|
`ThreadAsyncExecutor` 是 `AsyncExecutor` 的一个实现。接下来将着重说明它的一些关键部分。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class ThreadAsyncExecutor implements AsyncExecutor {
|
public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||||
@ -90,14 +91,14 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
然后,我们准备发射一些火箭,看看一切是如何协同工作的。
|
然后我们准备发射一些火箭,看看所有东西是如何一起运作的。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// 构造一个将执行异步任务的新执行程序
|
// construct a new executor that will run async tasks
|
||||||
var executor = new ThreadAsyncExecutor();
|
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 asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||||
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
|
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||||
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||||
@ -105,11 +106,11 @@ public static void main(String[] args) throws Exception {
|
|||||||
final var asyncResult5 =
|
final var asyncResult5 =
|
||||||
executor.startProcess(lazyval("callback", 600), callback("Deploying lunar rover"));
|
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); // 哦,兄弟,我们在这很辛苦
|
Thread.sleep(350); // Oh boy, we are working hard here
|
||||||
log("Mission command is sipping coffee");
|
log("Mission command is sipping coffee");
|
||||||
|
|
||||||
// 等待任务完成
|
// wait for completion of the tasks
|
||||||
final var result1 = executor.endProcess(asyncResult1);
|
final var result1 = executor.endProcess(asyncResult1);
|
||||||
final var result2 = executor.endProcess(asyncResult2);
|
final var result2 = executor.endProcess(asyncResult2);
|
||||||
final var result3 = executor.endProcess(asyncResult3);
|
final var result3 = executor.endProcess(asyncResult3);
|
||||||
@ -117,14 +118,13 @@ public static void main(String[] args) throws Exception {
|
|||||||
asyncResult5.await();
|
asyncResult5.await();
|
||||||
|
|
||||||
// log the results of the tasks, callbacks log immediately when complete
|
// log the results of the tasks, callbacks log immediately when complete
|
||||||
// 记录任务结果的日志, 回调的日志会在回调完成时立刻记录
|
|
||||||
log("Space rocket <" + result1 + "> launch complete");
|
log("Space rocket <" + result1 + "> launch complete");
|
||||||
log("Space rocket <" + result2 + "> launch complete");
|
log("Space rocket <" + result2 + "> launch complete");
|
||||||
log("Space rocket <" + result3 + "> launch complete");
|
log("Space rocket <" + result3 + "> launch complete");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
这是程序控制台的输出。
|
以下是控制台输出。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
21:47:08.227 [executor-2] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launched successfully
|
21:47:08.227 [executor-2] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launched successfully
|
||||||
@ -140,21 +140,22 @@ 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
|
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)
|
* [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)
|
* [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)
|
* [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)
|
* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx)
|
||||||
|
|
||||||
|
@ -4,34 +4,33 @@ title: Balking
|
|||||||
folder: balking
|
folder: balking
|
||||||
permalink: /patterns/balking/
|
permalink: /patterns/balking/
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
---
|
---
|
||||||
|
|
||||||
## 意图
|
## 含义
|
||||||
|
|
||||||
止步模式用于防止对象在不完整或不合适的状态下执行某些代码。
|
阻止模式用于防止一个对象在不完整或不适当的状态下执行某段代码。
|
||||||
|
|
||||||
## 解释
|
## 解释
|
||||||
|
|
||||||
真实世界例子
|
真实世界的案例
|
||||||
|
|
||||||
> 洗衣机中有一个开始按钮,用于启动衣物洗涤。当洗衣机处于非活动状态时,按钮将按预期工作,但是如果已经在洗涤,则按钮将不起任何作用。
|
> 洗衣机里有一个用于启动衣物洗涤的启动按钮。当洗衣机没有启动时,该按钮可以正常按下生效,但如果洗衣机已经在洗衣服了,再按下按钮就不生效了。
|
||||||
|
|
||||||
通俗地说
|
简而言之
|
||||||
|
|
||||||
> 使用止步模式,仅当对象处于特定状态时才执行特定代码。
|
> 使用阻止模式,只有当对象处于特定状态时,才会执行某段代码。
|
||||||
|
|
||||||
维基百科说
|
维基百科的解释
|
||||||
|
|
||||||
> 禁止模式是一种软件设计模式,仅当对象处于特定状态时才对对象执行操作。例如,一个对象读取zip压缩文件并在压缩文件没打开的时候调用get方法,对象将在请求的时候”止步“。
|
> 阻止模式是一种软件设计模式,它只在对象处于特定状态时对其执行动作。例如,如果一个对象读取 ZIP 文件,当 ZIP 文件没有打开时,如果一个方法在该对象上调用一个获取方法,该对象就会对阻止这个请求。
|
||||||
|
|
||||||
**程序示例**
|
**编程示例**
|
||||||
|
|
||||||
在此示例中,` WashingMachine`是一个具有两个状态的对象,可以处于两种状态:ENABLED和WASHING。 如果机器已启用,则使用线程安全方法将状态更改为WASHING。 另一方面,如果已经进行了清洗并且任何其他线程执行`wash()`,则它将不执行该操作,而是不执行任何操作而返回。
|
在这个例子的实现中,`WashingMachine` 对象存在 2 种状态: `ENABLED` 和 `WASHING`。如果该对象处于 `ENABLED` 状态,则使用一个线程安全的方法可以其状态改变为 `WASHING`。在另一方面,如果它已经处于 `WASHING` 状态,而任何其他线程执行了 `wash()`,它不会执行该指令,而是什么都不做就返回。
|
||||||
|
|
||||||
这里是`WashingMachine` 类相关的部分。
|
以下是 `WashingMachine` 类的相关代码。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -70,7 +69,7 @@ public class WashingMachine {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
这里是一个`WashingMachine`所使用的`DelayProvider`简单接口。
|
以下是 `WashingMachine` 使用的简单 `DelayProvider` 接口。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface DelayProvider {
|
public interface DelayProvider {
|
||||||
@ -78,7 +77,7 @@ public interface DelayProvider {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
现在,我们使用`WashingMachine`介绍该应用程序。
|
现在我们介绍一下使用 `WashingMachine` 的应用。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
@ -97,7 +96,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
|
14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
|
||||||
@ -111,21 +110,20 @@ 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)
|
* [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
|
layout: pattern
|
||||||
title: Bridge
|
title: Bridge
|
||||||
folder: bridge
|
folder: bridge
|
||||||
permalink: /patterns/bridge/
|
permalink: /patterns/bridge/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -184,7 +184,7 @@ hammer.unwield();
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

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

|

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

|

|
||||||
|
|
||||||
## 相关模式
|
## 相关模式
|
||||||
|
|
||||||
* [服务定位器模式](https://java-design-patterns.com/patterns/service-locator/)
|
* [Service locator pattern](https://java-design-patterns.com/patterns/service-locator/)
|
||||||
|
|
||||||
## 适用性
|
## 适用场景
|
||||||
|
|
||||||
使用业务委托模式当
|
业务委托模式的适用场景:
|
||||||
|
|
||||||
* 你希望表示层和业务层之间的松散耦合
|
* 你希望表现层和业务层之间是松耦合的。
|
||||||
* 你想编排对多个业务服务的调用
|
* 你想要协调对多个业务服务的调用。
|
||||||
* 你希望封装查找服务和服务调用
|
* 你想要对服务查询、服务调用进行封装。
|
||||||
|
|
||||||
## 教程
|
## 教程
|
||||||
|
|
||||||
* [Business Delegate Pattern at TutorialsPoint](https://www.tutorialspoint.com/design_pattern/business_delegate_pattern.htm)
|
* [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)
|
* [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)
|
* [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)
|
||||||
|
@ -1,235 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
layout: pattern
|
||||||
title: Caching
|
title: Caching
|
||||||
folder: caching
|
folder: caching
|
||||||
permalink: /patterns/caching/
|
permalink: /patterns/caching/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -14,7 +14,7 @@ tags:
|
|||||||
为了避免昂贵的资源重新获取,方法是在资源使用后不立即释放资源。资源保留其身份,保留在某些快速访问的存储中,并被重新使用,以避免再次获取它们。
|
为了避免昂贵的资源重新获取,方法是在资源使用后不立即释放资源。资源保留其身份,保留在某些快速访问的存储中,并被重新使用,以避免再次获取它们。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

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

|

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

|

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

|
||||||
|
|
||||||

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

|

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

|

|
||||||
|
|
||||||
## 适用性
|
## 适用场景
|
||||||
|
|
||||||
在以下情况下使用断路器模式
|
在以下场景下,可以使用断路器模式:
|
||||||
|
|
||||||
- 构建一个容错应用程序,其中某些服务的故障不应导致整个应用程序宕机。
|
- 构建一个高可用的应用程序,某些些服务的失败不会导致整个应用程序的崩溃。
|
||||||
- 构建一个持续运行(永远在线)的应用程序,这样它的组件就可以在不完全关闭的情况下升级。
|
- 构建一个持续运行(长期在线)的应用程序,以便其组件可以在不完全关闭的情况下进行升级。
|
||||||
|
|
||||||
## 相关模式
|
## 相关模式
|
||||||
|
|
||||||
- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry)
|
- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry)
|
||||||
|
|
||||||
## 真实世界例子
|
## 现实案例
|
||||||
|
|
||||||
* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker)
|
* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker)
|
||||||
* [Netflix Hystrix API](https://github.com/Netflix/Hystrix)
|
* [Netflix Hystrix API](https://github.com/Netflix/Hystrix)
|
||||||
|
|
||||||
## 鸣谢
|
## 引用
|
||||||
|
|
||||||
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
|
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
|
||||||
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
|
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
---
|
|
||||||
layout: pattern
|
|
||||||
title: Static Content Hosting
|
|
||||||
folder: cloud-static-content-hosting
|
|
||||||
permalink: /patterns/cloud-static-content-hosting/
|
|
||||||
categories: Cloud
|
|
||||||
language: zh
|
|
||||||
tags:
|
|
||||||
- Cloud distributed
|
|
||||||
---
|
|
||||||
|
|
||||||
## 意图
|
|
||||||
|
|
||||||
将静态内容部署到基于云的存储服务,该服务可以将它们直接交付给客户端。 这可以减少对昂贵计算实例的需求。
|
|
||||||
|
|
||||||
## 解释
|
|
||||||
|
|
||||||
真实世界例子
|
|
||||||
|
|
||||||
> 全球性的营销网站(静态内容)需要快速的部署以开始吸引潜在的客户。为了将托管费用和维护成本降至最低,使用云托管存储服务和内容交付网络。
|
|
||||||
|
|
||||||
通俗地说
|
|
||||||
|
|
||||||
> 静态内容托管模式利用云原生存储服务来存储内容和全球内容交付网络,将其缓存在世界各地的多个数据中心。 在静态网站上,单个网页包含静态内容。 它们还可能包含客户端脚本,例如 Javascript。相比之下,动态网站依赖于服务器端处理,包括服务器端脚本,如 PHP、JSP 或 ASP.NET。
|
|
||||||
|
|
||||||
维基百科说
|
|
||||||
|
|
||||||
> 与由 Web 应用程序生成的动态网页相反,静态网页(有时称为平面网页或固定网页)是完全按照存储的方式传送到用户的网页浏览器的网页。静态网页适用于从不或很少需要更新的内容,尽管现代
|
|
||||||
> Web 模板系统正在改变这一点。可以将大量静态页面作为文件进行维护,没有自动化工具(例如静态站点生成器)是不切实际的。
|
|
||||||
|
|
||||||
**示例**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
在这个例子中我们使用AWS S3创建一个静态网站,并利用 AWS Cloudfront 在全球范围内分发内容。
|
|
||||||
|
|
||||||
1. 首先你需要一个AWS账户,你可以在这个创建一个免费的:[AWS Free Tier](https://aws.amazon.com/free/free-tier/)
|
|
||||||
|
|
||||||
2. 登陆 [AWS控制台](https://console.aws.amazon.com/console/home?nc2=h_ct&src=header-signin)
|
|
||||||
|
|
||||||
3. 进入身份和接入管理服务 (IAM) .
|
|
||||||
|
|
||||||
4. 创建一个仅具有此应用程序必要权限的IAM用户。
|
|
||||||
|
|
||||||
* 点击 `用户`
|
|
||||||
* 点击 `添加用户`. 选择你想要的 `用户名`, `接入类型`应该是 `编程式接入`. 点击 `下一步: 权限`.
|
|
||||||
* 选择 `直接附加已存在的策略`. 选择 `AmazonS3FullAccess` 和 `CloudFrontFullAccess`. Click `下一步: 标签`.
|
|
||||||
* 没有需要的标签, 所以直接点击 `下一步: 回顾`.
|
|
||||||
* 检查呈现的信息,没问题的话点击`创建用户`
|
|
||||||
* 完成这个示例所需要的`访问秘钥Id`和`访问秘钥密码`将会呈现在你面前,请妥善保管。
|
|
||||||
* 点击 `关闭`.
|
|
||||||
|
|
||||||
5. [安装AWS 命令行工具 (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html) 来获得编程式访问AWS云。
|
|
||||||
|
|
||||||
6. 使用`aws configure`命令来配置AWS CLI [说明书](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config)
|
|
||||||
|
|
||||||
7. 为web站点创建AWS S3 bucket。 注意S3 bucket名字必须要在全球范围内唯一。
|
|
||||||
|
|
||||||
|
|
||||||
* 语法是 `aws s3 mb <bucket name>` [说明书](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-buckets-creating)
|
|
||||||
* 比如 `aws s3 mb s3://my-static-website-jh34jsjmg`
|
|
||||||
* 使用列出现有存储桶的命令`aws s3 ls`验证存储桶是否已成功创建
|
|
||||||
|
|
||||||
8. 使用命令`aws s3 website`来配置bucket作为web站点。 [说明书](https://docs.aws.amazon.com/cli/latest/reference/s3/website.html).
|
|
||||||
|
|
||||||
* 比如`aws s3 website s3://my-static-website-jh34jsjmg --index-document index.html --error-document error.html`
|
|
||||||
|
|
||||||
9. 上传内容到bucket中。
|
|
||||||
* 首先创建内容,至少包含`index.html`和`error.html`文档。
|
|
||||||
* 上传内容到你的bucket中。 [说明书](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-copy)
|
|
||||||
* 比如`aws s3 cp index.html s3://my-static-website-jh34jsjmg` and `aws s3 cp error.html s3://my-static-website-jh34jsjmg`
|
|
||||||
|
|
||||||
10. 然后我们需要设置bucket的策略以允许读取访问。
|
|
||||||
|
|
||||||
* 使用以下内容创建`policy.json`(注意需要将bucket名称替换为自己的)。
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Sid": "PublicReadGetObject",
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": "*",
|
|
||||||
"Action": "s3:GetObject",
|
|
||||||
"Resource": "arn:aws:s3:::my-static-website-jh34jsjmg/*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* 根据这些设置桶策略[说明书](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-policy.html)
|
|
||||||
* 比如 `aws s3api put-bucket-policy --bucket my-static-website-jh34jsjmg --policy file://policy.json`
|
|
||||||
|
|
||||||
11. 使用浏览器测试web站点。
|
|
||||||
|
|
||||||
* web站点的URL格式是 `http://<bucket-name>.s3-website-<region-name>.amazonaws.com`
|
|
||||||
* 比如 这个站点创建在 `eu-west-1` 区域 ,名字是 `my-static-website-jh34jsjmg` 所以它可以通过 `http://my-static-website-jh34jsjmg.s3-website-eu-west-1.amazonaws.com`来访问。
|
|
||||||
|
|
||||||
12. 为web站点创建CloudFormation 分发。
|
|
||||||
|
|
||||||
* 语法文档在这里 [this reference](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-distribution.html)
|
|
||||||
* 比如,最简单的方式是使用命令l `aws cloudfront create-distribution --origin-domain-name my-static-website-jh34jsjmg.s3.amazonaws.com --default-root-object index.html`
|
|
||||||
* 也支持JSON格式的配置 比如使用 `--distribution-config file://dist-config.json` 来传递分发的配置文件参数
|
|
||||||
* 命令的舒勇将显示准确的分配配置项,包括包括可用于测试的生成的 CloudFront 域名,例如 `d2k3xwnaqa8nqx.cloudfront.net`
|
|
||||||
* CloudFormation 分发部署需要一些时间,但一旦完成,您的网站就会从全球各地的数据中心提供服务!
|
|
||||||
|
|
||||||
13. 就是这样! 您已经实现了一个静态网站,其内容分发网络以闪电般的速度在世界各地提供服务。
|
|
||||||
|
|
||||||
* 要更新网站,您需要更新 S3 存储桶中的对象并使 CloudFront 分配中的对象无效
|
|
||||||
* 要从 AWS CLI 执行此操作,请参阅 [this reference](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-invalidation.html)
|
|
||||||
* 您可能想要做的进一步开发是通过 https 提供内容并为您的站点添加域名
|
|
||||||
|
|
||||||
## 适用性
|
|
||||||
|
|
||||||
当您想要执行以下操作时,请使用静态内容托管模式:
|
|
||||||
|
|
||||||
* 最小化包含一些静态资源的网站和应用程序的托管成本。
|
|
||||||
* 使用静态内容构建全球可用的网站
|
|
||||||
* 监控网站流量、带宽使用、成本等。
|
|
||||||
|
|
||||||
## 典型用例
|
|
||||||
|
|
||||||
* 具有全球影响力的网站
|
|
||||||
* 静态网站生成器生成的内容
|
|
||||||
* 没有动态内容要求的网站
|
|
||||||
|
|
||||||
## 真实世界例子
|
|
||||||
|
|
||||||
* [Java Design Patterns web site](https://java-design-patterns.com)
|
|
||||||
|
|
||||||
## 鸣谢
|
|
||||||
|
|
||||||
* [Static Content Hosting pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/static-content-hosting)
|
|
@ -4,7 +4,6 @@ title: Collection Pipeline
|
|||||||
folder: collection-pipeline
|
folder: collection-pipeline
|
||||||
permalink: /patterns/collection-pipeline/
|
permalink: /patterns/collection-pipeline/
|
||||||
categories: Functional
|
categories: Functional
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Reactive
|
- Reactive
|
||||||
---
|
---
|
||||||
@ -14,7 +13,7 @@ tags:
|
|||||||
在函数式编程中,可以通过一系列较小的模块化函数或操作来编排复杂的操作。这一系列函数被称为函数组合。当一个数据集合流经一个函数组合时,它就成为一个集合管道。函数组合和集合管道是函数式编程中经常使用的两种设计模式。
|
在函数式编程中,可以通过一系列较小的模块化函数或操作来编排复杂的操作。这一系列函数被称为函数组合。当一个数据集合流经一个函数组合时,它就成为一个集合管道。函数组合和集合管道是函数式编程中经常使用的两种设计模式。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
在以下场景适用集合管道模式:
|
在以下场景适用集合管道模式:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Command
|
title: Command
|
||||||
folder: command
|
folder: command
|
||||||
permalink: /patterns/command/
|
permalink: /patterns/command/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -222,7 +222,7 @@ goblin.printStatus();
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
使用命令模式当你想
|
使用命令模式当你想
|
||||||
|
@ -4,7 +4,6 @@ title: Composite Entity
|
|||||||
folder: composite-entity
|
folder: composite-entity
|
||||||
permalink: /patterns/composite-entity/
|
permalink: /patterns/composite-entity/
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Enterprise Integration Pattern
|
- Enterprise Integration Pattern
|
||||||
---
|
---
|
||||||
@ -110,7 +109,7 @@ Arrays.stream(console.getData()).forEach(LOGGER::info);
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Composite
|
title: Composite
|
||||||
folder: composite
|
folder: composite
|
||||||
permalink: /patterns/composite/
|
permalink: /patterns/composite/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -154,7 +154,7 @@ elfMessage.print(); // Much wind pours from your mouth.
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Converter
|
title: Converter
|
||||||
folder: converter
|
folder: converter
|
||||||
permalink: /patterns/converter/
|
permalink: /patterns/converter/zh
|
||||||
categories: Creational
|
categories: Creational
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -86,7 +86,7 @@ var user = userConverter.convertFromDto(dtoUser);
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Data Access Object
|
title: Data Access Object
|
||||||
folder: dao
|
folder: dao
|
||||||
permalink: /patterns/dao/
|
permalink: /patterns/dao/zh
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -149,7 +149,7 @@ customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@6ec8211c
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ layout: pattern
|
|||||||
title: Data Bus
|
title: Data Bus
|
||||||
folder: data-bus
|
folder: data-bus
|
||||||
permalink: /patterns/data-bus/
|
permalink: /patterns/data-bus/
|
||||||
|
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
---
|
---
|
||||||
@ -14,7 +14,7 @@ tags:
|
|||||||
数据总线模式(译者:实际上,就是 Event-Bus 消息总线模式)允许在一个应用程序的组件之间收发消息/事件,而不需要这些组件相互感知,它们只需要知道所发送/接收的消息/事件的类型即可。
|
数据总线模式(译者:实际上,就是 Event-Bus 消息总线模式)允许在一个应用程序的组件之间收发消息/事件,而不需要这些组件相互感知,它们只需要知道所发送/接收的消息/事件的类型即可。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
可以在以下场景使用数据总线模式:
|
可以在以下场景使用数据总线模式:
|
||||||
|
@ -4,7 +4,6 @@ title: Data Mapper
|
|||||||
folder: data-mapper
|
folder: data-mapper
|
||||||
permalink: /patterns/data-mapper/
|
permalink: /patterns/data-mapper/
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
---
|
---
|
||||||
@ -13,7 +12,7 @@ tags:
|
|||||||
一个用于在持久化对象和数据库之间传输数据的映射器,同时保持它们之间和映射器本身的独立性。
|
一个用于在持久化对象和数据库之间传输数据的映射器,同时保持它们之间和映射器本身的独立性。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
数据映射器适用于以下场景:
|
数据映射器适用于以下场景:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Data Transfer Object
|
title: Data Transfer Object
|
||||||
folder: data-transfer-object
|
folder: data-transfer-object
|
||||||
permalink: /patterns/data-transfer-object/
|
permalink: /patterns/data-transfer-object/zh
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -94,7 +94,7 @@ public class CustomerResource {
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Decorator
|
title: Decorator
|
||||||
folder: decorator
|
folder: decorator
|
||||||
permalink: /patterns/decorator/
|
permalink: /patterns/decorator/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -106,7 +106,7 @@ clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away!
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
使用装饰者
|
使用装饰者
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Delegation
|
title: Delegation
|
||||||
folder: delegation
|
folder: delegation
|
||||||
permalink: /patterns/delegation/
|
permalink: /patterns/delegation/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -16,7 +16,7 @@ tags:
|
|||||||
它是一种让对象将某种行为向外部表达,但实际上将实现该行为的责任委托给关联对象的技术。
|
它是一种让对象将某种行为向外部表达,但实际上将实现该行为的责任委托给关联对象的技术。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
使用委托模式以实现以下目的
|
使用委托模式以实现以下目的
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Dependency Injection
|
title: Dependency Injection
|
||||||
folder: dependency-injection
|
folder: dependency-injection
|
||||||
permalink: /patterns/dependency-injection/
|
permalink: /patterns/dependency-injection/zh
|
||||||
categories: Creational
|
categories: Creational
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -84,7 +84,7 @@ public class AdvancedWizard implements Wizard {
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Dirty Flag
|
title: Dirty Flag
|
||||||
folder: dirty-flag
|
folder: dirty-flag
|
||||||
permalink: /patterns/dirty-flag/
|
permalink: /patterns/dirty-flag/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -17,7 +17,7 @@ tags:
|
|||||||
避免昂贵资源的重新获取。资源保留其身份,保留在某些快速访问的存储中,并被重新使用以避免再次获取它们。
|
避免昂贵资源的重新获取。资源保留其身份,保留在某些快速访问的存储中,并被重新使用以避免再次获取它们。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
在以下情况下使用脏标志模式
|
在以下情况下使用脏标志模式
|
||||||
|
@ -4,7 +4,6 @@ title: Double Checked Locking
|
|||||||
folder: double-checked-locking
|
folder: double-checked-locking
|
||||||
permalink: /patterns/double-checked-locking/
|
permalink: /patterns/double-checked-locking/
|
||||||
categories: Idiom
|
categories: Idiom
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Performance
|
- Performance
|
||||||
---
|
---
|
||||||
@ -13,7 +12,7 @@ tags:
|
|||||||
通过先测试锁定标准("锁提示")而不实际获取锁的方式来减少获取锁的开销。只有当锁定标准检查表明需要锁定时,才进行实际的锁定逻辑。
|
通过先测试锁定标准("锁提示")而不实际获取锁的方式来减少获取锁的开销。只有当锁定标准检查表明需要锁定时,才进行实际的锁定逻辑。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
在以下场景适合使用双重锁检查模式:
|
在以下场景适合使用双重锁检查模式:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Facade
|
title: Facade
|
||||||
folder: facade
|
folder: facade
|
||||||
permalink: /patterns/facade/
|
permalink: /patterns/facade/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -189,7 +189,7 @@ facade.endDay();
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
使用外观模式当
|
使用外观模式当
|
||||||
|
@ -4,7 +4,6 @@ title: Factory Kit
|
|||||||
folder: factory-kit
|
folder: factory-kit
|
||||||
permalink: /patterns/factory-kit/
|
permalink: /patterns/factory-kit/
|
||||||
categories: Creational
|
categories: Creational
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Extensibility
|
- Extensibility
|
||||||
---
|
---
|
||||||
@ -13,7 +12,7 @@ tags:
|
|||||||
使用分离的构建器和工厂接口来定义一个不可变内容的工厂。
|
使用分离的构建器和工厂接口来定义一个不可变内容的工厂。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
工厂套件模式适用于与以下场景:
|
工厂套件模式适用于与以下场景:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Factory Method
|
title: Factory Method
|
||||||
folder: factory-method
|
folder: factory-method
|
||||||
permalink: /patterns/factory-method/
|
permalink: /patterns/factory-method/zh
|
||||||
categories: Creational
|
categories: Creational
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -63,7 +63,7 @@ blacksmith.manufactureWeapon(WeaponType.AXE);
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
使用工厂方法模式当
|
使用工厂方法模式当
|
||||||
|
@ -4,7 +4,6 @@ title: Factory
|
|||||||
folder: factory
|
folder: factory
|
||||||
permalink: /patterns/factory/
|
permalink: /patterns/factory/
|
||||||
categories: Creational
|
categories: Creational
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Gang of Four
|
- Gang of Four
|
||||||
---
|
---
|
||||||
@ -109,7 +108,7 @@ This is Ferrari.
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Interpreter
|
title: Interpreter
|
||||||
folder: interpreter
|
folder: interpreter
|
||||||
permalink: /patterns/interpreter/
|
permalink: /patterns/interpreter/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -13,7 +13,7 @@ tags:
|
|||||||
给定一种语言,请定义其语法的表示形式,以及使用该表示形式来解释该语言中的句子的解释器。
|
给定一种语言,请定义其语法的表示形式,以及使用该表示形式来解释该语言中的句子的解释器。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
有一种要解释的语言时,请使用解释器模式,并且可以将语言中的语句表示为抽象语法树。解释器模式在以下情况下效果最佳
|
有一种要解释的语言时,请使用解释器模式,并且可以将语言中的语句表示为抽象语法树。解释器模式在以下情况下效果最佳
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Iterator
|
title: Iterator
|
||||||
folder: iterator
|
folder: iterator
|
||||||
permalink: /patterns/iterator/
|
permalink: /patterns/iterator/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -115,7 +115,7 @@ while (itemIterator.hasNext()) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
以下情况使用迭代器模式
|
以下情况使用迭代器模式
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Observer
|
title: Observer
|
||||||
folder: observer
|
folder: observer
|
||||||
permalink: /patterns/observer/
|
permalink: /patterns/observer/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -129,7 +129,7 @@ public class Weather {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
|
|
||||||
## 应用
|
## 应用
|
||||||
在下面任何一种情况下都可以使用观察者模式
|
在下面任何一种情况下都可以使用观察者模式
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Private Class Data
|
title: Private Class Data
|
||||||
folder: private-class-data
|
folder: private-class-data
|
||||||
permalink: /patterns/private-class-data/
|
permalink: /patterns/private-class-data/zh
|
||||||
categories: Idiom
|
categories: Idiom
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -120,7 +120,7 @@ immutableStew.mix(); // Mixing the immutable stew we find: 2 potatoes, 4 carrot
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Producer Consumer
|
title: Producer Consumer
|
||||||
folder: producer-consumer
|
folder: producer-consumer
|
||||||
permalink: /patterns/producer-consumer/
|
permalink: /patterns/producer-consumer/zh
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -13,7 +13,7 @@ tags:
|
|||||||
生产者消费者设计模式是一种经典的并发模式,通过将工作与执行工作任务分开来减少生产者与消费者之间的耦合。
|
生产者消费者设计模式是一种经典的并发模式,通过将工作与执行工作任务分开来减少生产者与消费者之间的耦合。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
在以下情况下使用生产者消费者
|
在以下情况下使用生产者消费者
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Proxy
|
title: Proxy
|
||||||
folder: proxy
|
folder: proxy
|
||||||
permalink: /patterns/proxy/
|
permalink: /patterns/proxy/zh
|
||||||
categories: Structural
|
categories: Structural
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -123,7 +123,7 @@ Brown wizard is not allowed to enter!
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ title: Sharding
|
|||||||
folder: sharding
|
folder: sharding
|
||||||
permalink: /patterns/sharding/
|
permalink: /patterns/sharding/
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Performance
|
- Performance
|
||||||
- Cloud distributed
|
- Cloud distributed
|
||||||
@ -16,7 +15,7 @@ tags:
|
|||||||
一个分片本身就是一个数据存储(它可以包含许多不同类型的实体的数据),运行在作为存储节点的服务器上。
|
一个分片本身就是一个数据存储(它可以包含许多不同类型的实体的数据),运行在作为存储节点的服务器上。
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用场景
|
## 适用场景
|
||||||
这种设计模式提供了一下的好处:
|
这种设计模式提供了一下的好处:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: State
|
title: State
|
||||||
folder: state
|
folder: state
|
||||||
permalink: /patterns/state/
|
permalink: /patterns/state/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -135,7 +135,7 @@ public class Mammoth {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Strategy
|
title: Strategy
|
||||||
folder: strategy
|
folder: strategy
|
||||||
permalink: /patterns/strategy/
|
permalink: /patterns/strategy/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -112,7 +112,7 @@ public class DragonSlayer {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 应用
|
## 应用
|
||||||
使用策略模式当
|
使用策略模式当
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Template method
|
title: Template method
|
||||||
folder: template-method
|
folder: template-method
|
||||||
permalink: /patterns/template-method/
|
permalink: /patterns/template-method/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -119,7 +119,7 @@ public class HalflingThief {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类图
|
## 类图
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Version Number
|
title: Version Number
|
||||||
folder: versionnumber
|
folder: versionnumber
|
||||||
permalink: /patterns/versionnumber/
|
permalink: /patterns/versionnumber/zh
|
||||||
description: Entity versioning with version number
|
description: Entity versioning with version number
|
||||||
|
language: zh
|
||||||
|
|
||||||
categories:
|
categories:
|
||||||
- Concurrency
|
- Concurrency
|
||||||
|
|
||||||
language: zh
|
|
||||||
tags:
|
tags:
|
||||||
- Data access
|
- Data access
|
||||||
- Microservices
|
- Microservices
|
||||||
@ -135,7 +135,7 @@ Exception: Tried to update stale version 0 while actual version is 1
|
|||||||
|
|
||||||
## 类图
|
## 类图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
layout: pattern
|
layout: pattern
|
||||||
title: Visitor
|
title: Visitor
|
||||||
folder: visitor
|
folder: visitor
|
||||||
permalink: /patterns/visitor/
|
permalink: /patterns/visitor/zh
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
language: zh
|
language: zh
|
||||||
tags:
|
tags:
|
||||||
@ -201,7 +201,7 @@ Good to see you commander
|
|||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 适用性
|
## 适用性
|
||||||
|
|
||||||
|
1
pom.xml
1
pom.xml
@ -232,7 +232,6 @@
|
|||||||
<module>table-module</module>
|
<module>table-module</module>
|
||||||
<module>presentation</module>
|
<module>presentation</module>
|
||||||
<module>lockable-object</module>
|
<module>lockable-object</module>
|
||||||
<module>fanout-fanin</module>
|
|
||||||
<module>domain-model</module>
|
<module>domain-model</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user