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

Best approachTime O(commands * subscribers)Space O(subscribers)

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.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * 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)
  1. Does the board know what a subscriber does with the message?