Является ли принцип разделения интерфейса в отношении классов или объектов?

Напомнить (из вики):

Принцип сегрегации интерфейса (ISP) гласит, что ни один клиент не должен зависеть от методов, которые он не использует.

А теперь посмотри на мой пример.

Вот моя изменчивая сущность. Он редактируется откуда-то и может уведомлять об изменениях через интерфейс только для чтения:

interface ICounter
{
    event Action<int> NewNumber;
}

class Counter : ICounter
{
    public event Action<int> NewNumber;

    int number = 0;
    public void IncrementAndSend(int x)
    {
        number += x;
        if (NewNumber != null) NewNumber(number);
    }
}

А вот класс из транспортного уровня, который его использует. Посмотрите на два варианта инъекций (Attach_1 а также Attach_2) и мои предположения ниже:

class OneToManyRouter
{
    IEnumerable<Counter> _destinations;

    public OneToManyRouter(IEnumerable<Counter> destinations)
    {
        _destinations = destinations;
    }

    // 1         
    public void Attach_1(ICounter source)
    {
        source.NewNumber += (n) =>
        {
            foreach (var dest in _destinations) dest.IncrementAndSend(n);
        };
    }

    // 2 
    public void Attach_2(Counter source)
    {
        source.NewNumber += (n) =>
        {
            foreach (var dest in _destinations) dest.IncrementAndSend(n);
        };
    }
}
  1. Интернет-провайдер о реальных объектах. Вы не должны использовать "чрезмерные" ссылки на входящие параметры.
  2. Интернет-провайдер о занятиях. Если ваш класс где-то уже использует полный интерфейс, нет необходимости ограничивать ссылочный тип в определенных методах.ICounter интерфейс является чрезмерным в этом примере.
  3. Эта архитектура совершенно неверна с точки зрения принципов SOLID (тогда почему?).

2 ответа

Решение

ISP - это не классы и не объекты, а строго об интерфейсах, в частности, о дизайне интерфейсов. Этот принцип направлен на то, чтобы не поощрять группирование частично связанных методов в одном интерфейсе, чтобы пользователи не нуждались в подмножестве этих методов для реализации остальных как пустых функций (либо выбрасывая NotImplementedException или оставить его буквально пустым { }). Таким образом, проще реализовать более согласованные классы и более эффективно использовать интерфейсы.

В вашем примере вы комбинируете оба Counter класс с ICounter интерфейс, таким образом, который не имеет прямого отношения к концепции провайдера:

  1. Интернет-провайдер о реальных объектах. Вы не должны использовать "чрезмерные" ссылки на входящие параметры.

Это отчасти верно (если я правильно истолковываю понятие "чрезмерное"). Однако, как я уже говорил, ISP не о том, как взаимодействовать с реальными объектами, а о том, как определить полезный интерфейс.

  1. Интернет-провайдер о занятиях. Если ваш класс где-то уже использует полный интерфейс, нет необходимости ограничивать ссылочный тип в определенных методах. Интерфейс ICounter является чрезмерным в этом примере.

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

  1. Эта архитектура совершенно неверна с точки зрения принципов SOLID (тогда почему?).

С архитектурной точки зрения с акцентом на принципы SOLID, я бы предложил иметь зависимость от ICounter скорее, чем Counterи в том числе IncrementAndSend как часть определения интерфейса.

Я думаю, что было бы лучше добавить метод IncrementAndSend к интерфейсу и сделать класс OneToManyRouter зависимым от IEnumerable. По моему мнению, это не нарушение ISP, потому что действие события NewNumber и метод IncrementAndSend тесно связаны. Надеюсь, это поможет вам.

Другие вопросы по тегам