Observer Pattern: News Board
Problem
A news board keeps a list of subscribers. Commands: subscribe NAME (add a subscriber, ignore if already subscribed), unsubscribe NAME, publish MESSAGE. When a message is published, every subscriber (in the order of subscription) is notified: print NAME got: MESSAGE. If nobody is subscribed, print No subscribers. The other commands print nothing.
Constraints
- 1 <= lines <= 1000
Examples
Input
subscribe A subscribe B publish hello
Output
A got: hello B got: hello
Solutions
The subject does not know what its observers do. It only calls them. New observers can be added without changing the board. This is how event systems and UI listeners work.
/*
* Problem : Process commands line by line.
* Input : Several lines of commands.
* Output : Notification lines.
* Approach: A subject with a list of observers.
* Time : O(commands * subscribers)
* Space : O(subscribers)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// Step 1: An observer is anything that wants to be told about a message.
interface Subscriber {
void notify(String message);
}
// Step 2: The subject (the board) keeps its observers and tells all of them about each message.
static class NewsBoard {
private final java.util.LinkedHashMap<String, Subscriber> subscribers = new java.util.LinkedHashMap<>();
void subscribe(String name, Subscriber subscriber) {
subscribers.putIfAbsent(name, subscriber);
}
void unsubscribe(String name) {
subscribers.remove(name);
}
int publish(String message) {
for (Subscriber subscriber : subscribers.values()) {
subscriber.notify(message);
}
return subscribers.size();
}
}
// This method solves the task. It receives the input and returns the answer.
static String[] solve(String[] lines) {
NewsBoard board = new NewsBoard();
java.util.List<String> output = new java.util.ArrayList<>();
for (String line : lines) {
String[] parts = line.split(" ", 2);
if (parts[0].equals("subscribe")) {
// Step 3: Each subscriber writes its own line when it is notified.
String name = parts[1];
board.subscribe(name, message -> output.add(name + " got: " + message));
} else if (parts[0].equals("unsubscribe")) {
board.unsubscribe(parts[1]);
} else {
// Step 4: Publishing tells all current subscribers.
if (board.publish(parts[1]) == 0) {
output.add("No subscribers");
}
}
}
return output.toArray(new String[0]);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
java.util.List<String> all = new java.util.ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
all.add(line);
}
}
String[] lines = all.toArray(new String[0]);
System.out.println(String.join("\n", solve(lines)));
}
}
Hints (1)
- Does the board know what a subscriber does with the message?