2

I'm trying to make food for my IAnimals using a FoodFactory and have a large List<IAnimal> of Dogs and Foxs etc. Ideally, I would pass in an IAnimal and the FoodFactory would return the right food but I am not sure how to do this.

interface IAnimal {
   void MakeNoise();
}
public sealed class Dog : IAnimal {
    public void MakeNoise() { Console.WriteLine("Woof woof"); }
}
public sealed class Fox : IAnimal {
    public void MakeNoise() { Console.WriteLine("What does the fox say?"); }
}
public static class FoodFactory {
    public static void Create(Dog dog) {
        Console.WriteLine("return dog food");
    }
    public static void Create(Fox fox) {
        Console.WriteLine("return fox food");
    }
}

and here's my caller code:

var myList = new List<IAnimal> { new Dog(), new Fox() };
foreach (var animal in myList)
{
    FoodFactory.Create(animal); // Sadly, this doesn't work
}

Is there a 'proper' way to do this? All I can think of is a load of if statements like:

if (animal is Dog) { FoodFactory.Create(animal as Dog); }

I have a lot of animals and I'd much rather the computer work out which one it's dealing with than me! Thank you.

UPDATE

Thank you to all that have posted. I went with Xinchao's answer because it was most applicable in my context; it didn't affect my animal classes and allowed the type to be resolved at runtime without me checking all the animal types. There were three helpful answers which would have worked (e.g. using visitor pattern) but they weren't quite applicable in my context as I don't want to change/extend my animals.

Big AL
  • 421
  • 3
  • 11
  • Is that fair for you to add `CreateFood` method or `CreateFoodFactory` method which returns a abstract factory which knows to create food in `IAnimal` ? If you could then it would be easy to achieve it polymorphically. May be for this animal example it looks weird, but it will help. – Sriram Sakthivel Sep 13 '14 at 19:11
  • One thing you'll want to do to make the modeling more clear is to separate the models from the UI. For example, a factory should *return* something. That's going to help drive this design a bit more. – David Sep 13 '14 at 19:13
  • @David agreed. This is just a knockup of my problem for illustration. Let's say my actual code returns some food. – Big AL Sep 13 '14 at 19:18
  • Your `Factory` knows nothing about abstract concept called "IAnimal" – Aniket Inge Sep 13 '14 at 19:19
  • @BigAL: That's my point, though. If your actual code is going to return an `IFood` or a `BaseFood` then the direction you've already attempted wouldn't have even compiled. It might be a minor thing, but have a concrete set of your models (as opposed to a notion of them in your head) is going to help you determine the interactions of those models. – David Sep 13 '14 at 19:19
  • I Think your all missing the point of him trying to explicitly Downcast. – eran otzap Sep 13 '14 at 19:21
  • 1
    Looking at nice answers this question collected so far some clarification of the question is needed to see which one answers better your needs. Adding details on number of what types you expect to grow (`IAnimal` or types of mapper like FoodFactory, DrinkFactory, SomePropertyFactory) will allow to see whether visitor pattern once or double virtual dispatch once are more suitable. – Alexei Levenkov Sep 13 '14 at 19:50

4 Answers4

4

The reason you are having this problem is the so-called overload resolution happens at compile time instead of run-time. There are a couple of ways to solve it: Using a bunch of if-else-if statements is certainly one way, although you can write it prettier.

With .Net 4.0 or above, you can use to "dynamic" keyword to delay the overload resolution to run-time. It has a performance penalty, but it achieves accurately what you need:

public static class FoodFactory {
     public static void Create(dynamic animal) {
        InternalCreate (animal);
    }
    private static void InternalCreate (Dog dog) {
        Console.WriteLine("return dog food");
    }
    private static void InternalCreate (Fox fox) {
        Console.WriteLine("return fox food");
    }
}

To add a bit more type safety, you might consider to do something like:

public static class FoodFactory {
    public static void Create(IAnimal animal) {
        Dispatch (animal);
    }

    private static void Dispatch (dynamic animal) {
        InternalCreate (animal);
    }
    private static void InternalCreate (Dog dog) {
        Console.WriteLine("return dog food");
    }
    private static void InternalCreate (Fox fox) {
        Console.WriteLine("return fox food");
    }
}
Xinchao
  • 2,929
  • 1
  • 24
  • 39
  • +1. This is one nice looking way to implement mapping when you can't (or simply don't want to) touch your class to add more properties. It also scales better than adding methods to class when you need multiple mappings (like multiple factory types to get favorite food, dress, hairbrush, environment, tree, .... for an animal). – Alexei Levenkov Sep 13 '14 at 19:34
2

I think you need to modify your Create method in FoodFactory class to accept IAnimal as a parameter instead. You would also need to have a method declaration for FavFood or whatever you want to call it in the Interface which would get specific implementation from classes (Dogs, Fox) that inherits the Interface. Then in a factory class you could supply any animal of type IAnimal and have a method that invokes Animal specific FavFood method.

interface IAnimal
{
    void FavFood();
}

public sealed class Dog : IAnimal
{
    public void FavFood() { Console.WriteLine("Me loves  dog food. Woof woof."); }
}

public sealed class Goat : IAnimal
{
    public void FavFood() { Console.WriteLine("Me loves goat food. myaaa.."); }
}


public static class FoodFactory
{
    public static void Create(IAnimal animal)
    {
        animal.FavFood();
    }
}

And when you call it, you would do

var animals = new List<IAnimal> { new Dog(), new Fox() };

foreach (var animal in animals)
{
    FoodFactory.Create(animal);
}

Did I answer what you were looking for? If not, let me know where I missed it...

haku
  • 4,105
  • 7
  • 38
  • 63
2

Your FoodFactory does need to know what kind of animal its feeding, but I would imagine that the animal itself knows what kind of food it wants to eat. What if IAnimal provided that?

interface IAnimal {
   void MakeNoise();
   FoodType FavoriteFood { get; }
}
public sealed class Dog : IAnimal {
    public void MakeNoise() { Console.WriteLine("Woof woof"); }
    public FoodType FavoriteFood { get { return FoodType.DogFood; } }
}
public sealed class Fox : IAnimal {
    public void MakeNoise() { Console.WriteLine("What does the fox say?"); }
    public FoodType FavoriteFood { get { return FoodType.WhatTheFoxEats; } }
}

Now your FoodFactory has the information it needs to build food:

public static class FoodFactory {
    public static IFood Create(IAnimal animal) {
        // animal.FavoriteFood tells you what food to make
    }
}

Maybe FavoriteFood actually returns an instance of food, and the factory just delegates to that? Maybe the factory maintains a mapping or some other logic of the enum above to actual food instances? Maybe some other way? (Or maybe you just output to the console like you already are instead of returning an object like I'm trying to do, in which case the animals can just write to the console and the factory still doesn't need to know anything else about the animal.) In any event, the factory's relationship to the animal is now polymorphically defined.

David
  • 208,112
  • 36
  • 198
  • 279
2

Another alternative would be to use the visitor pattern:

using System;
using System.Collections.Generic;

public interface IAnimalVisitor
{
    void Visit(Dog dog);
    void Visit(Fox fox);
}

public class FeedingPersonnel : IAnimalVisitor
{
    public void Visit(Dog dog) 
    {
        Console.WriteLine("return dog food");
    }

    public void Visit(Fox fox)
    {
        Console.WriteLine("return fox food");
    }
}

//public class Veterinarian : IAniamalVisitor { ... } (if you need it)

interface IAnimal 
{
    void Accept( IAnimalVisitor visitor);
    void MakeNoise();
}

public sealed class Dog : IAnimal {
    public void Accept( IAnimalVisitor visitor) { visitor.Visit(this); }
    public void MakeNoise() { Console.WriteLine("Woof woof"); }
}

public sealed class Fox : IAnimal {
    public void Accept( IAnimalVisitor visitor) { visitor.Visit(this); }
    public void MakeNoise() { Console.WriteLine("What does the fox say?"); }
}


public class Test
{
    public static void Main()
    {
        var myList = new List<IAnimal> { new Dog(), new Fox() };
        var feeder = new FeedingPersonnel();

        foreach (var animal in myList)
        {
           animal.Accept(feeder);
        }
    }
}

This method avoids casting and also provides you the means to add another types of visitors. With the downside that you have to provide Visit once for each new Animal and add a new method to the IAnimalVisitor and define it in each visitor implementer whenever a new Animal is added.

Depending on you actual situation this might be acceptable (or not).

ds27680
  • 1,993
  • 10
  • 11
  • Thanks, this is a really nice solution. Unfortunately, for me, I don't want to /can't change my IAnimal but otherwise I would have gone with this. – Big AL Sep 13 '14 at 20:17