3 syntax highligting
source | link
interface Animal {
  Food wantedFood();
}
interface Animal {
  Food wantedFood();
}
interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()
interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()
interface Animal {
  Food wantedFood();
}
interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()
interface Animal {
  Food wantedFood();
}
interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()
2 Linked to Wikipedia for more info.
source | link

There are two possible approaches here.

The simplest way to solve this if every Animal knows itself what they are supposed to be fed. So:

interface Animal {
  Food wantedFood();
}

This might completely solve your problem, and if so, is a good solution.

But while this is simple, this is often unsatisfactory: your Animal interface will grow and grow with marginally related methods. Or maybe we don't want each animal to feed itself, and rather want a separate ZooKeeper to handle this. A ZooKeeper knows how to handle() each Animal. How does the ZooKeeper know which animal they are handling? There's a technique for this called double dispatchdouble dispatch, where the Animal is responsible for asking the ZooKeeper for correct handling. This looks very much like the above example where the Animal itself knows what food we want, but once we have a generic ZooKeeper we can have different ZooKeepers with different behaviours:

interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()

We can now add other ZooKeepers without having to change the Animals.

This is generally known as the visitor patternvisitor pattern, and allows us to implement a function differently for different types, even if we don't know which kind of type we'll get at run time. However, there is a large trade off here: if the zoo gets a new Animal, we have to update the ZooKeeper interface, and all ZooKeeper implementations with it. This is bad, because this makes it hard to extend, but also good because it makes it more difficult to forget to handle a case.

There are two possible approaches here.

The simplest way to solve this if every Animal knows itself what they are supposed to be fed. So:

interface Animal {
  Food wantedFood();
}

This might completely solve your problem, and if so, is a good solution.

But while this is simple, this is often unsatisfactory: your Animal interface will grow and grow with marginally related methods. Or maybe we don't want each animal to feed itself, and rather want a separate ZooKeeper to handle this. A ZooKeeper knows how to handle() each Animal. How does the ZooKeeper know which animal they are handling? There's a technique for this called double dispatch, where the Animal is responsible for asking the ZooKeeper for correct handling. This looks very much like the above example where the Animal itself knows what food we want, but once we have a generic ZooKeeper we can have different ZooKeepers with different behaviours:

interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()

We can now add other ZooKeepers without having to change the Animals.

This is generally known as the visitor pattern, and allows us to implement a function differently for different types, even if we don't know which kind of type we'll get at run time. However, there is a large trade off here: if the zoo gets a new Animal, we have to update the ZooKeeper interface, and all ZooKeeper implementations with it. This is bad, because this makes it hard to extend, but also good because it makes it more difficult to forget to handle a case.

There are two possible approaches here.

The simplest way to solve this if every Animal knows itself what they are supposed to be fed. So:

interface Animal {
  Food wantedFood();
}

This might completely solve your problem, and if so, is a good solution.

But while this is simple, this is often unsatisfactory: your Animal interface will grow and grow with marginally related methods. Or maybe we don't want each animal to feed itself, and rather want a separate ZooKeeper to handle this. A ZooKeeper knows how to handle() each Animal. How does the ZooKeeper know which animal they are handling? There's a technique for this called double dispatch, where the Animal is responsible for asking the ZooKeeper for correct handling. This looks very much like the above example where the Animal itself knows what food we want, but once we have a generic ZooKeeper we can have different ZooKeepers with different behaviours:

interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()

We can now add other ZooKeepers without having to change the Animals.

This is generally known as the visitor pattern, and allows us to implement a function differently for different types, even if we don't know which kind of type we'll get at run time. However, there is a large trade off here: if the zoo gets a new Animal, we have to update the ZooKeeper interface, and all ZooKeeper implementations with it. This is bad, because this makes it hard to extend, but also good because it makes it more difficult to forget to handle a case.

1
source | link

There are two possible approaches here.

The simplest way to solve this if every Animal knows itself what they are supposed to be fed. So:

interface Animal {
  Food wantedFood();
}

This might completely solve your problem, and if so, is a good solution.

But while this is simple, this is often unsatisfactory: your Animal interface will grow and grow with marginally related methods. Or maybe we don't want each animal to feed itself, and rather want a separate ZooKeeper to handle this. A ZooKeeper knows how to handle() each Animal. How does the ZooKeeper know which animal they are handling? There's a technique for this called double dispatch, where the Animal is responsible for asking the ZooKeeper for correct handling. This looks very much like the above example where the Animal itself knows what food we want, but once we have a generic ZooKeeper we can have different ZooKeepers with different behaviours:

interface ZooKeeper {
  handleDog(Dog dog);
  handleFish(Fish fish);
}

interface Animal {
  accept(ZooKeeper keeper);
}

class Dog implements Animal {
  accept(ZooKeeper keeper) { keeper.handleDog(this); }
}

class Fish implements Animal {
  accept(ZooKeeper keeper) { keeper.handleFish(this); }
}

class FeedingZooKeeper implements ZooKeeper {
  handeDog(Dog dog) { /* the dog gets meat */ }
  handeFish(Fish fish) { /* the fish gets bread */ }
}

Animal someAnimal = ...;
FeedingZooKeeper keeper = new FeedingZooKeeper();
someAnimal.accept(keeper); // either calls handleDog() or handleFish()

We can now add other ZooKeepers without having to change the Animals.

This is generally known as the visitor pattern, and allows us to implement a function differently for different types, even if we don't know which kind of type we'll get at run time. However, there is a large trade off here: if the zoo gets a new Animal, we have to update the ZooKeeper interface, and all ZooKeeper implementations with it. This is bad, because this makes it hard to extend, but also good because it makes it more difficult to forget to handle a case.