Compare commits
3 Commits
all-contri
...
updateTram
Author | SHA1 | Date | |
---|---|---|---|
|
5681340ec7 | ||
|
c66ca67201 | ||
|
2679f7aa6f |
@@ -1776,6 +1776,15 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "castleKing1997",
|
||||||
|
"name": "DragonDreamer",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/35420129?v=4",
|
||||||
|
"profile": "http://rosaecrucis.cn",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
@@ -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/>
|
||||||
@@ -325,6 +325,7 @@ This project is licensed under the terms of the MIT license.
|
|||||||
<td align="center"><a href="https://github.com/interactwithankush"><img src="https://avatars.githubusercontent.com/u/18613127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>interactwithankush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=interactwithankush" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/interactwithankush"><img src="https://avatars.githubusercontent.com/u/18613127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>interactwithankush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=interactwithankush" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/yuhangbin"><img src="https://avatars.githubusercontent.com/u/17566866?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CharlieYu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yuhangbin" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/yuhangbin"><img src="https://avatars.githubusercontent.com/u/17566866?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CharlieYu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yuhangbin" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/Leisterbecker"><img src="https://avatars.githubusercontent.com/u/20650323?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leisterbecker</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Leisterbecker" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/Leisterbecker"><img src="https://avatars.githubusercontent.com/u/20650323?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leisterbecker</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Leisterbecker" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="http://rosaecrucis.cn"><img src="https://avatars.githubusercontent.com/u/35420129?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DragonDreamer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=castleKing1997" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -9,6 +9,10 @@ tags:
|
|||||||
- Reactive
|
- Reactive
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Name
|
||||||
|
|
||||||
|
Event Aggregator
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
A system with lots of objects can lead to complexities when a
|
A system with lots of objects can lead to complexities when a
|
||||||
client wants to subscribe to events. The client has to find and register for
|
client wants to subscribe to events. The client has to find and register for
|
||||||
@@ -17,6 +21,136 @@ requires a separate subscription. An Event Aggregator acts as a single source
|
|||||||
of events for many objects. It registers for all the events of the many objects
|
of events for many objects. It registers for all the events of the many objects
|
||||||
allowing clients to register with just the aggregator.
|
allowing clients to register with just the aggregator.
|
||||||
|
|
||||||
|
## Explanation
|
||||||
|
|
||||||
|
Real-world example
|
||||||
|
|
||||||
|
> King Joffrey sits on the iron throne and rules the seven kingdoms of Westeros. He receives most
|
||||||
|
> of his critical information from King's Hand, the second in command. King's hand has many
|
||||||
|
> close advisors himself, feeding him with relevant information about events occurring in the
|
||||||
|
> kingdom.
|
||||||
|
|
||||||
|
In Plain Words
|
||||||
|
|
||||||
|
> Event Aggregator is an event mediator that collects events from multiple sources and delivers
|
||||||
|
> them to registered observers.
|
||||||
|
|
||||||
|
**Programmatic Example**
|
||||||
|
|
||||||
|
In our programmatic example, we demonstrate the implementation of an event aggregator pattern. Some of
|
||||||
|
the objects are event listeners, some are event emitters, and the event aggregator does both.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface EventObserver {
|
||||||
|
void onEvent(Event e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class EventEmitter {
|
||||||
|
|
||||||
|
private final Map<Event, List<EventObserver>> observerLists;
|
||||||
|
|
||||||
|
public EventEmitter() {
|
||||||
|
observerLists = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void registerObserver(EventObserver obs, Event e) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void notifyObservers(Event e) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`KingJoffrey` is listening to events from `KingsHand`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public class KingJoffrey implements EventObserver {
|
||||||
|
@Override
|
||||||
|
public void onEvent(Event e) {
|
||||||
|
LOGGER.info("Received event from the King's Hand: {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`KingsHand` is listening to events from his subordinates `LordBaelish`, `LordVarys`, and `Scout`.
|
||||||
|
Whatever he hears from them, he delivers to `KingJoffrey`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class KingsHand extends EventEmitter implements EventObserver {
|
||||||
|
|
||||||
|
public KingsHand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public KingsHand(EventObserver obs, Event e) {
|
||||||
|
super(obs, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(Event e) {
|
||||||
|
notifyObservers(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, `LordVarys` finds a traitor every Sunday and notifies the `KingsHand`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
public class LordVarys extends EventEmitter implements EventObserver {
|
||||||
|
@Override
|
||||||
|
public void timePasses(Weekday day) {
|
||||||
|
if (day == Weekday.SATURDAY) {
|
||||||
|
notifyObservers(Event.TRAITOR_DETECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following snippet demonstrates how the objects are constructed and wired together.
|
||||||
|
|
||||||
|
```java
|
||||||
|
var kingJoffrey = new KingJoffrey();
|
||||||
|
|
||||||
|
var kingsHand = new KingsHand();
|
||||||
|
kingsHand.registerObserver(kingJoffrey, Event.TRAITOR_DETECTED);
|
||||||
|
kingsHand.registerObserver(kingJoffrey, Event.STARK_SIGHTED);
|
||||||
|
kingsHand.registerObserver(kingJoffrey, Event.WARSHIPS_APPROACHING);
|
||||||
|
kingsHand.registerObserver(kingJoffrey, Event.WHITE_WALKERS_SIGHTED);
|
||||||
|
|
||||||
|
var varys = new LordVarys();
|
||||||
|
varys.registerObserver(kingsHand, Event.TRAITOR_DETECTED);
|
||||||
|
varys.registerObserver(kingsHand, Event.WHITE_WALKERS_SIGHTED);
|
||||||
|
|
||||||
|
var scout = new Scout();
|
||||||
|
scout.registerObserver(kingsHand, Event.WARSHIPS_APPROACHING);
|
||||||
|
scout.registerObserver(varys, Event.WHITE_WALKERS_SIGHTED);
|
||||||
|
|
||||||
|
var baelish = new LordBaelish(kingsHand, Event.STARK_SIGHTED);
|
||||||
|
|
||||||
|
var emitters = List.of(
|
||||||
|
kingsHand,
|
||||||
|
baelish,
|
||||||
|
varys,
|
||||||
|
scout
|
||||||
|
);
|
||||||
|
|
||||||
|
Arrays.stream(Weekday.values())
|
||||||
|
.<Consumer<? super EventEmitter>>map(day -> emitter -> emitter.timePasses(day))
|
||||||
|
.forEachOrdered(emitters::forEach);
|
||||||
|
```
|
||||||
|
|
||||||
|
The console output after running the example.
|
||||||
|
|
||||||
|
```
|
||||||
|
18:21:52.955 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Warships approaching
|
||||||
|
18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: White walkers sighted
|
||||||
|
18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Stark sighted
|
||||||
|
18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Traitor detected
|
||||||
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|

|
||||||
|
|
||||||
@@ -26,9 +160,13 @@ Use the Event Aggregator pattern when
|
|||||||
* Event Aggregator is a good choice when you have lots of objects that are
|
* Event Aggregator is a good choice when you have lots of objects that are
|
||||||
potential event sources. Rather than have the observer deal with registering
|
potential event sources. Rather than have the observer deal with registering
|
||||||
with them all, you can centralize the registration logic to the Event
|
with them all, you can centralize the registration logic to the Event
|
||||||
Aggregator. As well as simplifying registration, a Event Aggregator also
|
Aggregator. As well as simplifying registration, an Event Aggregator also
|
||||||
simplifies the memory management issues in using observers.
|
simplifies the memory management issues in using observers.
|
||||||
|
|
||||||
|
## Related patterns
|
||||||
|
|
||||||
|
* [Observer](https://java-design-patterns.com/patterns/observer/)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html)
|
* [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html)
|
||||||
|
@@ -17,19 +17,19 @@ and to interleave the execution of functions without hard coding them together.
|
|||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer
|
Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer
|
||||||
style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems
|
style. For example, calculating Fibonacci accumulating sum and factorials. In these kinds of
|
||||||
recursion is more straightforward than their loop counterpart. Furthermore recursion may need less
|
problems, recursion is more straightforward than its loop counterpart. Furthermore, recursion may
|
||||||
code and looks more concise. There is a saying that every recursion problem can be solved using
|
need less code and looks more concise. There is a saying that every recursion problem can be solved
|
||||||
a loop with the cost of writing code that is more difficult to understand.
|
using a loop with the cost of writing code that is more difficult to understand.
|
||||||
|
|
||||||
However recursion type solutions have one big caveat. For each recursive call it typically needs
|
However, recursion-type solutions have one big caveat. For each recursive call, it typically needs
|
||||||
an intermediate value stored and there is a limited amount of stack memory available. Running out of
|
an intermediate value stored and there is a limited amount of stack memory available. Running out of
|
||||||
stack memory creates a stack overflow error and halts the program execution.
|
stack memory creates a stack overflow error and halts the program execution.
|
||||||
|
|
||||||
Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the
|
Trampoline pattern is a trick that allows defining recursive algorithms in Java without blowing the
|
||||||
stack.
|
stack.
|
||||||
|
|
||||||
Real world example
|
Real-world example
|
||||||
|
|
||||||
> A recursive Fibonacci calculation without the stack overflow problem using the Trampoline pattern.
|
> A recursive Fibonacci calculation without the stack overflow problem using the Trampoline pattern.
|
||||||
|
|
||||||
@@ -105,24 +105,26 @@ public interface Trampoline<T> {
|
|||||||
Using the `Trampoline` to get Fibonacci values.
|
Using the `Trampoline` to get Fibonacci values.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static Trampoline<Integer> loop(int times, int prod) {
|
public static void main(String[] args) {
|
||||||
|
LOGGER.info("Start calculating war casualties");
|
||||||
|
var result = loop(10, 1).result();
|
||||||
|
LOGGER.info("The number of orcs perished in the war: {}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Trampoline<Integer> loop(int times, int prod) {
|
||||||
if (times == 0) {
|
if (times == 0) {
|
||||||
return Trampoline.done(prod);
|
return Trampoline.done(prod);
|
||||||
} else {
|
} else {
|
||||||
return Trampoline.more(() -> loop(times - 1, prod * times));
|
return Trampoline.more(() -> loop(times - 1, prod * times));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("start pattern");
|
|
||||||
var result = loop(10, 1).result();
|
|
||||||
log.info("result {}", result);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Program output:
|
Program output:
|
||||||
|
|
||||||
```
|
```
|
||||||
start pattern
|
19:22:24.462 [main] INFO com.iluwatar.trampoline.TrampolineApp - Start calculating war casualties
|
||||||
result 3628800
|
19:22:24.472 [main] INFO com.iluwatar.trampoline.TrampolineApp - The number of orcs perished in the war: 3628800
|
||||||
```
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||
@@ -133,8 +135,8 @@ result 3628800
|
|||||||
|
|
||||||
Use the Trampoline pattern when
|
Use the Trampoline pattern when
|
||||||
|
|
||||||
* For implementing tail recursive function. This pattern allows to switch on a stackless operation.
|
* For implementing tail-recursive functions. This pattern allows to switch on a stackless operation.
|
||||||
* For interleaving the execution of two or more functions on the same thread.
|
* For interleaving execution of two or more functions on the same thread.
|
||||||
|
|
||||||
## Known uses
|
## Known uses
|
||||||
|
|
||||||
|
@@ -107,6 +107,4 @@ public interface Trampoline<T> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -39,9 +39,9 @@ public class TrampolineApp {
|
|||||||
* Main program for showing pattern. It does loop with factorial function.
|
* Main program for showing pattern. It does loop with factorial function.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
LOGGER.info("start pattern");
|
LOGGER.info("Start calculating war casualties");
|
||||||
var result = loop(10, 1).result();
|
var result = loop(10, 1).result();
|
||||||
LOGGER.info("result {}", result);
|
LOGGER.info("The number of orcs perished in the war: {}", result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,5 +55,4 @@ public class TrampolineApp {
|
|||||||
return Trampoline.more(() -> loop(times - 1, prod * times));
|
return Trampoline.more(() -> loop(times - 1, prod * times));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user