rageit
rageit

Reputation: 3621

Using interface to differentiate implementation

Here is my specific scenario with an interface and its implementation:

IPerson {string Name;}

American : IPerson {string Name;}
Asian : IPerson {string Name;}
European : IPerson {string Name;}

People = new List<IPerson>(); // This list can have American, Asian and/or European

When I access People list I need to make distinction between American, Asian and European and they can share the same interface. Is it good to use additional interfaces (IAmerican, IAsian, IEuropean) which all implements IPerson and use that to differentiate between the implementing class like:

IAmerican : IPerson {}
IAsian : IPerson {}
IEuropean : IPerson {}

American : IAmerican {string Name;}
Asian : IAsian {string Name;}
European : IEuropean {string Name;}

People = new List<IPerson>();
People.Add(new American());
People.Add(new Asian());
People.Add(new European());

var americans = People.OfType<IAmerican>(); // Getting all Americans from People

New Interfaces aren't of much use but to segregate the objects. Is this a good approach or should I implement some type property in IPerson to differentiate its implementation?

Upvotes: 6

Views: 395

Answers (6)

Jeroen Vannevel
Jeroen Vannevel

Reputation: 44448

You don't have to do your second step, your first one should work as well.

void Main()
{
    var people = new List<IPerson>();
    people.Add(new American { Name = "jack"});
    people.Add(new American { Name = "John"});
    people.Add(new Asian { Name = "ho"});

    Console.WriteLine (people.OfType<American>());

}

public interface IPerson {
    string Name {get; set;}
}

class American : IPerson {public string Name {get; set; }}
class Asian : IPerson {public string Name {get; set; }}
class European : IPerson {public string Name {get; set; }}

Output:

jack
john

The list defines every object as their common denominator (IPerson), but that doesn't mean it loses track of the actual object. I don't see the need to create obsolete interfaces.

That being said: I would prefer composition over inheritance here. What separates an American from a European? Keep a property in the Person class (make it a class instead of an interface) that indicates a person's regionality.

Upvotes: 5

P.Brian.Mackey
P.Brian.Mackey

Reputation: 44295

Selecting the correct concrete type based upon some value is a good fit for the Factory Pattern. I recommend you implement a Factory to select the correct IPerson. On the other hand, if you plan to implement Inversion of Control against IPerson then it's better to program to an interface and go with the multi interface approach.

Upvotes: 1

Jeremy West
Jeremy West

Reputation: 12745

Probably not. The point of the interface is to define the similarities between different objects. If your algorithm must know what type of person each IPerson is, then you have gained very little by the abstraction of the interface. Furthermore, your algorithm will break (perhaps in bizarre ways) if you attempt to create a new type of IPerson and forget to put a case in for it.

In fact, even a Type property with a switch is probably not an optimal approach. A common design strategy that you may find useful is the Visitor Pattern.

Upvotes: 0

Nothing you've described suggests that you'd benefit from adding extra interfaces.

Even if the implementation is different, if the interface is the same

  • It has the same public members
  • The public members do conceptually the same thing

than it still doesn't really buy you anything.

The whole point of an interface is so that even though classes behave the same to the outside world, they don't necessarily have the same implementation. That's why it's called an Interface and not an Implementation.

Upvotes: 1

MarcinJuraszek
MarcinJuraszek

Reputation: 125660

I would go with a property.

enum PersonType
{
    American, Asian, European
}

interface IPerson
{
    string Name { get; set; }
    PersonType Type { get; }
}

American : IPerson
{
    public string Name { get; set; }
    public PersonType Type { get { return PersonType.American; } }
}

And querying for Americans:

var americans = People.Where(p => p.Type == PersonType.American);

You should probably find a better name for that enum, but the concept is important here, not the name.

Upvotes: 1

Wiktor Zychla
Wiktor Zychla

Reputation: 48314

Types are not only available discriminators. You can just ask the object directly:

enum Continent { Europe, Asia, America }

public interface IPerson 
{  
    string Name { get; set; }
    Continent Continent { get; set; }
}

public class Asian : IPerson
{
    public Continent Continent
    {
        get 
        {
           return Continent.Asia;
        }
    }
}

This is what interfaces are about - classes implement their functionality in their own specific way.

Upvotes: 2

Related Questions