Animal Sounds with an Interface

Problem

Each input line is an animal: dog, cat or cow. Print its sound: Woof, Meow or Moo. For any other animal print unknown animal. Make one class for each animal that follows a common interface.

Constraints

  • 1 <= lines <= 10^4

Examples

Input

dog
cat
fish

Output

Woof
Meow
unknown animal

Solutions

Best approachTime O(n)Space O(n)

The calling code works with the interface only. To add a new animal you add a class and one map entry; the loop does not change. Object.hasOwn prevents a name like constructor from being found in a plain object.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process lines.
 * Input   : Several lines.
 * Output  : One sound per line.
 * Approach: Classes with a common method.
 * Time    : O(n)
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: An interface says what every animal can do. It has no code about how.
        interface Animal {
            String sound();
        }

        static class Dog implements Animal {
            public String sound() {
                return "Woof";
            }
        }

        static class Cat implements Animal {
            public String sound() {
                return "Meow";
            }
        }

        static class Cow implements Animal {
            public String sound() {
                return "Moo";
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        // Step 2: A map from the name to a new animal object. Every value has the type Animal.
        java.util.Map<String, java.util.function.Supplier<Animal>> animals = new java.util.HashMap<>();
        animals.put("dog", Dog::new);
        animals.put("cat", Cat::new);
        animals.put("cow", Cow::new);

        String[] output = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            // Step 3: Make the animal and call sound(). We do not check the class: the interface guarantees the method.
            java.util.function.Supplier<Animal> maker = animals.get(lines[i]);
            output[i] = maker == null ? "unknown animal" : maker.get().sound();
        }
        return output;
    }

    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. What does the loop need to know about each animal?