I have 3 classes:
Event
public class Event<T> {
private List<BiConsumer<Object, T>> consumers = new ArrayList<>();
public void subscribe(BiConsumer<Object, T> consumer) {
consumers.add(consumer);
}
public void invoke(Object sender, T arg) {
for (BiConsumer<Object, T> consumer : consumers) {
System.out.println(sender + " " + "sender");
consumer.accept(sender, arg);
}
}
}
Rat:
public class Rat {
private Game game;
public Rat(Game game) {
this.game = game;
game.ratEnters.subscribe((sender, arg) -> {
System.out.println( this + " " + sender);
});
System.out.println(this + "this");
game.ratEnters.invoke(this, null);
}
}
Game:
public class Game {
public Event ratEnters = new Event();
}
and single test:
public class ObserverPatternTest {
@Test
public void singleRatTest() {
Game game = new Game();
Rat rat = new Rat(game);
Rat rat2 = new Rat(game);
Rat rat3 = new Rat(game);
}
}
The output:
design.patterns.behavioral.patterns.observer.exercises.Rat@4e515669this
design.patterns.behavioral.patterns.observer.exercises.Rat@4e515669 sender
design.patterns.behavioral.patterns.observer.exercises.Rat@4e515669 design.patterns.behavioral.patterns.observer.exercises.Rat@4e515669
design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166this
design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166 sender
design.patterns.behavioral.patterns.observer.exercises.Rat@4e515669 design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166
design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166 sender
design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166 design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166
My question is: how it is possible that this instance is not the same as sender instance?
design.patterns.behavioral.patterns.observer.exercises.Rat@4e515669 design.patterns.behavioral.patterns.observer.exercises.Rat@17d10166
Just trying to explain with an example completely. What happens with your code (modified for a more readable output) is as follows :
Rat rat1 = new Rat(game);
is executed as :
this ----> pack.Sample$Rat@4cf777e8
sender ----> pack.Sample$Rat@4cf777e8
pack.Sample$Rat@4cf777e8 this ----> sender pack.Sample$Rat@4cf777e8
Simple, right? I believe this was self-explanatory since a single instance(4cf777e8) created, just the list with one consumer and everything works as expected.
Then in the second initialization
Rat rat2 = new Rat(game);
you've now created another instance of Rat(5702b3b1) which becomes the sender now in your Event.invoke call as:
// part-1
this ----> pack.Sample$Rat@5702b3b1
// part-2
sender ----> pack.Sample$Rat@5702b3b1
pack.Sample$Rat@4cf777e8 this ----> sender pack.Sample$Rat@5702b3b1
sender ----> pack.Sample$Rat@5702b3b1
pack.Sample$Rat@5702b3b1 this ----> sender pack.Sample$Rat@5702b3b1
the output that you see is divided into two parts, the first part prints the current instance of this and sender which is the latest instance created.
The second part is what is crucial since it now has the List<BiConsumer<Object, T>>, this list has a previous instance of Rat(4cf777e8) as well, and that's the reason when you perform consumer.accept(sender, arg);, the first instance comes into the picture, with this pointing to its instance and sender pointing to the current sender you've passed into the argument.
Further in the last initialization
Rat rat3 = new Rat(game);
you can now see how the list of consumers have grown and its impact on the output. Bear in mind that the list now has BiConsumers, each for an instance of Rat created i.e. Rat(4cf777e8), Rat(5702b3b1) and Rat@69ea3742 as you would observe in the output.
// part-1
this ----> pack.Sample$Rat@69ea3742
// part-2
sender ----> pack.Sample$Rat@69ea3742
pack.Sample$Rat@4cf777e8 this ----> sender pack.Sample$Rat@69ea3742 // (first element in list)
sender ----> pack.Sample$Rat@69ea3742
pack.Sample$Rat@5702b3b1 this ----> sender pack.Sample$Rat@69ea3742 // (second element in list)
sender ----> pack.Sample$Rat@69ea3742
pack.Sample$Rat@69ea3742 this ----> sender pack.Sample$Rat@69ea3742 // (third element in list)
A simplified version of your code to test that I came up with :
public static class Event {
private List<Consumer<Object>> consumers = new ArrayList<>();
void subscribe(Consumer<Object> consumer) {
consumers.add(consumer);
}
void invoke(Object sender) {
consumers.forEach(consumer -> {
System.out.println("sender ----> " + sender);
consumer.accept(sender);
});
}
}
public static class Rat {
private Game game;
Rat(Game game) {
this.game = game;
System.out.println("this ----> " + this);
game.ratEnters.subscribe((sender) -> System.out.println(this + " this ----> sender " + sender));
game.ratEnters.invoke(this);
}
}
public static class Game {
Event ratEnters = new Event();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With