Reputation: 3621
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
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
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
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
Reputation: 31206
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
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
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 American
s:
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
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