'How can I structure my classes which usually need to be called together?

I have some related classes that implement the same method

class Dog {
    public void speak() { System.out.println("Bark") }
}
class Cat {
    public void speak() { System.out.println("Meow") }
}

90% of the time, users would want both the dog and the cat to speak. They don't want to know the details. When we add a new animal, they'll want it to speak too. The idea is to avoid:

// All animals need to be explicitly told to speak every time
new Dog().speak();
new Cat().speak();

// But we just added Birds, and the users need to remember to add this call everywhere
new Bird.speak();

I could do something like

class Animals {
    public void speak() {
        new Dog().speak();
        new Cat().speak();
        new Bird().speak();
    }
}

So that users can just call new Animals().speak() every time.

However, 10% of the time, it does need to be configurable. What I want is a way for users to do something like this

// Used most of the time
Animals.withAllAnimals().speak();

// Sometimes they don't want cats, and they want the dogs to woof instead
Animals.exclude(Cat)
  .configure(Dog.sound, "Woof")
  .speak();

How can I structure my classes to accomplish this?



Solution 1:[1]

I know that it is question tagged with java. However, let me show an example with C# as these languages have many common things. The first thing is I would use inheritance and create abstract class Animal as common behaviour Speak() is used. So, abstract class should define behavior, and the derived classes should implement that behavior:

public abstract class Animal
{
    public abstract void Speak();
}

Then just use inheritance and override behaviour in derived classes:

public class Bird : Animal
{
    public override void Speak()
    {
        System.Console.WriteLine("I am a bird!");
    }
}

public class Cat : Animal
{
    public override void Speak()
    {
        System.Console.WriteLine("I am a cat!");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        System.Console.WriteLine("I am a dog!");
    }
}

Then we need a class that allows to speak for all animals. Let's create Choir class for this purpose:

public class Choir
{
    private List<Animal> choristers;

    public void AddChoristers(IEnumerable<Animal> choristers)
    {
        if (choristers == null)
            choristers = new List<Animal>();

        choristers.AddRange(choristers);
    }

    public void SpeakAll()
    {
        foreach (Animal animal in choristers)
            animal.Speak();
    }

    public void Speak(Func<Animal, bool> filter)
    {
        IEnumerable<Animal> filteredAnimals = choristers
            .Where(filter ?? (animal => true));
        foreach (Animal animal in filteredAnimals)
            animal.Speak();
    }
}

Pay attention to Speak() method. It can take a predicate as a parameter, so you can choose desired animals to speak().

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1