Using an interface to differentiate an 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 go to the People list, I need to make a distinction between American, Asian and European, and they can use the same interface. Is it good to use additional interfaces (IAmerican, IAsian, IEuropean) that all implement IPerson and use them in order to distinguish between the implementation class, for example:

 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 

The new interfaces are not very useful, but for separating objects. Is this a good approach, or should I implement some type property in IPerson in order to distinguish its implementation?

+6
source share
6 answers

I would go with the 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 request for American s:

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

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

+1
source

You do not need to take your second step, your first should work.

 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 each object as a common denominator ( IPerson ), but this does not mean that it loses traces of the actual object. I do not see the need to create legacy interfaces.

That said: I would prefer composition over inheritance here. What separates American from a European ? Store the property in the Person class (make it a class instead of an interface) that points to the user's area.

+5
source

Types are not only affordable discriminators. You can simply 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 class interfaces implement their functionality in their own way.

+2
source

Nothing that you described assumes that you will add additional interfaces.

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

  • It has the same public elements.
  • Public members do the same thing conceptually

than he still buys nothing.

The whole point of the interface is that even if classes behave the same way in the outside world, they do not necessarily have the same implementation. Therefore, he called Interface , not Implementation .

+1
source

Choosing the right particular type based on some value is appropriate for the Factory pattern. I recommend that you run Factory to select the correct IPerson . On the other hand, if you plan to implement Inversion of Control against IPerson , then it is better to program the interface and go with a multi-interface approach.

+1
source

Probably not. An interface point is the definition of similarity between different objects. If your algorithm needs to know what type of person each IPerson is, then you have gained very little due to the abstraction of the interface. In addition, your algorithm will break (perhaps bizarrely) if you try to create a new type of IPerson and forget to put it in it.

In fact, even a type property with a switch is probably not the optimal approach. The general development strategy that you may find useful is the Visitor Template .

0
source

Source: https://habr.com/ru/post/958508/


All Articles