Подтвердить что ты не робот

Хороший пример для интерфейсов

Я работаю в компании, где некоторые из них требуют обоснования использования интерфейса в нашем коде (Visual Studio С# 3.5).

Я хотел бы попросить аргумент Iron Clad, для которого требуются интерфейсы. (Моя цель - ПРОВЕРИТЬ, что интерфейсы являются нормальной частью программирования.)

Мне не нужно убеждать, мне просто нужен хороший аргумент для использования в убеждении других.

Тип аргумента, который я ищу, основан на фактах, а не на сравнении (т.е. "потому что библиотека .NET использует их" основана на сравнении).

Аргумент против них таков: если класс правильно настроен (со своими публичными и частными членами), то интерфейс - это дополнительные дополнительные накладные расходы, потому что те, кто использует этот класс, ограничены публичными членами. Если вам нужен интерфейс, который реализуется более чем одним классом, тогда просто установите наследование/полиморфизм.

4b9b3361

Ответ 1

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

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

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

Ответ 2

Таким образом, аргумент против них: Если класс правильно настроен (с его общественные и частные члены), то интерфейс - это дополнительные дополнительные накладные расходы потому что те, кто использует класс, ограниченным для публичных членов. если ты необходимо иметь интерфейс, который реализовано более чем 1 классом, тогда просто установите наследование/полиморфизм.

Рассмотрим следующий код:

interface ICrushable
{
  void Crush();
}

public class Vehicle
{
}

public class Animal
{
}

public class Car : Vehicle, ICrushable
{
  public void Crush()
  {
     Console.WriteLine( "Crrrrrassssh" );
  }
}

public class Gorilla : Animal, ICrushable
{
  public void Crush()
  {
     Console.WriteLine( "Sqqqquuuuish" );
  }
}

Есть ли смысл вообще устанавливать иерархию классов, которая связывает животных с транспортными средствами, даже если они могут быть раздавлены моей гигантской дробильной машиной? Нет.

Ответ 3

В дополнение к вещам, описанным в других ответах, interfaces позволяет моделировать множественное наследование в .NET, которое в противном случае не разрешено.

Увы, как сказал кто-то

В технологии доминируют два типа людей: те, кто понимает, что им не удается, и те, кто управляет тем, что они не понимают.

Ответ 4

Чтобы включить модульное тестирование класса.

Эффективно отслеживать зависимости (если интерфейс не проверен и не тронут, возможно, изменилась только семантика класса).

Потому что накладные расходы нет.

Чтобы включить инъекцию зависимостей.

... и, возможно, потому, что он не в 70-х, а современные дизайнеры языка действительно знают, что они делают?

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

Ответ 5

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

Подумайте о чем-то, что Serializable, на самом деле не имеет смысла (с точки зрения дизайна/моделирования) иметь базовый класс под названием Serializable, так как не имеет смысла говорить что-то isA Serializable. Имея что-то, реализующее интерфейс Serializable, имеет смысл сказать, что "это то, что может сделать класс, а не класс"

Ответ 6

Интерфейсы не обязательны для всех, это дизайнерское решение. Я думаю, вам нужно убедить себя, почему, в каждом конкретном случае, полезно использовать интерфейс, потому что в добавлении интерфейса есть накладные расходы. С другой стороны, чтобы противостоять аргументу против интерфейсов, потому что вы можете "просто" использовать наследование: наследование имеет обратную поддержку, один из них - по крайней мере на С# и Java - вы можете использовать только наследование один раз (одно наследование); но второй - и, возможно, более важный - заключается в том, что наследование требует от вас понимания работы не только родительского класса, но и всех классов-предков, что делает расширение более сложным, но также более хрупким, поскольку изменение в родительском классе "реализация может легко разбить подклассы. В этом суть аргумента" композиция над наследием", которую учил нам книга GOF.

Ответ 7

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

Как вы доказываете, что вам нужны интерфейсы в коде, который вы пишете на своем рабочем месте? Найдя место в вашей реальной кодовой базе (не в некотором коде из какого-либо другого продукта и, конечно же, не в каком-нибудь игрушечном примере о Duck, реализующем метод makeNoise в IAnimal), где решение на основе интерфейса лучше, чем решение на основе наследования. Покажите своим начальникам проблему, с которой вы столкнулись, и спросите, имеет ли смысл модифицировать рекомендации для решения подобных ситуаций. Это учебный момент, когда каждый смотрит на одни и те же факты, а не на то, чтобы ударить друг друга по голове с общими и спекуляциями.

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

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

Ответ 8

  • Разработка, управляемая тестированием.
  • Тестирование устройств

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

Ответ 9

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

Ответ 10

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

В этом случае мы говорим, что "эта вещь может быть перечислина, но это не единственная определяющая характеристика".

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

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

Они также упрощают модульное тестирование, но я не считаю, что это сильный аргумент, поскольку вы можете создать систему без модульных тестов (не рекомендуется).

Ответ 11

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

Ответ 12

Проблема с аргументом наследования заключается в том, что у вас будет либо гигантский божественный класс, либо иерархия настолько глубокая, что у вас будет голова. Кроме того, вы получите методы в классе, который вам не нужен или не имеет смысла.

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

Настраивается реализация IDisposable. Ваша команда поместила бы метод Dispose в класс Object и позволяла ему распространяться через систему независимо от того, имеет ли это смысл для объекта или нет.

Ответ 13

Интерфейс объявляет контракт, к которому будет привязан любой объект, реализующий его. Это делает качество кода намного проще, чем попытка принудительного исполнения письменной (не кодовой) или вербальной структуры, в тот момент, когда класс украшен ссылкой на интерфейс, требования/контракт ясны, и код не будет компилироваться до тех пор, пока вы не выполните этот интерфейс полностью и безопасен.

Есть много других причин для использования интерфейсов (см. здесь), но, вероятно, не слишком резонирует с управлением, а также хорошим, старомодным "качеством";)

Ответ 14

Хорошо, моя первая реакция заключается в том, что, если вы должны объяснить, почему вам нужны интерфейсы, это будет битвой в любом случае:)

что, помимо упомянутых выше причин, интерфейсы являются единственным способом для слабосвязанного программирования, n-уровневых архитектур, где вам нужно обновлять/заменять компоненты "на лету" и т.д. - в личном опыте, однако это было слишком эзотерическая концепция для руководителя команды архитектуры, в результате чего мы жили в dll hell - в мире .net no-less!

Ответ 15

Пожалуйста, прости меня за псевдокод заранее!

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

Где вы можете использовать

Widget widget1 = new Widget;

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

public class AnotherObject
{
    public void SomeMethod(Widget widget1)
    {
        //..do something with widget1
    }
}

Мы все еще привязаны к использованию виджета здесь. Но, по крайней мере, это более проверяемо, поскольку мы можем внедрить реализацию Widget в SomeMethod. Теперь, если бы мы использовали интерфейс, мы могли бы еще разделить все.

public class AnotherObject
{
    public void SomeMethod(IWidget widget1)
    {
        //..do something with widget1
    }
}

Обратите внимание, что теперь мы не требуем конкретной реализации Widget, но вместо этого мы просим все, что соответствует интерфейсу IWidget. Это означает, что все может быть введено, что означает, что в повседневном использовании кода мы могли бы внедрить фактическую реализацию Widget. Но это также означает, что, когда мы хотим протестировать этот код, мы можем ввести фальшивку/макет/заглушку (в зависимости от вашего понимания этих условий) и протестировать наш код.

Но как мы можем это сделать дальше. С помощью StructureMap мы можем еще больше отделить этот код. С последним примером кода наш код вызова мой выглядит примерно так.

public class AnotherObject
{
    public void SomeMethod(IWidget widget1)
    {
        //..do something with widget1
    }
}

public class CallingObject
{
    public void AnotherMethod()
    {
        IWidget widget1 = new Widget();
        new AnotherObject().SomeMethod(widget1);
    }
}

Как вы можете видеть в приведенном выше коде, мы удалили зависимость в SomeMethod, передав объект, соответствующий IWidget. Но в CallingObject(). AnotherMethod у нас все еще есть зависимость. Мы также можем использовать StructureMap, чтобы удалить эту зависимость!

[PluginFamily("Default")]
public interface IAnotherObject
{
    ...
}

[PluginFamily("Default")]
public interface ICallingObject
{
    ...
}

[Pluggable("Default")]
public class AnotherObject : IAnotherObject
{
    private IWidget _widget;
    public AnotherObject(IWidget widget)
    {
        _widget = widget;
    }

    public void SomeMethod()
    {
        //..do something with _widget
    }
}

[Pluggable("Default")]
public class CallingObject : ICallingObject
{
    public void AnotherMethod()
    {
        ObjectFactory.GetInstance<IAnotherObject>().SomeMethod();
    }
}

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

Ответ 16

Приложения, поскольку это не отвечает на ваш вопрос относительно случая для интерфейсов.

Однако я предлагаю, чтобы этот вопрос был прочитан.

Нарисуйте первые шаблоны дизайна

- Ли

Ответ 17

Я не понимаю, как его дополнительные накладные расходы.

Интерфейсы обеспечивают гибкость, управляемый код и возможность повторного использования. Кодирование на интерфейс вам не нужно беспокоиться о конкретном коде реализации или логике определенного класса, который вы используете. Вы просто ожидаете результата. Многие классы имеют разную реализацию для одной и той же функции (StreamWriter, StringWriter, XmlWriter). Вам не нужно беспокоиться о том, как они реализуют запись, вам просто нужно ее вызвать.