Compare commits
1 Commits
updateTram
...
valueObjec
Author | SHA1 | Date | |
---|---|---|---|
d2fab302ce |
@ -9,10 +9,6 @@ tags:
|
||||
- Reactive
|
||||
---
|
||||
|
||||
## Name
|
||||
|
||||
Event Aggregator
|
||||
|
||||
## Intent
|
||||
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
|
||||
@ -21,136 +17,6 @@ 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
|
||||
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
|
||||

|
||||
|
||||
@ -160,13 +26,9 @@ Use the Event Aggregator pattern when
|
||||
* 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
|
||||
with them all, you can centralize the registration logic to the Event
|
||||
Aggregator. As well as simplifying registration, an Event Aggregator also
|
||||
Aggregator. As well as simplifying registration, a Event Aggregator also
|
||||
simplifies the memory management issues in using observers.
|
||||
|
||||
## Related patterns
|
||||
|
||||
* [Observer](https://java-design-patterns.com/patterns/observer/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [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
|
||||
|
||||
Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer
|
||||
style. For example, calculating Fibonacci accumulating sum and factorials. In these kinds of
|
||||
problems, recursion is more straightforward than its loop counterpart. Furthermore, recursion may
|
||||
need less code and looks more concise. There is a saying that every recursion problem can be solved
|
||||
using a loop with the cost of writing code that is more difficult to understand.
|
||||
style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems
|
||||
recursion is more straightforward than their loop counterpart. Furthermore recursion may need less
|
||||
code and looks more concise. There is a saying that every recursion problem can be solved using
|
||||
a loop with the cost of writing code that is more difficult to understand.
|
||||
|
||||
However, recursion-type solutions have one big caveat. For each recursive call, it typically needs
|
||||
However recursion type solutions have one big caveat. For each recursive call it typically needs
|
||||
an intermediate value stored and there is a limited amount of stack memory available. Running out of
|
||||
stack memory creates a stack overflow error and halts the program execution.
|
||||
|
||||
Trampoline pattern is a trick that allows defining recursive algorithms in Java without blowing the
|
||||
Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the
|
||||
stack.
|
||||
|
||||
Real-world example
|
||||
Real world example
|
||||
|
||||
> A recursive Fibonacci calculation without the stack overflow problem using the Trampoline pattern.
|
||||
|
||||
@ -105,26 +105,24 @@ public interface Trampoline<T> {
|
||||
Using the `Trampoline` to get Fibonacci values.
|
||||
|
||||
```java
|
||||
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) {
|
||||
public static Trampoline<Integer> loop(int times, int prod) {
|
||||
if (times == 0) {
|
||||
return Trampoline.done(prod);
|
||||
return Trampoline.done(prod);
|
||||
} 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:
|
||||
|
||||
```
|
||||
19:22:24.462 [main] INFO com.iluwatar.trampoline.TrampolineApp - Start calculating war casualties
|
||||
19:22:24.472 [main] INFO com.iluwatar.trampoline.TrampolineApp - The number of orcs perished in the war: 3628800
|
||||
start pattern
|
||||
result 3628800
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
@ -135,8 +133,8 @@ Program output:
|
||||
|
||||
Use the Trampoline pattern when
|
||||
|
||||
* For implementing tail-recursive functions. This pattern allows to switch on a stackless operation.
|
||||
* For interleaving execution of two or more functions on the same thread.
|
||||
* For implementing tail recursive function. This pattern allows to switch on a stackless operation.
|
||||
* For interleaving the execution of two or more functions on the same thread.
|
||||
|
||||
## Known uses
|
||||
|
||||
|
@ -107,4 +107,6 @@ public interface Trampoline<T> {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -39,9 +39,9 @@ public class TrampolineApp {
|
||||
* Main program for showing pattern. It does loop with factorial function.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LOGGER.info("Start calculating war casualties");
|
||||
LOGGER.info("start pattern");
|
||||
var result = loop(10, 1).result();
|
||||
LOGGER.info("The number of orcs perished in the war: {}", result);
|
||||
LOGGER.info("result {}", result);
|
||||
|
||||
}
|
||||
|
||||
@ -55,4 +55,5 @@ public class TrampolineApp {
|
||||
return Trampoline.more(() -> loop(times - 1, prod * times));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,19 +10,80 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Provide objects which follow value semantics rather than reference semantics.
|
||||
This means value objects' equality are not based on identity. Two value objects are
|
||||
This means value objects' equality is not based on identity. Two value objects are
|
||||
equal when they have the same value, not necessarily being the same object.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real-world example
|
||||
|
||||
> There is a class for hero statistics in a role-playing game. The statistics contain attributes
|
||||
> such as strength, intelligence, and luck. The statistics of different heroes should be equal
|
||||
> when all the attributes are equal.
|
||||
|
||||
In plain words
|
||||
|
||||
> Value objects are equal when their attributes have the same value
|
||||
|
||||
Wikipedia says
|
||||
|
||||
> In computer science, a value object is a small object that represents a simple entity whose
|
||||
> equality is not based on identity: i.e. two value objects are equal when they have the same
|
||||
> value, not necessarily being the same object.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Here is the `HeroStat` class that is the value object. Notice the use of
|
||||
[Lombok's `@Value`](https://projectlombok.org/features/Value) annotation.
|
||||
|
||||
```java
|
||||
@Value(staticConstructor = "valueOf")
|
||||
class HeroStat {
|
||||
|
||||
int strength;
|
||||
int intelligence;
|
||||
int luck;
|
||||
}
|
||||
```
|
||||
|
||||
The example creates three different `HeroStat`s and compares their equality.
|
||||
|
||||
```java
|
||||
var statA = HeroStat.valueOf(10, 5, 0);
|
||||
var statB = HeroStat.valueOf(10, 5, 0);
|
||||
var statC = HeroStat.valueOf(5, 1, 8);
|
||||
|
||||
LOGGER.info(statA.toString());
|
||||
LOGGER.info(statB.toString());
|
||||
LOGGER.info(statC.toString());
|
||||
|
||||
LOGGER.info("Is statA and statB equal : {}", statA.equals(statB));
|
||||
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
|
||||
```
|
||||
|
||||
Here's the console output.
|
||||
|
||||
```
|
||||
20:11:12.199 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
|
||||
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
|
||||
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=5, intelligence=1, luck=8)
|
||||
20:11:12.202 [main] INFO com.iluwatar.value.object.App - Is statA and statB equal : true
|
||||
20:11:12.203 [main] INFO com.iluwatar.value.object.App - Is statA and statC equal : false
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Use the Value Object when
|
||||
|
||||
* You need to measure the objects' equality based on the objects' value
|
||||
* The object's equality needs to be based on the object's value
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [java.util.Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html)
|
||||
* [java.time.LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html)
|
||||
@ -31,6 +92,7 @@ Use the Value Object when
|
||||
## Credits
|
||||
|
||||
* [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.html)
|
||||
* [ValueObject](https://martinfowler.com/bliki/ValueObject.html)
|
||||
* [VALJOs - Value Java Objects : Stephen Colebourne's blog](http://blog.joda.org/2014/03/valjos-value-java-objects.html)
|
||||
* [Value Object : Wikipedia](https://en.wikipedia.org/wiki/Value_object)
|
||||
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
|
||||
|
@ -43,7 +43,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* This practice creates three HeroStats(Value object) and checks equality between those.
|
||||
* This example creates three HeroStats (value objects) and checks equality between those.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
var statA = HeroStat.valueOf(10, 5, 0);
|
||||
@ -51,6 +51,8 @@ public class App {
|
||||
var statC = HeroStat.valueOf(5, 1, 8);
|
||||
|
||||
LOGGER.info(statA.toString());
|
||||
LOGGER.info(statB.toString());
|
||||
LOGGER.info(statC.toString());
|
||||
|
||||
LOGGER.info("Is statA and statB equal : {}", statA.equals(statB));
|
||||
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
|
||||
|
@ -23,10 +23,7 @@
|
||||
|
||||
package com.iluwatar.value.object;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* HeroStat is a value object.
|
||||
@ -35,23 +32,10 @@ import lombok.ToString;
|
||||
* http://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html
|
||||
* </a>
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
public class HeroStat {
|
||||
|
||||
// Stats for a hero
|
||||
|
||||
private final int strength;
|
||||
private final int intelligence;
|
||||
private final int luck;
|
||||
|
||||
// Static factory method to create new instances.
|
||||
public static HeroStat valueOf(int strength, int intelligence, int luck) {
|
||||
return new HeroStat(strength, intelligence, luck);
|
||||
}
|
||||
|
||||
// The clone() method should not be public. Just don't override it.
|
||||
@Value(staticConstructor = "valueOf")
|
||||
class HeroStat {
|
||||
|
||||
int strength;
|
||||
int intelligence;
|
||||
int luck;
|
||||
}
|
||||
|
Reference in New Issue
Block a user