Всегда полезно использовать интерфейс, но использование нескольких интерфейсов для каждого класса имеет как преимущества, так и недостатки.

Интерфейс всегда был одной из обсуждаемых тем в большинстве моих собеседований, когда я работал инженером-программистом в юные годы. В интервью меня спросили, как реализовать несколько интерфейсов в одном классе и когда он будет его использовать. Это был не сложный вопрос, я полагаю, что интервьюеры больше интересовались моим пониманием как принципов ООП, так и принципов SOLID ((если вам нужно освежиться, посмотрите Четыре принципа ООП, объясненные за пять минут и SOLID Принципы, объясненные за пять минут ). I (принцип разделения интерфейсов) в принципах SOLID гласит, что клиентов не следует заставлять реализовывать функции, которые им не нужны. Создание интерфейса хороший способ сгруппировать связанные функции. Бывают случаи, когда вам нужно объединить связанные функции в один класс. Возможность реализации нескольких интерфейсов дает вам такую ​​гибкость. Мы рассмотрим, как реализовать несколько интерфейсов и сценариев, где это уместно Сделай так.

Вы можете создать один класс для каждого интерфейса, и это тоже будет хорошо. Но если вам нужно объединить связанные функции, вы все равно будете соблюдать принцип разделения интерфейса.

Рассмотрим фрагмент кода ниже

public interface INavigation
{
    List<Address> GetAllContactAddress();
    List<Address> GetTopFiveTraveledDestination();
}
public interface IEngine
{
    void Start();
    void Stop();
}
public interface IElectricalSystem
{
    void IncreaseTemperature();
    void DecreaseTemperature();
}
public class Address
{
    public string StreetAddress { get; set; }
    public int NumberOfTimes { get; set; }
    public Address(string streetAddress, int numberOftimes)
    {
        this.StreetAddress = streetAddress;
        this.NumberOfTimes = numberOftimes;
    }
}

Допустим, нашему приложению нужен класс Car, реализующий функции этих интерфейсов. Важно отметить, что если вы решили создать по одному классу на интерфейс вместо этого подхода, вы могли бы добиться того же с композицией. Вам нужно будет добавить свойство экземпляра Engine, Navigation и ElectricalSystem в свой класс Car. Вместо этого мы будем использовать один класс, реализующий все интерфейсы, наш класс Car будет выглядеть примерно так.

public class Car : INavigation, IEngine, IElectricalSystem
{
    private List<Address> traveledDestinations = new List<Address>
    {
        new Address("street 1", 3),
        new Address("street 2", 5),
        new Address("street 3", 2),
        new Address("street 4", 6),
        new Address("street 4", 9)
    };
    public void DecreaseTemperature()
    {
        Console.WriteLine("Temperature decreased...");
    }
    public List<Address> GetAllContactAddress()
    {
        return this.traveledDestinations;
    }
    public List<Address> GetTopFiveTraveledDestination()
    {
        return this.traveledDestinations;
    }
    public void IncreaseTemperature()
    {
        Console.WriteLine("Temperature increased...");
    }
    public void Start()
    {
        Console.WriteLine("Engine started...");
    }
    public void Stop()
    {
        Console.WriteLine("Engine stopped...");
    }
}

Когда мы используем этот класс, если мы создадим экземпляр нашего класса Car, мы получим функциональные возможности всех интерфейсов.

Однако, если бы мы хотели получить доступ только к функциям из одного конкретного интерфейса, мы могли бы просто создать экземпляр нашего класса для самого этого интерфейса.

Несмотря на то, что все функции реализованы в классе, теперь мы видим только методы, определенные интерфейсом IEngine. Это дает вам такой же детальный доступ, как если бы вы создавали один класс для каждого интерфейса.

Всегда есть загвоздка, когда используются технические приемы для удовлетворения некоторых требований. Например, если бы у всех трех интерфейсов был вызов метода PrintInfo, который печатал имя их свойств, это было бы проблемой. Лучше всего реализовать каждый интерфейс с другим классом, чтобы избежать этой проблемы. Кроме того, если вам нужно добавить функции, специфичные для интерфейса, это станет проблемой, потому что компилятор не сможет различить, какой метод принадлежит какому интерфейсу. Вы можете решить эту проблему, явно указав перед методом имя интерфейса, и вы сможете получить доступ к этому методу только при создании экземпляра нашего класса Car с интерфейсом, в противном случае этот метод не будет виден. Если это каким-то образом ускользает от вас, вот пример.

В наших интерфейсах теперь есть этот новый метод.

public interface INavigation
{
    //prior methods
    void PrintGreeting();
}
public interface IEngine
{
    //prior methods
    void PrintGreeting();
}
public interface IElectricalSystem
{
    //prior methods
    void PrintGreeting();
}

У нашего класса Car теперь есть три новых метода

void IEngine.PrintGreeting()
{
    Console.WriteLine("Greeting from IEngine");
}
void IElectricalSystem.PrintGreeting()
{
    Console.WriteLine("Greeting from IElectricalSystem");
}
void INavigation.PrintGreeting()
{
    Console.WriteLine("Greeting from INavigation");
}

Если мы попытаемся получить доступ к этому методу, снова создав экземпляр нашего класса Car как объект Car, у нас не получится.

Но если мы создадим экземпляр нашего нового класса Car с одним из интерфейсов, то сможем получить доступ к новому методу.

Помните, что каждый используемый метод одновременно хорош и плох, в зависимости от его использования. Обязательно сделайте это, когда это имеет смысл, а не только ради реализации нескольких интерфейсов, когда ситуация требует чего-то еще. Это может быстро выйти из-под контроля, поэтому используйте его экономно.