-
Notifications
You must be signed in to change notification settings - Fork 1
/
BrokerChain.java
172 lines (146 loc) · 4.07 KB
/
BrokerChain.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
Broker Chain - patterns used:
chain of responsibility + observer + mediator + mementos
*/
package behavioral.chainofresponsibility;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
// Command Query Separation (observer pattern used here)
class Event<Args>
{
private int index = 0; // key into the map to find a consumer
private Map<Integer, Consumer<Args>>
handlers = new HashMap<>();
public int subscribe(Consumer<Args> handler)
{
int i = index;
handlers.put(index++, handler);
return i;
}
public void unsubscribe(int key)
{
handlers.remove(key);
}
public void fire(Args args)
{
for (Consumer<Args> handler : handlers.values())
{
handler.accept(args); // fire the event on every single consumer
}
}
}
class Query
{
public String creatureName;
enum Argument
{
ATTACK, DEFENSE
}
public Argument argument;
public int result; // value of the handlers
public Query(String creatureName,
Argument argument, int result) {
this.creatureName = creatureName;
this.argument = argument;
this.result = result;
}
}
class Game
{
public Event<Query> queries = new Event<>(); // central location where any modifier can subscribe itself to queries on the creature and modify its attributes
}
class Character
{
private Game game;
public String name;
public int baseAttack, baseDefense;
public Character(Game game, String name,
int baseAttack, int baseDefense) {
this.game = game;
this.name = name;
this.baseAttack = baseAttack;
this.baseDefense = baseDefense;
}
int getAttack()
{
Query q = new Query(name, Query.Argument.ATTACK, baseAttack);
game.queries.fire(q);
return q.result;
}
int getDefense()
{
Query q = new Query(name, Query.Argument.DEFENSE, baseDefense);
game.queries.fire(q);
return q.result;
}
@Override
public String toString() {
return "Creature{" +
"game=" + game +
", name='" + name + '\'' +
", attack=" + getAttack() +
", defense=" + getDefense() +
'}';
}
}
class CharacterModifier
{
protected Game game;
protected Character character;
public CharacterModifier(Game game, Character character) {
this.game = game;
this.character = character;
}
}
class IncreaseDefenseMod
extends CharacterModifier
{
public IncreaseDefenseMod(Game game, Character character) {
super(game, character);
game.queries.subscribe(q -> {
if (q.creatureName.equals(character.name)
&& q.argument == Query.Argument.DEFENSE)
{
q.result += 3;
}
});
}
}
class DoubleAttackMod
extends CharacterModifier
implements AutoCloseable
{
private final int token;
public DoubleAttackMod(Game game, Character character) {
super(game, character);
// subscribe mediator (game) to all queries
token = game.queries.subscribe(q -> {
if (q.creatureName.equals(character.name)
&& q.argument == Query.Argument.ATTACK)
{
q.result *= 2;
}
});
}
@Override
public void close() /*throws Exception */
{
game.queries.unsubscribe(token); // unsubscribe from handling any changes to the underlying character
}
}
class BrokerChainDemo
{
public static void main(String[] args) {
Game game = new Game();
Character goblin = new Character(game, "Strong Goblin", 2, 2);
System.out.println(goblin);
IncreaseDefenseMod icm = new IncreaseDefenseMod(game, goblin);
DoubleAttackMod dam = new DoubleAttackMod(game, goblin);
try(dam)
{
System.out.println("inside try block: " + goblin);
}
System.out.println("double attack mod goes back: " + goblin);
}
}